Magento 2: увезете производи директно во базата на податоци

В претходниот напис Го опишав процесот на увоз на производи во Magento 2 на вообичаен начин - преку модели и складишта. Вообичаениот метод има многу мала брзина на обработка на податоци. Мојот лаптоп произведуваше околу еден производ во секунда. Во ова продолжение размислувам за алтернативен начин за увоз на производ - со директно внесување во базата на податоци, заобиколувајќи ги стандардните механизми Magento 2 (модели, фабрики, складишта). Редоследот на чекори за увоз на производи може да се прилагоди на кој било програмски јазик што може да работи со MySQL.

Општи услови: Magento има готова функционалност за увоз на податоци и, најверојатно, тоа ќе биде доволно за вас. Меѓутоа, ако ви треба поцелосна контрола врз процесот на увоз, не ограничувајќи се на подготовка на CSV-датотека за она што го имате, добредојдовте во cat.

Magento 2: увезете производи директно во базата на податоци

Кодот што произлегува од пишувањето на двете статии може да се види во модулот Magento "flancer32/mage2_ext_demo_import“. Еве неколку ограничувања што ги следев за да го поедноставам кодот на демо-модулот:

  • Производите се создаваат само, не се ажурираат.
  • Еден магацин
  • Се увезуваат само имиња на категории, без нивната структура
  • Структурите на податоци се усогласени со верзијата 2.3

JSON за увоз на еден производ:

{
  "sku": "MVA20D-UBV-3",
  "name": "Заглушка для пломбировки ВА47-29 IEK",
  "desc": "Обеспечение доступа к устройствам ...",
  "desc_short": "Заглушка для пломбировки ВА47-29 IEK предназначена для ...",
  "price": 5.00,
  "qty": 25,
  "categories": ["Категория 1", "Категория 2"],
  "image_path": "mva20d_ubv_3.png"
}

Преглед на главните фази на увозот

  • регистрација на самиот производ
  • врска помеѓу производот и веб-страницата
  • основни атрибути на производот (EAV)
  • податоци за залиха (количество на производ на залиха)
  • медиуми (слики)
  • врска со каталошки категории

Регистрација на производи

Основните информации за производот може да се најдат во catalog_product_entity:

CREATE TABLE `catalog_product_entity` (
  `entity_id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT 'Entity Id',
  `attribute_set_id` smallint(5) unsigned NOT NULL DEFAULT '0' COMMENT 'Attribute Set ID',
  `type_id` varchar(32) NOT NULL DEFAULT 'simple' COMMENT 'Type ID',
  `sku` varchar(64) DEFAULT NULL COMMENT 'SKU',
  `has_options` smallint(6) NOT NULL DEFAULT '0' COMMENT 'Has Options',
  `required_options` smallint(5) unsigned NOT NULL DEFAULT '0' COMMENT 'Required Options',
  `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT 'Creation Time',
  `updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT 'Update Time',
  PRIMARY KEY (`entity_id`),
  KEY `CATALOG_PRODUCT_ENTITY_ATTRIBUTE_SET_ID` (`attribute_set_id`),
  KEY `CATALOG_PRODUCT_ENTITY_SKU` (`sku`)
)

Минималните информации потребни за креирање запис во регистарот на производи се:

  • attribute_set_id
  • sku

дополнителни:

  • type_id - ако не го специфицираме, тогаш ќе се користи „едноставно“.

За да пишувам директно во базата на податоци, го користам DB адаптерот на самиот Magento:

function create($sku, $typeId, $attrSetId)
{
    /** @var MagentoFrameworkAppResourceConnection $this->resource */
    /** @var MagentoFrameworkDBAdapterPdoMysql $conn */
    $conn = $this->resource->getConnection();
    $table = $this->resource->getTableName('catalog_product_entity');
    $bind = [
        'sku' => $sku,
        'type_id' => $typeId,
        'attribute_set_id' => $attrSetId
    ];
    $conn->insert($table, $bind);
    $result = $conn->lastInsertId($table);
    return $result;
}

По регистрирањето на производот со catalog_product_entity станува видливо во административниот панел, во мрежата на производи (Каталог/Производи).

Magento 2: увезете производи директно во базата на податоци

Врска помеѓу производот и веб-страницата

Поврзаноста на производот со страницата одредува во кои продавници и изложби производот ќе биде достапен напред.

function linkToWebsite($prodId, $websiteId)
{
    /** @var MagentoFrameworkAppResourceConnection $this->resource */
    /** @var MagentoFrameworkDBAdapterPdoMysql $conn */
    $conn = $this->resource->getConnection();
    $table = $this->resource->getTableName('catalog_product_website');
    $bind = [
        'product_id' => $prodId,
        'website_id' => $websiteId
    ];
    $conn->insert($table, $bind);
}

Magento 2: увезете производи директно во базата на податоци

Основни атрибути на производот

Новорегистрираниот производ сè уште нема име или опис. Сето ова се прави преку EAV атрибути. Еве список на основни атрибути на производот што се потребни за да може производот правилно да се прикаже на предната страна:

  • name
  • price
  • description
  • short_description
  • status
  • tax_class_id
  • url_key
  • visibility

Посебен атрибут се додава на ваков производ (деталите за добивање на идентификаторот и типот на атрибутот од неговиот код се испуштени):

public function create($prodId, $attrCode, $attrValue)
{
    $attrId = /* get attribute ID by attribute code */
    $attrType = /* get attribute type [datetime|decimal|int|text|varchar]) by attribute code */
    if ($attrId) {
        /** @var MagentoFrameworkAppResourceConnection $this->resource */
        /** @var MagentoFrameworkDBAdapterPdoMysql $conn */
        $conn = $this->resource->getConnection();
        $tblName = 'catalog_product_entity_' . $attrType;
        $table = $this->resource->getTableName($tblName);
        $bind = [
            'attribute_id' => $attrId,
            'entity_id' => $prodId,
            /* put all attributes to default store view with id=0 (admin) */
            'store_id' => 0,
            'value' => $attrValue
        ];
        $conn->insert($table, $bind);
    }
}

Користејќи го кодот на атрибутот, го одредуваме неговиот id и типот на податоци (datetime, decimal, int, text, varchar), потоа запишете ги податоците за административниот прозорец во соодветната табела (store_id = 0).

Откако ќе ги додадете горенаведените атрибути на производот, ја добивате оваа слика во административниот панел:

Magento 2: увезете производи директно во базата на податоци

Податоци за залиха

Почнувајќи од верзијата 2.3 во Magento, постојат две паралелни групи на табели кои обезбедуваат складирање на информации за залиха (количина на производот):

  • cataloginventory_*: стара структура;
  • inventory_*: нова структура (MSI - Multi Source Inventory);

Треба да додадете податоци за залиха на двете структури, бидејќи новата структура сè уште не е целосно независна од старата (многу е веројатно дека за default магацин во новата структура вклучена е маса cataloginventory_stock_status како inventory_stock_1).

каталог инвентар_

При распоредување на Magneto 2.3, првично имаме 2 записи store_website, што одговара на две локации - административен и главен клиент:

website_id|code |name        |sort_order|default_group_id|is_default|
----------|-----|------------|----------|----------------|----------|
         0|admin|Admin       |         0|               0|         0|
         1|base |Main Website|         0|               1|         1|

Табела cataloginventory_stock имаме само еден влез:

stock_id|website_id|stock_name|
--------|----------|----------|
       1|         0|Default   |

Тоа е, во нашата стара структура има само еден „магацин“ (stock) и тој е поврзан со административната веб-страница. Додавање нови преку админ панелот sources/stocks во MSI (нова структура) не резултира со нови записи во cataloginventory_stock.

Податоците за залихите за производите во старата структура првично се евидентираат во табелите:

  • cataloginventory_stock_item
  • cataloginventory_stock_status

cataloginventory_stock_item

function createOldItem($prodId, $qty)
{
    $isQtyDecimal = (((int)$qty) != $qty);
    $isInStock = ($qty > 0);
    /** @var MagentoFrameworkAppResourceConnection $this->resource */
    /** @var MagentoFrameworkDBAdapterPdoMysql $conn */
    $conn = $this->resource->getConnection();
    $table = $this->resource->getTableName('cataloginventory_stock_item');
    $bind = [
        'product_id' => $prodId,
        /* we use one only stock in 'cataloginventory' structure by default */
        'stock_id' => 1,
        'qty' => $qty,
        'is_qty_decimal' => $isQtyDecimal,
        'is_in_stock' => $isInStock,
        /* default stock is bound to admin website (see `cataloginventory_stock`) */
        'website_id' => 0
    ];
    $conn->insert($table, $bind);
}

cataloginventory_stock_status

function createOldStatus($prodId, $qty)
{
    $isInStock = ($qty > 0);
    /** @var MagentoFrameworkAppResourceConnection $this->resource */
    /** @var MagentoFrameworkDBAdapterPdoMysql $conn */
    $conn = $this->resource->getConnection();
    $table = $this->resource->getTableName('cataloginventory_stock_status');
    $bind = [
        'product_id' => $prodId,
        /* we use one only stock in 'cataloginventory' structure by default */
        'stock_id' => 1, 
        'qty' => $qty,
        'stock_status' => MagentoCatalogInventoryApiDataStockStatusInterface::STATUS_IN_STOCK,
        /* default stock is bound to admin website (see `cataloginventory_stock`) */
        'website_id' => 0 
    ];
    $conn->insert($table, $bind);
}

инвентар_

Првично, новата структура за складирање на податоци за залихи содржи 1 "извор'(inventory_source):

source_code|name          |enabled|description   |latitude|longitude|country_id|...|
-----------|--------------|-------|--------------|--------|---------|----------|...|
default    |Default Source|      1|Default Source|0.000000| 0.000000|US        |...|

и еден“магацин'(inventory_stock):

stock_id|name         |
--------|-------------|
       1|Default Stock|

«Извор» го претставува физичкото складирање на производите (записот содржи физички координати и адреса за пошта). "Складиште„е логичен спој на неколку „извори“ (inventory_source_stock_link)

link_id|stock_id|source_code|priority|
-------|--------|-----------|--------|
      1|       1|default    |       1|

на ниво на кое се јавува поврзувањето со продажниот канал (inventory_stock_sales_channel)

type   |code|stock_id|
-------|----|--------|
website|base|       1|

Судејќи според структурата на податоците, се претпоставуваат различни видови продажни канали, но стандардно само врската “акции"-" "(врската до веб-страницата го следи кодот на веб-страницата - base).

Еден"магацин„може да се поврзе со неколку“извори"и еден"извор„- на неколку“магацини„(врска од многу-на-многу). Исклучоците се стандардни "извор"И"магацин“. Тие не се повторно поврзани со други ентитети (ограничување на ниво на код - грешка „Не може да се зачува врската поврзана со стандардниот извор или стандардната залиха"). Повеќе детали за структурата MSI во Magento 2 може да се најдат во статијата “Систем за управување со складиште со користење на CQRS и извори на настани. Дизајн".

Ќе ја користам стандардната конфигурација и ќе ги додадам сите информации за залиха на изворот default, кој е вклучен во продажниот канал поврзан со веб-страницата со кодот base (одговара на предниот крај на продавницата - види store_website):

function createNewItem($sku, $qty)
{
    /** @var MagentoFrameworkAppResourceConnection $this->resource */
    /** @var MagentoFrameworkDBAdapterPdoMysql $conn */
    $conn = $this->resource->getConnection();
    $table = $this->resource->getTableName('inventory_source_item');
    $bind = [
        'source_code' => 'default',
        'sku' => $sku,
        'quantity' => $qty,
        'status' => MagentoInventoryApiApiDataSourceItemInterface::STATUS_IN_STOCK
    ];
    $conn->insert($table, $bind);
}

Откако ќе додадете податоци за залиха на производот во административниот панел, ја добивате оваа слика:

Magento 2: увезете производи директно во базата на податоци

Медиуми

Кога „рачно“ додавате слика на производ преку администраторскиот панел, релевантните информации се запишуваат во следните табели:

  • catalog_product_entity_media_gallery: медиумски регистар (слики и видео датотеки);
  • catalog_product_entity_media_gallery_value: поврзување на медиумите со производи и изложби (локализација);
  • catalog_product_entity_media_gallery_value_to_entity: поврзување медиуми само со производи (веројатно стандардна медиумска содржина за производот);
  • catalog_product_entity_varchar: Улогите во кои се користи сликата се зачувани овде;

а самите слики се зачувуваат во директориумот ./pub/media/catalog/product/x/y/каде x и y — првата и втората буква од името на датотеката со слика. На пример, датотека image.png треба да се зачува како ./pub/media/catalog/product/i/m/image.png, за да може платформата да ја користи како слика при опишување на производи од каталогот.

Регистрирајте се објавени во ./pub/media/catalog/product/ медиумска датотека (процесот на поставување на самата датотека не се дискутира во овој напис):

function createMediaGallery($imgPathPrefixed)
{
    $attrId = /* get attribute ID by attribute code 'media_gallery' */
    /** @var MagentoFrameworkAppResourceConnection $this->resource */
    /** @var MagentoFrameworkDBAdapterPdoMysql $conn */
    $conn = $this->resource->getConnection();
    $table = $this->resource->getTableName('catalog_product_entity_media_gallery');
    $bind = [
        'attribute_id' => $attrId,
        'value' => $imgPathPrefixed,
        /* 'image' or 'video' */
        'media_type' => 'image',
        'disabled' => false
    ];
    $conn->insert($table, $bind);
    $result = $conn->lastInsertId($table);
    return $result;
}

Кога е регистрирана, на новата медиумска датотека и се доделува идентификатор.

Ние ја поврзуваме регистрираната медиумска датотека со соодветниот производ за стандардниот излог:

function createGalleryValue($mediaId, $prodId)
{
    /** @var MagentoFrameworkAppResourceConnection $this->resource */
    /** @var MagentoFrameworkDBAdapterPdoMysql $conn */
    $conn = $this->resource->getConnection();
    $table = $this->resource->getTableName('catalog_product_entity_media_gallery_value');
    $bind = [
        'value_id' => $mediaId,
        /* use admin store view by default */
        'store_id' => 0,
        'entity_id' => $prodId,
        'label' => null,
        /* we have one only image */
        'position' => 1,
        'disabled' => false
    ];
    $conn->insert($table, $bind);
}

Регистрираната медиумска датотека ја поврзуваме со соодветниот производ без да бидеме врзани за излог. Не е јасно каде точно се користат овие податоци и зошто е невозможно да се пристапи до податоците од претходната табела, но оваа табела постои и податоците се запишуваат на неа кога ќе се додаде слика на производот. Па тоа е тоа.

function createGalleryValueToEntity($mediaId, $prodId)
{
    /** @var MagentoFrameworkAppResourceConnection $this->resource */
    /** @var MagentoFrameworkDBAdapterPdoMysql $conn */
    $conn = $this->resource->getConnection();
    $table = $this->resource->getTableName('catalog_product_entity_media_gallery_value_to_entity');
    $bind = [
        'value_id' => $mediaId,
        'entity_id' => $prodId
    ];
    $conn->insert($table, $bind);
}

catalog_product_entity_varchar

Медиумска датотека може да се користи со различни улоги (соодветниот код на атрибутот е означен во загради):

  • База(image)
  • Мала слика (small_image)
  • сликичка (thumbnail)
  • Своч слика (swatch_image)

Поврзувањето улоги со медиумска датотека е токму она што се случува во catalog_product_entity_varchar. Обврзувачкиот код е сличен на кодот во "Основни атрибути на производот".

Откако ќе додадете слика на производот во административниот панел, изгледа вака:

Magento 2: увезете производи директно во базата на податоци

Категории

Главни табели кои содржат податоци по категорија:

  • catalog_category_entity: регистар на категории;
  • catalog_category_product: врска помеѓу производите и категориите;
  • catalog_category_entity_*: вредности на атрибутот EAV;

Првично, во празна апликација Magento, регистарот на категории содржи 2 категории (ги скратив имињата на колоните: crt - created_at, upd - updated_at):

entity_id|attribute_set_id|parent_id|crt|upd|path|position|level|children_count|
---------|----------------|---------|---|---|----|--------|-----|--------------|
        1|               3|        0|...|...|1   |       0|    0|             1|
        2|               3|        1|...|...|1/2 |       1|    1|             0|

Категоријата со id=1 е коренот на целиот каталог на Magento и не е достапна ниту во административниот панел ниту на насловната страница. Категорија со id=2 (Стандардна категорија) е основната категорија за главната продавница на главната страница (Главна продавница на веб-страница) создадена кога апликацијата е распоредена (види. Админ / Продавници / Сите продавници). Покрај тоа, основната категорија на самата продавница исто така не е достапна на предната страна, туку само нејзините подкатегории.

Бидејќи темата на оваа статија сè уште е увоз на податоци за производите, нема да користам директно внесување во базата при креирање категории, туку ќе ги користам класите обезбедени од самиот Magento (модели и складишта). Директното внесување во базата на податоци се користи само за поврзување на увезениот производ со категорија (категоријата се совпаѓа со нејзиното име, а идентификацијата на категоријата се враќа при совпаѓањето):

function create($prodId, $catId)
{
    /** @var MagentoFrameworkAppResourceConnection $this->resource */
    /** @var MagentoFrameworkDBAdapterPdoMysql $conn */
    $conn = $this->resource->getConnection();
    $table = $this->resource->getTableName('catalog_category_product');
    $bind = [
        'category_id' => $catId,
        'product_id' => $prodId,
    ];
    $conn->insert($table, $bind);
}

Откако ќе додадете врска за производ до категориите „Категорија 1“ и „Категорија 2“, деталите за производот во административниот панел изгледаат вака:

Magento 2: увезете производи директно во базата на податоци

Дополнителни активности

Откако ќе заврши увозот на податоците, треба да ги завршите следните дополнителни чекори:

  • индексирање на податоци: јавете се во конзолата ./bin/magento indexer:reindex;
  • регенерирање URL-адреси за производи/категории: можете да ја користите наставката „elgentos/regenere-catalog-urls«

Производи во административниот панел по извршување на дополнителни дејства:

Magento 2: увезете производи директно во базата на податоци

и напред:

Magento 2: увезете производи директно во базата на податоци

Краток преглед

Истиот сет на производи (10 парчиња) како во претходниот напис се увезува барем за ред на големина побрзо (1 секунда наспроти 10). За попрецизно да ја процените брзината, потребен ви е поголем број производи - неколку стотици, или уште подобро илјадници. Сепак, дури и со толку мала големина на влезни податоци, можеме да заклучиме дека употребата на алатките обезбедени од Magento (модели и складишта) е значајна (нагласувам - многу!) го забрза развојот на потребната функционалност, но во исто време значително (нагласувам - многу!) намалете ја брзината со која податоците влегуваат во базата на податоци.

Како резултат на тоа, водата се покажа влажна и ова не е откровение. Сепак, сега го имам кодот со кој да си поиграм и можеби да дојдам до некои поинтересни заклучоци.

Извор: www.habr.com

Додадете коментар