Magento 2: ymportearje produkten direkt yn 'e databank

В foarige artikel Ik beskreau it proses fan it ymportearjen fan produkten yn Magento 2 op 'e gewoane manier - fia modellen en repositories. De gewoane metoade hat in heul lege gegevensferwurkingssnelheid. Myn laptop produsearre sawat ien produkt per sekonde. Yn dizze fuortsetting beskôgje ik in alternative manier om in produkt te ymportearjen - troch direkte yngong yn 'e databank, troch de standert Magento 2-meganismen (modellen, fabriken, repositories) te omgean. De folchoarder fan stappen om produkten te ymportearjen kin oanpast wurde oan elke programmeartaal dy't kin wurkje mei MySQL.

Disclaimer: Magento hat klearebare funksjonaliteit foar gegevens ymportearje en, nei alle gedachten, it sil wêze genôch foar dy. As jo ​​​​lykwols mear folsleine kontrôle nedich hawwe oer it ymportproses, net beheind ta it tarieden fan in CSV-bestân foar wat jo hawwe, wolkom by kat.

Magento 2: ymportearje produkten direkt yn 'e databank

De koade dy't ûntstiet út it skriuwen fan beide artikels kin besjoen wurde yn 'e Magento-module "flancer32/mage2_ext_demo_import". Hjir binne wat beheiningen dy't ik folge om de koade fan de demomodule te ferienfâldigjen:

  • Produkten wurde allinich makke, net bywurke.
  • Ien pakhús
  • Allinnich kategorynammen wurde ymportearre, sûnder harren struktuer
  • Gegevensstruktueren foldogge oan ferzje 2.3

JSON foar it ymportearjen fan ien produkt:

{
  "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"
}

Oersjoch fan de wichtichste stadia fan ymport

  • registraasje fan it produkt sels
  • ferbining tusken produkt en webside
  • Basic Product attributes (EAV)
  • ynventarisgegevens (hoefolle produkt op foarried)
  • media (foto's)
  • ferbining mei katalogus kategoryen

Produkt Registraasje

Basis produktynformaasje kin fûn wurde yn 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`)
)

De minimale ynformaasje dy't nedich is om in yngong yn it produktregister te meitsjen is:

  • attribute_set_id
  • sku

oanfoljend:

  • type_id - as wy it net spesifisearje, dan sil 'ienfâldich' brûkt wurde

Om direkt nei de databank te skriuwen, brûk ik de DB-adapter fan Magento sels:

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

Nei it registrearjen fan it produkt mei catalog_product_entity it wurdt sichtber yn it adminpaniel, yn it produktraster (Katalogus / Products).

Magento 2: ymportearje produkten direkt yn 'e databank

Relaasje tusken produkt en webside

De assosjaasje fan it produkt mei de side bepaalt yn hokker winkels en displays it produkt oan de foarkant te krijen is.

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: ymportearje produkten direkt yn 'e databank

Basis produkt attributen

It nij registrearre produkt hat noch gjin namme of beskriuwing. Dit alles wurdt dien troch EAV attributen. Hjir is in list mei basisproduktattributen dy't nedich binne om it produkt korrekt op 'e foarkant te sjen:

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

In apart attribút wurdt tafoege oan in produkt lykas dit (de details fan it krijen fan de identifier en it type fan it attribút út syn koade binne weilitten):

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

Mei de attribútkoade bepale wy syn id en gegevenstype (datetime, decimal, int, text, varchar), skriuw dan de gegevens foar it bestjoerlike finster yn de passende tabel (store_id = 0).

Nei it tafoegjen fan de boppesteande attributen oan it produkt, krije jo dizze ôfbylding yn it adminpaniel:

Magento 2: ymportearje produkten direkt yn 'e databank

Ynventarisaasje gegevens

Begjinnend fan ferzje 2.3 yn Magento binne d'r twa parallelle sets tabellen dy't opslach leverje fan ynventarisaasjeynformaasje (produktkwantiteit):

  • cataloginventory_*: âlde struktuer;
  • inventory_*: nije struktuer (MSI - Multi Source Inventory);

Jo moatte tafoegje ynventarisaasje gegevens oan beide struktueren, omdat de nije struktuer is noch net folslein ûnôfhinklik fan 'e âlde (it is tige wierskynlik dat foar default pakhús yn de nije struktuer in tafel is belutsen cataloginventory_stock_status lykas inventory_stock_1).

cataloginventory_

By it ynsetten fan Magneto 2.3 hawwe wy yn earste ynstânsje 2 yngongen yn store_website, wat oerienkomt mei twa siden - bestjoerlike en haadkliïnt:

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

Tafel cataloginventory_stock wy hawwe mar ien yngong:

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

Dat is, yn ús âlde struktuer is d'r mar ien "pakhús" (stock) en it is keppele oan de bestjoerlike webside. Nije tafoegje fia it adminpaniel sources/stocks yn MSI (nije struktuer) net resultearje yn nije yngongen yn cataloginventory_stock.

Ynventarisgegevens oer produkten yn 'e âlde struktuer wurde yn earste ynstânsje opnommen yn tabellen:

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

ynventaris_

Yn earste ynstânsje befettet de nije struktuer foar it opslaan fan ynventarisgegevens 1 "boarne"(inventory_source):

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

en ien"pakhús"(inventory_stock):

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

«Boarne» fertsjintwurdiget de fysike opslach foar produkten (it rekord befettet fysike koördinaten en postadres). "Warehouse"is in logyske uny fan ferskate "boarnen" (inventory_source_stock_link)

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

op it nivo wêrop de ferbining mei it ferkeapkanaal plakfynt (inventory_stock_sales_channel)

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

Beoardielje troch de gegevensstruktuer, wurde ferskate soarten ferkeapkanalen oannommen, mar standert allinich de ferbining "stock"-"website"(de keppeling nei de webside folget de websidekoade - base).

Ien "pakhús"kin keppele wurde oan ferskate"boarnen"en ien"boarne"- oan ferskate"pakhuzen"(in protte-to-in protte relaasje). De útsûnderings binne standert "boarne"En"pakhús". Se binne net opnij keppele oan oare entiteiten (beheining op koadenivo - de flater "Kin gjin keppeling opslaan relatearre oan Standert boarne of Standert Stock"). Mear details oer de MSI-struktuer yn Magento 2 kinne fûn wurde yn it artikel "Warehouse management systeem mei CQRS en Event Sourcing. Ûntwerp".

Ik sil de standertkonfiguraasje brûke en alle ynventarisynformaasje tafoegje oan 'e boarne default, dy't belutsen is by it ferkeapkanaal ferbûn mei de webside mei de koade base (komt oerien mei de foarkant fan 'e winkel - sjoch 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);
}

Nei it tafoegjen fan ynventarisgegevens oan it produkt yn it adminpaniel, krije jo dizze ôfbylding:

Magento 2: ymportearje produkten direkt yn 'e databank

Media

As "manueel" in ôfbylding tafoegje oan in produkt fia it adminpaniel, wurdt de relevante ynformaasje opskreaun yn 'e folgjende tabellen:

  • catalog_product_entity_media_gallery: mediaregister (ôfbyldings en fideobestannen);
  • catalog_product_entity_media_gallery_value: keppeljen fan media oan produkten en showcases (lokalisaasje);
  • catalog_product_entity_media_gallery_value_to_entity: keppele media oan produkten allinnich (nei alle gedachten standert media ynhâld foar it produkt);
  • catalog_product_entity_varchar: De rollen dêr't de ôfbylding yn brûkt wurdt, wurde hjir bewarre;

en de ôfbyldings sels wurde bewarre yn 'e map ./pub/media/catalog/product/x/y/wêr x и y - de earste en twadde letters fan de namme fan it byldbestân. Bygelyks, triem image.png moatte wurde bewarre as ./pub/media/catalog/product/i/m/image.png, sadat it platfoarm it as ôfbylding brûke kin by it beskriuwen fan produkten út de katalogus.

Register pleatst yn ./pub/media/catalog/product/ mediabestân (it proses fan it pleatsen fan it bestân sels wurdt net besprutsen yn dit artikel):

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

As registrearre, wurdt in nij mediabestân in identifier tawiisd.

Wy assosjearje it registrearre mediabestân mei it oerienkommende produkt foar de standert winkelfront:

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

Wy assosjearje it registrearre mediabestân mei it korrespondearjende produkt sûnder te wêzen bûn oan in winkelfront. It is net dúdlik wêr't dizze gegevens krekt brûkt wurde en wêrom't it ûnmooglik is om tagong te krijen ta de gegevens fan 'e foarige tabel, mar dizze tabel bestiet en de gegevens wurde skreaun nei it as in foto tafoege wurdt oan it produkt. Dat is it dus.

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

In mediabestân kin brûkt wurde mei ferskate rollen (de oerienkommende attribútkoade wurdt oanjûn tusken heakjes):

  • Basis(image)
  • Lytse ôfbylding (small_image)
  • Miniatuer (thumbnail)
  • Swatchôfbylding (swatch_image)

Rollen keppelje oan in mediabestân is krekt wat der yn bart catalog_product_entity_varchar. De binende koade is fergelykber mei de koade yn de "Basis produkt attributen".

Nei it tafoegjen fan in ôfbylding oan it produkt yn it adminpaniel sjocht it der sa út:

Magento 2: ymportearje produkten direkt yn 'e databank

Categories

Haadtabellen mei gegevens per kategory:

  • catalog_category_entity: register fan kategoryen;
  • catalog_category_product: ferbining tusken produkten en kategoryen;
  • catalog_category_entity_*: EAV attribút wearden;

Yn it earstoan, yn in lege Magento-applikaasje, befettet it kategoryregister 2 kategoryen (ik haw de kolomnammen ynkoarte: 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|

De kategory mei id = 1 is de root fan 'e hiele Magento-katalogus en is net beskikber yn it adminpaniel of op 'e foarside. Kategory mei id=2 (Standert Kategory) is de rootkategory foar de haadwinkel fan 'e haadside (Main Website Store) makke as de applikaasje wurdt ynset (sjoch. Admin / Winkels / Alle winkels). Boppedat is de rootkategory fan 'e winkel sels ek net oan' e foarkant beskikber, allinich syn subkategoryen.

Om't it ûnderwerp fan dit artikel noch gegevens oer produkten ymportearret, sil ik gjin direkte yngong yn 'e databank brûke by it meitsjen fan kategoryen, mar sil de klassen brûke dy't Magento sels leveret (modellen en repositories). Direkte ynfier yn 'e databank wurdt allinich brûkt om it ymporteare produkt te assosjearjen mei in kategory (de kategory wurdt oerienkomme mei syn namme, en de kategory-id wurdt ophelle tidens it oerienkommen):

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

Nei it tafoegjen fan in produktkeppeling oan 'e kategoryen "Kategory 1" en "Kategory 2", sjogge de produktdetails yn it adminpaniel der sa út:

Magento 2: ymportearje produkten direkt yn 'e databank

Oanfoljende aksjes

Sadree't de gegevensymport is foltôge, moatte jo de folgjende ekstra stappen foltôgje:

  • data yndeksearring: belje yn 'e konsole ./bin/magento indexer:reindex;
  • regenerearjen fan URL's foar produkten/kategoryen: jo kinne de tafoeging brûke "elgentos/regenerate-catalog-urls«

Produkten yn it adminpaniel nei it útfieren fan ekstra aksjes:

Magento 2: ymportearje produkten direkt yn 'e databank

en foarop:

Magento 2: ymportearje produkten direkt yn 'e databank

Gearfetting

Deselde set fan produkten (10 stikken) as yn it foarige artikel wurdt ymportearre op syn minst in folchoarder fan grutte flugger (1 sekonde tsjin 10). Om de snelheid krekter te skatten, hawwe jo in grutter oantal produkten nedich - ferskate hûnderten, of better noch tûzenen. Sels mei sa'n lytse grutte fan ynfiergegevens kinne wy ​​​​lykwols konkludearje dat it gebrûk fan 'e ark levere troch Magento (modellen en repositories) signifikant is (ik beklamje - folle!) Fersnelle de ûntwikkeling fan 'e fereaske funksjonaliteit, mar tagelyk signifikant (ik beklamje - folle!) ferminderje de snelheid wêrmei't gegevens yn 'e databank komme.

Dêrtroch bleek it wetter wiet te wêzen en dit is gjin iepenbiering. No haw ik lykwols de koade om mei te boartsjen en miskien ta wat nijsgjirrigere konklúzjes te kommen.

Boarne: www.habr.com