В Popísal som proces dovozu produktov v Magento 2. Obvyklá metóda – prostredníctvom modelov a repozitárov. Obvyklá metóda sa vyznačuje veľmi nízkou rýchlosťou spracovania dát. Na mojom notebooku produkoval približne jeden produkt za sekundu. V tomto pokračovaní zvažujem alternatívnu metódu importu produktov – priamy zápis do databázy, obchádzanie štandardných mechanizmov. Magento 2 (modely, továrne, repozitáre). Postupnosť krokov pre import produktov je možné prispôsobiť akémukoľvek programovaciemu jazyku, ktorý podporuje MySQL.
Disclaimer: V Magento existuje pripravená funkcionalita pre a s najväčšou pravdepodobnosťou vám to bude stačiť. Ak však potrebujete úplnejšiu kontrolu nad procesom importu, ktorý sa neobmedzuje len na prípravu súboru CSV pre to, čo máte, vitajte na stránke cat.

Výsledný kód pre oba články si môžete pozrieť na adrese Magento-modul "". Tu sú niektoré obmedzenia, ktoré som dodržiaval, aby som zjednodušil kód demo modulu:
- Produkty sú len vytvorené, nie aktualizované.
- Jeden sklad
- Importujú sa iba názvy kategórií bez ich štruktúry
- Dátové štruktúry zodpovedajú verzii 2.3
JSON na import jedného produktu:
{
"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"
}Prehľad hlavných fáz importu
- registrácia samotného produktu
- prepojenie medzi produktom a webovou stránkou
- základné atribúty produktu (EAV)
- skladové údaje (množstvo produktu na sklade)
- médiá (obrázky)
- prepojenie s katalógovými kategóriami
Registrácia produktu
Základné informácie o produkte nájdete v 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`)
)Minimálne informácie potrebné na vytvorenie záznamu v registri produktov sú:
attribute_set_idsku
dodatočné:
type_id— ak to nešpecifikujeme, použije sa slovo „jednoduché“.
Na priamy zápis do databázy používam samotný DB adaptér 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;
}Po registrácii produktu s catalog_product_entity zobrazí sa na paneli správcu, v mriežke produktov (Katalóg/Produkty).

Vzťah medzi produktom a webovou stránkou
Priradenie produktu k stránke určuje, v ktorých predajniach a výstavách bude produkt dostupný na prednej strane.
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);
}
Základné vlastnosti produktu
Novo zaregistrovaný produkt ešte nemá názov ani popis. Toto všetko sa robí cez . Tu je zoznam základných atribútov produktu, ktoré sú potrebné na to, aby sa produkt správne zobrazoval na prednej strane:
namepricedescriptionshort_descriptionstatustax_class_idurl_keyvisibility
K takémuto produktu sa pridá samostatný atribút (podrobnosti o získaní identifikátora a typu atribútu z jeho kódu sú vynechané):
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);
}
}Pomocou kódu atribútu určíme jeho ID a typ údajov (datetime, decimal, int, text, varchar), potom zapíšte údaje pre administratívne okno do príslušnej tabuľky (store_id = 0).
Po pridaní vyššie uvedených atribútov k produktu získate tento obrázok v administračnom paneli:

Údaje o zásobách
Od verzie 2.3 Magento Existujú dve paralelné sady tabuliek, ktoré poskytujú ukladanie informácií o zásobách (množstvo produktu):
cataloginventory_*: stará štruktúra;inventory_*: nová štruktúra (MSI - Multi Source Inventory);
K obom štruktúram musíte pridať údaje o zásobách, pretože nová štruktúra ešte nie je úplne nezávislá od starej (je veľmi pravdepodobné, že pre default sklad v novej štruktúre je zahrnutý stôl cataloginventory_stock_status ako inventory_stock_1).
katalógový inventár_
Pri nasadzovaní Magneto 2.3 máme na začiatku 2 položky store_website, čo zodpovedá dvom stránkam - administratívnemu a hlavnému klientovi:
website_id|code |name |sort_order|default_group_id|is_default|
----------|-----|------------|----------|----------------|----------|
0|admin|Admin | 0| 0| 0|
1|base |Main Website| 0| 1| 1|Tabuľka cataloginventory_stock máme len jeden záznam:
stock_id|website_id|stock_name|
--------|----------|----------|
1| 0|Default |To znamená, že v našej starej štruktúre je len jeden „sklad“ (stock) a je prepojený s administratívnou webovou stránkou. Pridávanie nových cez administračný panel sources/stocks v MSI (nová štruktúra) nevedie k novým záznamom v cataloginventory_stock.
Údaje o zásobách o výrobkoch v starej štruktúre sa spočiatku zaznamenávajú v tabuľkách:
cataloginventory_stock_itemcataloginventory_stock_status
katalógový_zásob_položky
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);
}katalógový_stav_skladov
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);
}inventár_
Na začiatku nová štruktúra na ukladanie údajov o zásobách obsahuje 1 "zdroj"(inventory_source):
source_code|name |enabled|description |latitude|longitude|country_id|...|
-----------|--------------|-------|--------------|--------|---------|----------|...|
default |Default Source| 1|Default Source|0.000000| 0.000000|US |...|a jeden "sklad"(inventory_stock):
stock_id|name |
--------|-------------|
1|Default Stock|«Zdroj» predstavuje fyzické úložisko pre produkty (záznam obsahuje fyzické súradnice a poštovú adresu). "Sklad"je logickým spojením niekoľkých "zdrojov" (inventory_source_stock_link)
link_id|stock_id|source_code|priority|
-------|--------|-----------|--------|
1| 1|default | 1|na úrovni, na ktorej dochádza k spojeniu s predajným kanálom (inventory_stock_sales_channel)
type |code|stock_id|
-------|----|--------|
website|base| 1|Podľa štruktúry údajov sa predpokladajú rôzne typy predajných kanálov, ale štandardne iba spojenie „sklad„-“webové stránky"(odkaz na webovú stránku nasleduje za kódom webovej stránky - base).
jeden"sklad"možno prepojiť s viacerými"na zdroje"a jeden "zdroj"- viacerým"sklady"(vzťah veľa k mnohým). Výnimky sú predvolené "zdroj"A"sklad". Nie sú opätovne prepojené s inými entitami (obmedzenie na úrovni kódu – chyba “Nie je možné uložiť odkaz súvisiaci s predvoleným zdrojom alebo predvoleným skladom"). Viac podrobností o štruktúre MSI nájdete v Magento 2 si môžete prečítať v článku „".
Použijem predvolenú konfiguráciu a do zdroja pridám všetky informácie o inventári default, ktorý je zapojený do predajného kanála spojeného s webovou stránkou s kódom base (zodpovedá prednej časti predajne - viď 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);
}Po pridaní údajov o sklade k produktu na paneli správcu získate tento obrázok:

Médiá
Pri „ručnom“ pridávaní obrázka k produktu cez administračný panel sa príslušné informácie zapíšu do nasledujúcich tabuliek:
catalog_product_entity_media_gallery: register médií (obrázky a video súbory);catalog_product_entity_media_gallery_value: prepojenie médií s produktmi a vitrínami (lokalizácia);catalog_product_entity_media_gallery_value_to_entity: prepojenie médií iba s produktmi (pravdepodobne predvolený mediálny obsah pre produkt);catalog_product_entity_varchar: Tu sú uložené roly, v ktorých sa obrázok používa;
a samotné obrázky sa uložia do adresára ./pub/media/catalog/product/x/y/Kde x и y — prvé a druhé písmeno názvu súboru obrázka. Napríklad súbor image.png by mal byť uložený ako ./pub/media/catalog/product/i/m/image.png, aby ho platforma mohla použiť ako obrázok pri popise produktov z katalógu.
Catalog_product_entity_media_gallery
Registrácia zverejnená v ./pub/media/catalog/product/ mediálny súbor (proces umiestňovania samotného súboru nie je v tomto článku diskutovaný):
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;
}Po registrácii sa novému mediálnemu súboru pridelí identifikátor.
Catalog_product_entity_media_gallery_value
Registrovaný mediálny súbor spájame s príslušným produktom pre predvolený výklad:
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);
}Catalog_product_entity_media_gallery_value_to_entity
Registrovaný mediálny súbor spájame s príslušným produktom bez toho, aby bol viazaný na akýkoľvek výklad. Nie je jasné, kde presne sa tieto údaje používajú a prečo nie je možné získať prístup k údajom z predchádzajúcej tabuľky, ale táto tabuľka existuje a údaje sa do nej zapíšu, keď sa k produktu pridá obrázok. Takže to je všetko.
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
Mediálny súbor možno použiť s rôznymi rolami (zodpovedajúci kód atribútu je uvedený v zátvorkách):
- základňa(
image) - Malý obrázok (
small_image) - miniatúra (
thumbnail) - Obrázok vzorky (
swatch_image)
Prepojenie rolí s mediálnym súborom je presne to, čo sa deje v catalog_product_entity_varchar. Kód väzby je podobný kódu v "Základné vlastnosti produktu".
Po pridaní obrázka k produktu na paneli administrátora to vyzerá takto:

Категории
Hlavné tabuľky obsahujúce údaje podľa kategórie:
catalog_category_entity: register kategórií;catalog_category_product: prepojenie medzi produktmi a kategóriami;catalog_category_entity_*: hodnoty atribútov EAV;
Spočiatku v prázdnom Magento- register kategórií aplikácie obsahuje 2 kategórie (názvy stĺpcov som skrátil): 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|Kategória s id=1 je koreňom všetkého Magento-catalog a nie je dostupný ani v administračnom paneli, ani v rozhraní front-end. Kategória s id=2 (predvolené kategórie) je koreňová kategória pre hlavný obchod hlavnej stránky (Hlavná stránka obchodu) vytvorený pri nasadení aplikácie (pozri. Správca / Obchody / Všetky obchody). Navyše, koreňová kategória samotného obchodu tiež nie je k dispozícii na prednej strane, iba jej podkategórie.
Keďže témou tohto článku je stále import údajov o produktoch, pri vytváraní kategórií nebudem používať priamy vstup do databázy, ale použijem triedy, ktoré poskytuje Magento (modely a repozitáre). Priamy zápis do databázy sa používa iba na priradenie importovaného produktu ku kategórii (priradenie kategórie sa vykonáva podľa jej názvu a ID kategórie sa načíta počas priradenia):
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);
}Po pridaní odkazu na produkt do kategórií „Kategória 1“ a „Kategória 2“ vyzerajú podrobnosti o produkte v administračnom paneli približne takto:

Ďalšie akcie
Po dokončení importu údajov musíte vykonať nasledujúce dodatočné kroky:
- indexovanie údajov: volanie v konzole
./bin/magento indexer:reindex; - regenerácia URL pre produkty/kategórie: môžete použiť rozšírenie “«
Produkty na paneli správcu po vykonaní ďalších akcií:

a vpredu:

Zhrnutie
Rovnaká sada produktov (10 položiek) ako v predchádzajúcom článku sa importuje minimálne o rád rýchlejšie (1 sekunda oproti 10). Presnejší odhad rýchlosti by si vyžadoval väčší počet produktov – stovky, alebo ešte lepšie, tisíce. Napriek tomu, aj pri takej malej veľkosti vstupných údajov, možno dospieť k záveru, že pomocou poskytnutých nástrojov Magento (modely a repozitáre), významne (zdôrazňujem - veľa!) urýchliť vývoj požadovanej funkcionality, no zároveň výrazne (zdôrazňujem - veľa!) znížiť rýchlosť, akou sa údaje dostávajú do databázy.
V dôsledku toho sa voda ukázala ako mokrá a to nie je zjavenie. Teraz však mám kód, s ktorým sa môžem pohrať a možno dospieť k zaujímavejším záverom.
Zdroj: hab.com
