Magento 2: ürünleri doğrudan veritabanına aktarın

В önceki haber Magento 2'ye ürün aktarma sürecini her zamanki gibi modeller ve depolar aracılığıyla anlattım. Her zamanki yöntemin veri işleme hızı çok düşüktür. Dizüstü bilgisayarım saniyede yaklaşık bir ürün üretiyordu. Bu devamda, standart Magento 2 mekanizmalarını (modeller, fabrikalar, depolar) atlayarak veritabanına doğrudan giriş yaparak bir ürünü içe aktarmanın alternatif bir yolunu ele alacağım. Ürünleri içe aktarma adımlarının sırası, MySQL ile çalışabilen herhangi bir programlama diline uyarlanabilir.

Feragatname: Magento'nun aşağıdakiler için hazır işlevleri vardır: veri içe aktarma ve büyük olasılıkla sizin için yeterli olacaktır. Ancak, sahip olduğunuz CSV dosyasını hazırlamakla sınırlı olmamak üzere, içe aktarma süreci üzerinde daha eksiksiz bir kontrole ihtiyacınız varsa cat'e hoş geldiniz.

Magento 2: ürünleri doğrudan veritabanına aktarın

Her iki makalenin yazılması sonucunda ortaya çıkan kod Magento modülünde görüntülenebilir "flancer32/mage2_ext_demo_import". Demo modül kodunu basitleştirmek için takip ettiğim bazı kısıtlamalar şunlardır:

  • Ürünler yalnızca oluşturulur, güncellenmez.
  • Bir depo
  • Yapıları olmadan yalnızca kategori adları içe aktarılır
  • Veri yapıları sürüm 2.3 ile uyumludur

Tek bir ürünü içe aktarmak için 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"
}

İthalatın ana aşamalarına genel bakış

  • ürünün kendisinin kaydı
  • ürün ve web sitesi arasındaki bağlantı
  • temel ürün özellikleri (EAV)
  • envanter verileri (stokta bulunan ürün miktarı)
  • medya (resimler)
  • katalog kategorileriyle bağlantı

Ürün kaydı

Temel ürün bilgileri şurada bulunabilir: 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`)
)

Ürün kayıt defterinde bir giriş oluşturmak için gereken minimum bilgiler şunlardır:

  • attribute_set_id
  • sku

ek olarak:

  • type_id — eğer belirtmezsek 'basit' kullanılacaktır

Doğrudan veritabanına yazmak için Magento'nun DB adaptörünü kullanıyorum:

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

Ürünü kaydettikten sonra catalog_product_entity yönetici panelinde, ürün tablosunda görünür hale gelir (Katalog/Ürünler).

Magento 2: ürünleri doğrudan veritabanına aktarın

Ürün ve web sitesi arasındaki ilişki

Ürünün siteyle ilişkilendirilmesi, ürünün hangi mağazalarda ve vitrinlerde ön planda yer alacağını belirler.

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: ürünleri doğrudan veritabanına aktarın

Temel ürün özellikleri

Yeni kayıt edilen ürünün henüz bir adı veya açıklaması yoktur. Bütün bunlar aracılığıyla yapılır EAV özellikleri. Ürünün ön tarafta doğru şekilde görüntülenmesi için gereken temel ürün özelliklerinin listesi aşağıda verilmiştir:

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

Bunun gibi bir ürüne ayrı bir özellik eklenir (koddan özelliğin tanımlayıcısını ve türünü elde etme ayrıntıları atlanır):

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

Özellik kodunu kullanarak kimliğini ve veri türünü belirleriz (datetime, decimal, int, text, varchar), ardından yönetim penceresinin verilerini uygun tabloya yazın (store_id = 0).

Yukarıdaki özellikleri ürüne ekledikten sonra yönetici panelinde şu resmi görürsünüz:

Magento 2: ürünleri doğrudan veritabanına aktarın

Envanter verileri

Magento'daki sürüm 2.3'ten başlayarak, envanter bilgilerinin (ürün miktarı) depolanmasını sağlayan iki paralel tablo seti bulunmaktadır:

  • cataloginventory_*: eski yapı;
  • inventory_*: yeni yapı (MSI - Çok Kaynaklı Envanter);

Envanter verilerini her iki yapıya da eklemeniz gerekir çünkü yeni yapı henüz eskisinden tamamen bağımsız değildir (büyük ihtimalle default yeni yapıdaki depoda bir masa yer alıyor cataloginventory_stock_status gibi inventory_stock_1).

katalog envanteri_

Magneto 2.3'ü dağıtırken başlangıçta 2 girdimiz var store_websiteiki siteye karşılık gelir - idari ve ana istemci:

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

Tablo cataloginventory_stock sadece bir girdimiz var:

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

Yani eski yapımızda tek bir “depo” var (stock) ve idari web sitesine bağlantılıdır. Admin panelinden yenilerini ekleme sources/stocks MSI'da (yeni yapı) yeni girişlere yol açmaz cataloginventory_stock.

Eski yapıdaki ürünlere ilişkin stok verileri başlangıçta tablolara kaydedilir:

  • cataloginventory_stock_item
  • cataloginventory_stock_status

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

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

envanter_

Başlangıçta, envanter verilerinin depolanmasına yönelik yeni yapı 1 "kaynak"(inventory_source):

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

ve bir "depo"(inventory_stock):

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

«Kaynak» ürünler için fiziksel depolamayı temsil eder (kayıt fiziksel koordinatları ve posta adresini içerir). "depo"birkaç" kaynağın "mantıksal birleşimidir (inventory_source_stock_link)

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

satış kanalıyla bağlantının gerçekleştiği düzeyde (inventory_stock_sales_channel)

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

Veri yapısına göre çeşitli türde satış kanalları varsayılır, ancak varsayılan olarak yalnızca bağlantı "Stok"-"Web sitesi"(web sitesine olan bağlantı web sitesi kodunu takip eder - base).

Bir "depo"Birkaç taneye bağlanabilir"kaynaklar"ve bir "kaynak"- birkaçına"depolar"(çoka-çok ilişki). İstisnalar varsayılandır "kaynak"Ve"depo". Diğer varlıklara yeniden bağlanmazlar (kod düzeyinde sınırlama - hata "Varsayılan Kaynak veya Varsayılan Stok ile ilgili bağlantı kaydedilemiyor"). Magento 2'deki MSI yapısı hakkında daha fazla ayrıntıyı "CQRS ve Event Sourcing kullanan depo yönetim sistemi. Tasarım".

Varsayılan yapılandırmayı kullanacağım ve tüm envanter bilgilerini kaynağa ekleyeceğim defaultkoduyla web sitesiyle ilişkili satış kanalında yer alan base (mağazanın ön ucuna karşılık gelir - bkz. 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);
}

Yönetici panelinde ürüne envanter verilerini ekledikten sonra şu resmi görürsünüz:

Magento 2: ürünleri doğrudan veritabanına aktarın

medya

Yönetici paneli aracılığıyla bir ürüne “manuel olarak” görsel eklenirken ilgili bilgiler aşağıdaki tablolara yazılır:

  • catalog_product_entity_media_gallery: medya kaydı (resimler ve video dosyaları);
  • catalog_product_entity_media_gallery_value: medyayı ürünlere ve vitrinlere bağlamak (yerelleştirme);
  • catalog_product_entity_media_gallery_value_to_entity: medyayı yalnızca ürünlere bağlamak (muhtemelen ürün için varsayılan medya içeriği);
  • catalog_product_entity_varchar: Görüntünün kullanıldığı roller burada saklanır;

ve görüntülerin kendileri dizine kaydedilir ./pub/media/catalog/product/x/y/Nerede x и y — görüntü dosyası adının birinci ve ikinci harfleri. Örneğin, dosya image.png olarak kaydedilmeli ./pub/media/catalog/product/i/m/image.pngböylece platform, katalogdaki ürünleri açıklarken bunu resim olarak kullanabilir.

Kayıt gönderildi ./pub/media/catalog/product/ media dosyası (dosyanın kendisini yerleştirme işlemi bu makalede ele alınmamıştır):

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

Kaydedildiğinde yeni bir medya dosyasına bir tanımlayıcı atanır.

Kayıtlı medya dosyasını varsayılan vitrin için ilgili ürünle ilişkilendiririz:

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

Kayıtlı medya dosyasını herhangi bir vitrine bağlamadan ilgili ürünle ilişkilendiriyoruz. Bu verinin tam olarak nerede kullanıldığı ve bir önceki tablodaki verilere neden ulaşılamadığı açık değil ancak bu tablo mevcut ve ürüne resim eklendiğinde veriler ona yazılıyor. İşte bu kadar.

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

katalog_ürün_entity_varchar

Bir medya dosyası farklı rollerle kullanılabilir (ilgili nitelik kodu parantez içinde gösterilir):

  • Temel (image)
  • Küçük Resim (small_image)
  • Küçük resim (thumbnail)
  • Renk Örneği Resmi (swatch_image)

Rolleri bir medya dosyasına bağlamak tam olarak şu şekilde olur: catalog_product_entity_varchar. Bağlama kodu, "Temel ürün özellikleri".

Yönetici panelinde ürüne bir resim ekledikten sonra şu şekilde görünür:

Magento 2: ürünleri doğrudan veritabanına aktarın

kategori

Kategoriye göre verileri içeren ana tablolar:

  • catalog_category_entity: kategorilerin kaydı;
  • catalog_category_product: ürünler ve kategoriler arasındaki bağlantı;
  • catalog_category_entity_*: EAV öznitelik değerleri;

Başlangıçta boş bir Magento uygulamasında kategori kaydı 2 kategori içerir (sütun adlarını kısalttım: 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|

Kimliği=1 olan kategori tüm Magento kataloğunun köküdür ve ne yönetici panelinde ne de ön sayfada mevcut değildir. Kimliği=2 olan kategori (varsayılan Kategori) ana sitenin ana mağazasının kök kategorisidir (Ana Web Sitesi Mağazası) uygulamayı dağıtırken oluşturulur (bkz. Yönetici / Mağazalar / Tüm Mağazalar). Üstelik mağazanın kök kategorisi de ön tarafta mevcut değil, yalnızca alt kategorileri mevcut.

Bu makalenin konusu hala ürünlere ilişkin verileri içe aktarmak olduğundan, kategorileri oluştururken veritabanına doğrudan girişi kullanmayacağım, bunun yerine Magento'nun sağladığı sınıfları (modeller ve depolar) kullanacağım. Veritabanına doğrudan giriş, yalnızca içe aktarılan ürünü bir kategoriyle ilişkilendirmek için kullanılır (kategori, adıyla eşleştirilir ve eşleştirme sırasında kategori kimliği alınır):

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

“Kategori 1” ve “Kategori 2” kategorilerine bir ürün bağlantısı ekledikten sonra yönetici panelindeki ürün detayları şuna benzer:

Magento 2: ürünleri doğrudan veritabanına aktarın

Ek işlemler

Verilerin içe aktarımı tamamlandıktan sonra aşağıdaki ek adımları tamamlamanız gerekir:

Ek işlemler gerçekleştirdikten sonra yönetici panelindeki ürünler:

Magento 2: ürünleri doğrudan veritabanına aktarın

ve ön tarafta:

Magento 2: ürünleri doğrudan veritabanına aktarın

Özet

Önceki makaledekiyle aynı ürün seti (10 parça), en azından bir kat daha hızlı (1'a karşı 10 saniye) ithal ediliyor. Hızı daha doğru bir şekilde tahmin etmek için daha fazla sayıda ürüne ihtiyacınız var - birkaç yüz veya daha iyisi binlerce. Ancak bu kadar küçük boyutlu girdi verileriyle bile Magento tarafından sağlanan araçların (modeller ve depolar) kullanımının önemli olduğu sonucuna varabiliriz (vurgularım - çok!) gerekli işlevselliğin gelişimini hızlandırır, ancak aynı zamanda önemli ölçüde (vurgularım - çok!) Verilerin veritabanına girme hızını azaltır.

Sonuç olarak suyun ıslak olduğu ortaya çıktı ve bu bir vahiy değil. Ancak artık oynayabileceğim kod var ve belki daha ilginç sonuçlara varabilirim.

Kaynak: habr.com