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 — 如果我們不指定它,那麼將使用“simple”

為了直接寫入資料庫,我使用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:將產品直接匯入資料庫

庫存數據

從 Magento 2.3 版本開始,有兩組並行的表格提供庫存資訊(產品數量)的儲存:

  • cataloginventory_*:舊結構;
  • inventory_*:新結構(MSI - 多源庫存);

您需要將庫存資料添加到這兩個結構中,因為新結構尚未完全獨立於舊結構(很可能對於 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 和事件來源的倉庫管理系統。 設計“。

我將使用預設配置並將所有庫存資訊新增至來源中 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本身提供的類別(模型和儲存庫)。 直接錄入資料庫僅用於將匯入的產品與類別關聯(類別透過名稱進行匹配,匹配時檢索類別id):

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/重新生成目錄 url«

執行其他操作後管理面板中的產品:

Magento 2:將產品直接匯入資料庫

在前面:

Magento 2:將產品直接匯入資料庫

總結

與上一篇文章相同的一組產品(10 件)的導入速度至少快一個數量級(1 秒對 10 件)。 為了更準確地估計速度,您需要更多數量的產品 - 數百個,甚至數千個。 然而,即使輸入資料如此小,我們也可以得出結論,使用 Magento 提供的工具(模型和儲存庫)是很重要的(我強調 - 顯著地!)加快所需功能的開發,但同時顯著(我強調 - 顯著地!)降低資料進入資料庫的速度。

結果發現水是濕的,這不是一個啟示。 然而,現在我有了可以使用的程式碼,也許可以得出一些更有趣的結論。

來源: www.habr.com