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 — егер біз оны көрсетпесек, «қарапайым» пайдаланылады

Дерекқорға тікелей жазу үшін мен Magento-ның DB адаптерін қолданамын:

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);
    }
}

Атрибут кодын пайдаланып, оның идентификаторы мен деректер түрін анықтаймыз (datetime, decimal, int, text, varchar), содан кейін әкімшілік терезенің деректерін сәйкес кестеге жазыңыз (store_id = 0).

Өнімге жоғарыда аталған атрибуттарды қосқаннан кейін әкімші панелінде мына суретті аласыз:

Magento 2: өнімдерді тікелей дерекқорға импорттау

Түгендеу деректері

Magento 2.3 нұсқасынан бастап инвентарлық ақпаратты (өнім саны) сақтауды қамтамасыз ететін екі параллель кестелер жинағы бар:

  • 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

каталог_инвентарлық_қор_элемесі

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);
}

каталог_қор_жайы

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).

Бір »қойма«бірнешемен байланыстыруға болады»көздері«және бір»көзі"-бірнешеге"қоймалар«(көптен көпке қатынасы). Ерекшеліктер әдепкі болып табылады "көзі«Ал»қойма«. Олар басқа нысандармен қайта байланыспайды (код деңгейіндегі шектеу – қате «Әдепкі көзге немесе әдепкі қорға қатысты сілтемені сақтау мүмкін емес«). Magento 2-дегі MSI құрылымы туралы толығырақ ақпаратты мақаладан табуға болады.CQRS және Event Sourcing көмегімен қойманы басқару жүйесі. Дизайн«.

Мен әдепкі конфигурацияны қолданамын және барлық инвентарлық ақпаратты көзге қосамын 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/regenerate-catalog-urls«

Қосымша әрекеттерді орындағаннан кейін басқару тақтасындағы өнімдер:

Magento 2: өнімдерді тікелей дерекқорға импорттау

және алдыңғы жағында:

Magento 2: өнімдерді тікелей дерекқорға импорттау

Резюме

Алдыңғы мақаладағыдай өнімдердің бірдей жиынтығы (10 дана) кем дегенде магнитудасы жылдамырақ импортталады (1-ға қарсы 10 секунд). Жылдамдықты дәлірек бағалау үшін сізге көбірек өнімдер қажет - бірнеше жүздеген немесе одан да жақсырақ мыңдаған. Дегенмен, кіріс деректерінің осындай шағын өлшемімен де, Magento ұсынатын құралдарды (модельдер мен репозиторийлер) пайдалану маңызды деп қорытынды жасауға болады (мен атап өтемін - өте!) қажетті функционалдылықты дамытуды жылдамдатады, бірақ сонымен бірге айтарлықтай (мен атап өтемін - өте!) деректердің дерекқорға түсу жылдамдығын азайту.

Нәтижесінде су дымқыл болып шықты және бұл аян емес. Дегенмен, қазір менде ойнауға болатын код бар және мүмкін одан да қызықты қорытындыларға келемін.

Ақпарат көзі: www.habr.com