Преобразование данных из JSON и CSV в другой формат JSON

У меня 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 ответ
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']. Всегда старайтесь проектировать как можно менее сложные структуры данных. Другими словами, как можно скорее удалите ненужный первый уровень.

    Добавить комментарий

    Ваш адрес email не будет опубликован. Обязательные поля помечены *