У меня 2 файла
wholesaler_a.csv
id;ean;manufacturer;product;description;packaging product;foo;packaging unit;amount per unit;items on stock (availability);warehouse
12345600001;23880602029774;Drinks Corp.;Soda Drink, 12 * 1,0l;Lorem ipsum usu amet dicat nullam ea;case 12;bar;bottle;1.0l;123;north
и wholesaler_b.json
{
"data": [
{
"PRODUCT_IDENTIFIER": "12345600001",
"EAN_CODE_GTIN": "24880602029766",
"BRAND": "Drinks Corp.",
"NAME": "Soda Drink, 12x 1L",
"PACKAGE": "case",
"ADDITIONAL_INFO": "",
"VESSEL": "bottle",
"LITERS_PER_BOTTLE": "1",
"BOTTLE_AMOUNT": "12"
}
]
}
Цель состоит в том, чтобы преобразовать их в следующий формат JSON
{
"id": "",
"gtin": "",
"manufacturer": "",
"name": "",
"packaging": "",
"baseProductPackaging": "",
"baseProductUnit": "",
"baseProductAmount": "",
"baseProductQuantity": ""
}
Вот моя реализация:
<?php
namespace EgyTest;
abstract class AbstractProductAdapter implements ProductAdapterInterface
{
protected $data;
public function getMappedKeys(): array
{
return [
$this->getId() => DataAdapter::FIELD_ID,
$this->getGtin() => DataAdapter::FIELD_GTIN,
$this->getManufacture() => DataAdapter::FIELD_MANUFACTURE,
$this->getName() => DataAdapter::FIELD_NAME,
$this->getPackaging() => DataAdapter::FIELD_PACKAGING,
$this->getBaseProductPackaging() => DataAdapter::FIELD_BASE_PRODUCT_PACKAGING,
$this->getBaseProductUnit() => DataAdapter::FIELD_BASE_PRODUCT_UNIT,
$this->getBaseProductAmount() => DataAdapter::FIELD_BASE_PRODUCT_AMOUNT,
$this->getBaseProductQuantity() => DataAdapter::FIELD_BASE_PRODUCT_QUANTITY
];
}
public function __construct(DataProvider $dataProvider)
{
$this->data = $dataProvider->getProducts();
}
public function mapData(): array
{
$mappedData = [];
foreach ($this->data['data'] as $item) {
$mappedData[] = array_combine(array_merge($item, $this->getMappedKeys()), $item);
}
return $mappedData;
}
}
<?php
namespace EgyTest;
interface DataProvider
{
public function getProducts();
}
<?php
namespace EgyTest;
class CsvData implements DataProvider
{
protected $file;
public function __construct(string $file)
{
$this->file = $file;
}
public function getProducts(): array
{
$rows = array_map(function ($value) {
return str_getcsv($value, ";");
},
file($this->file)
);
$header = array_shift($rows);
$data = [];
foreach ($rows as $row) {
$data['data'][] = array_combine($header, $row);
}
return $data;
}
}
<?php
namespace EgyTest;
class CsvProductAdapter extends AbstractProductAdapter
{
const FIELD_ID = 'id';
const FIELD_GTIN = 'ean';
const FIELD_MANUFACTURE = 'manufacturer';
const FIELD_NAME = 'product';
const FIELD_PACKAGING = 'packaging product';
const FIELD_BASE_PRODUCT_PACKAGING = 'packaging unit';
const FIELD_BASE_PRODUCT_UNIT = 'amount per unit';
const FIELD_BASE_PRODUCT_AMOUNT = 'items on stock (availability)';
const FIELD_BASE_PRODUCT_QUANTITY = 'warehouse';
public function getId(): string
{
return self::FIELD_ID;
}
public function getGtin(): string
{
return self::FIELD_GTIN;
}
public function getManufacture(): string
{
return self::FIELD_MANUFACTURE;
}
public function getName(): string
{
return self::FIELD_NAME;
}
public function getPackaging(): string
{
return self::FIELD_PACKAGING;
}
public function getBaseProductPackaging(): string
{
return self::FIELD_BASE_PRODUCT_PACKAGING;
}
public function getBaseProductUnit(): string
{
return self::FIELD_BASE_PRODUCT_UNIT;
}
public function getBaseProductAmount(): string
{
return self::FIELD_BASE_PRODUCT_AMOUNT;
}
public function getBaseProductQuantity(): string
{
return self::FIELD_BASE_PRODUCT_QUANTITY;
}
}
И такая же реализация для формата JSON
Не могли бы вы просмотреть мой код
1 ответ
Я рекомендую меньше циклов в CsvData getProducts()
public function getProducts(): array
{
$lines = file($this->file);
$header = str_getcsv(array_shift($lines), ';');
return [
'data' => array_map(
function($line) use ($header) {
return array_combine(
$header,
str_getcsv($line, ';')
);
},
$lines
)
];
}
Или, если вы используете PHP7.4 или выше, используйте стрелочную функцию для менее подробного синтаксиса:
public function getProducts(): array
{
$lines = file($this->file);
$header = str_getcsv(array_shift($lines), ';');
return [
'data' => array_map(
fn($line) => array_combine($header, str_getcsv($line, ';')),
$lines
)
];
}
Я не уверен, что меня продают array_merge()
—array_combine()
техника в mapData()
. (Просто тихо, я думаю array_replace()
более семантически подходит по сравнению с array_merge()
— хотя эффект тот же.) Использование array_combine()
— функция, которая довольно строгая в отношении требований к данным — в getProducts()
более или менее простительно при условии, что источники данных надежно действительны. Однако в mapData()
, могут быть некоторые изменения или изменения в содержимом файла, которые не покрываются вашим getMappedKeys()
. Это заставляет меня думать, что должны быть какие-то условия для создания исключений в классе. Мне также интересно, если вместо индивидуального const
объявлений, я мог бы использовать поисковый массив для выполнения перевода. Может быть, вам над чем подумать, так как я еще не определился со своим мнением.
Наконец, я не вижу никакой пользы во вложении соответствующих данных в $data['data']
. Всегда старайтесь проектировать как можно менее сложные структуры данных. Другими словами, как можно скорее удалите ненужный первый уровень.