There are 4 tables in the database: months, types, prices, tonnages
There is an array of the following type:
'prices'=> [
'soy' => [
'january' => [
50 => 145,
75 => 136,
100 => 138
],
'february' => [
50 => 100,
75 => 125,
100 => 108
],
....
],
'hay' =>
'january' => [
50 => 105,
75 => 116,
100 => 118
],
'february' => [
50 => 100,
75 => 125,
100 => 108
],
....
This array is an example of data that should be loaded into a database by migrating to a table named prices.
The prices table has the same fields as: month_id, tonnage_id, type_id, price.
The months, types, and tonnages tables are filled in. How can I compare the data and upload it to the database?
I have a code that already works, but it seems to me that it turned out to be unnecessarily complicated.
public function safeUp()
{
$months = $this->getDb()->createCommand('SELECT * FROM months')->queryAll();
$tonnages = $this->getDb()->createCommand('SELECT * FROM tonnages')->queryAll();
$types = $this->getDb()->createCommand('SELECT * FROM raw_types')->queryAll();
$columns = ['price', 'month_id', 'tonnage_id', 'type_id'];
$rows = MigrationHelper::toRecords(Yii::$app->params['prices'], $months, $tonnages, $types);
$this->batchInsert('prices', $columns, $rows);
}
public static function toRecords(array $arr, array $months, array $tonnages, array $types): array
{
$result = [];
foreach ($arr as $type => $typeValues) {
$typeId = self::findIdByField($types, 'name', $type);
foreach ($typesValues as $month => $monthValue) {
$monthId = self::findIdByField($types, 'name', $month);
foreach ($monthValues as $tonnage => $price) {
$tonnageId = self::findIdByField($types, 'value', $tonnag);
$result[] = [
'price' = $price,
'month_id' => $monthId,
'tonnage_id' => $tonnageId,
'type_id' => $typeId
];
}
}
}
return $result;
}
private static function findIdByField(array $arr, string $fieldName, int | string $value) : int
{
foreach ($arr as $item) {
if ($item[$fieldName] === $value) {
return $item['id'];
}
}
}
I'm going to assume queryAll()
simply returns an array of associative arrays. You should convert them to associative arrays keyed off the fields you want to search, rather than using findIdByField()
, which is presumably a linear search.
public static function toRecords(array $arr, array $months, array $tonnages, array $types): array
{
$result = [];
$types = array_combine(array_column($types, 'name'), array_column($types, 'id'));
$months = array_combine(array_column($months, 'name'), array_column($months, 'id'));
$tonnages = array_combine(array_column($tonnage, 'value'), array_column($tonnage, 'id'));
foreach ($arr as $type => $typeValues) {
$typeId = $types[$type];
foreach ($typesValues as $month => $monthValue) {
$monthId = $months[$month]
foreach ($monthValues as $tonnage => $price) {
$tonnageId = $tonnages[$tonnage];
$result[] = [
'price' = $price,
'month_id' => $monthId,
'tonnage_id' => $tonnageId,
'type_id' => $typeId
];
}
}
}
return $result;
}