В předchozí článek Proces importu produktů do Magento 2 jsem popsal běžným způsobem – přes modely a repozitáře. Obvyklá metoda má velmi nízkou rychlost zpracování dat. Můj notebook produkoval asi jeden produkt za sekundu. V tomto pokračování zvažuji alternativní způsob importu produktu – přímým vstupem do databáze, obcházení standardních mechanismů Magento 2 (modely, továrny, úložiště). Posloupnost kroků k importu produktů lze přizpůsobit jakémukoli programovacímu jazyku, který umí pracovat s MySQL.
Odmítnutí odpovědnosti: Magento má připravené funkce pro import dat a s největší pravděpodobností vám to bude stačit. Pokud však potřebujete úplnější kontrolu nad procesem importu, neomezující se na přípravu souboru CSV pro to, co máte, vítejte na cat.
Kód vzniklý napsáním obou článků si můžete prohlédnout v modulu Magento "flancer32/mage2_ext_demo_import". Zde jsou některá omezení, kterými jsem se řídil, abych zjednodušil kód demo modulu:
Produkty jsou pouze vytvářeny, nikoli aktualizovány.
Jeden sklad
Importují se pouze názvy kategorií bez jejich struktury
Datové struktury odpovídají verzi 2.3
JSON pro import jednoho 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"
}
Přehled hlavních fází importu
registraci samotného produktu
propojení mezi produktem a webem
základní atributy produktu (EAV)
skladové údaje (množství produktu na skladě)
média (obrázky)
propojení s katalogovými kategoriemi
Registrace výrobku
Základní informace o produktu naleznete 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ální informace potřebné k vytvoření záznamu v registru produktů jsou:
attribute_set_id
sku
další:
type_id — pokud jej neuvedeme, použije se „jednoduchý“.
Pro přímý zápis do databáze používám DB adaptér samotného Magenta:
Nově registrovaný produkt ještě nemá název ani popis. To vše se provádí prostřednictvím EAV atributy. Zde je seznam základních atributů produktu, které jsou potřeba pro správné zobrazení produktu na přední straně:
name
price
description
short_description
status
tax_class_id
url_key
visibility
K produktu, jako je tento, je přidán samostatný atribut (podrobnosti o získání identifikátoru a typu atributu z jeho kódu jsou vynechány):
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);
}
}
Pomocí kódu atributu určíme jeho id a datový typ (datetime, decimal, int, text, varchar), poté zapište data pro administrativní okno do příslušné tabulky (store_id = 0).
Po přidání výše uvedených atributů k produktu získáte tento obrázek v admin panelu:
Údaje o zásobách
Počínaje verzí 2.3 v Magento existují dvě paralelní sady tabulek, které poskytují ukládání informací o zásobách (množství produktu):
cataloginventory_*: stará struktura;
inventory_*: nová struktura (MSI - Multi Source Inventory);
Do obou struktur musíte přidat inventární data, protože nová struktura ještě není zcela nezávislá na staré (je velmi pravděpodobné, že pro default sklad v nové struktuře je zahrnuta tabulka cataloginventory_stock_status jak inventory_stock_1).
katalogový inventář_
Při nasazení Magneta 2.3 máme zpočátku 2 položky store_website, což odpovídá dvěma webům – administrativnímu a hlavnímu klientovi:
To znamená, že v naší staré struktuře je pouze jeden „sklad“ (stock) a je propojen s administrativním webem. Přidávání nových prostřednictvím panelu administrátora sources/stocks v MSI (nová struktura) nevede k novým záznamům v cataloginventory_stock.
Údaje o zásobách o produktech ve staré struktuře jsou zpočátku zaznamenány v tabulkách:
cataloginventory_stock_item
cataloginventory_stock_status
katalogová_skladová_položka
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);
}
katalogový_stav_skladů
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ář_
Zpočátku nová struktura pro ukládání dat zásob obsahuje 1 "zdroj"(inventory_source):
«Zdroj» představuje fyzické úložiště pro produkty (záznam obsahuje fyzické souřadnice a poštovní adresu). "sklad"je logické spojení několika "zdrojů" (inventory_source_stock_link)
na úrovni, na které dochází k připojení k prodejnímu kanálu (inventory_stock_sales_channel)
type |code|stock_id|
-------|----|--------|
website|base| 1|
Soudě podle struktury dat se předpokládají různé typy prodejních kanálů, ale standardně pouze spojení „stock„-“webových stránkách "(odkaz na webovou stránku následuje za kódem webu - base).
Jeden "sklad"lze propojit s několika"ke zdrojům"a jeden"zdroj"- na několik"sklady"(vztah mnoho k mnoha). Výjimky jsou výchozí "zdroj"A"sklad". Nejsou znovu propojeny s jinými entitami (omezení na úrovni kódu – chyba “Nelze uložit odkaz související s výchozím zdrojem nebo výchozím skladem"). Více podrobností o struktuře MSI v Magento 2 naleznete v článku “Systém řízení skladu využívající CQRS a Event Sourcing. Design".
Použiji výchozí konfiguraci a do zdroje přidám všechny informace o inventáři default, která je zapojena do prodejního kanálu spojeného s webovou stránkou s kódem base (odpovídá přední části prodejny - viz store_website):
Po přidání inventárních dat k produktu na panelu administrátora získáte tento obrázek:
média
Při „ručním“ přidávání obrázku k produktu prostřednictvím panelu administrátora jsou příslušné informace zapsány do následujících tabulek:
catalog_product_entity_media_gallery: registr médií (obrázky a video soubory);
catalog_product_entity_media_gallery_value: propojení médií s produkty a vitrínami (lokalizace);
catalog_product_entity_media_gallery_value_to_entity: propojení médií pouze s produkty (pravděpodobně výchozí mediální obsah pro produkt);
catalog_product_entity_varchar: Zde jsou uloženy role, ve kterých je obrázek použit;
a samotné obrázky se uloží do adresáře ./pub/media/catalog/product/x/y/Kde x и y — první a druhé písmeno názvu souboru obrázku. Například soubor image.png by měl být uložen jako ./pub/media/catalog/product/i/m/image.png, aby jej platforma mohla použít jako obrázek při popisu produktů z katalogu.
katalog_produkt_entity_media_galerie
Registrace zveřejněna v ./pub/media/catalog/product/ mediální soubor (proces umístění samotného souboru není v tomto článku popsán):
Registrovaný mediální soubor spojujeme s odpovídajícím produktem, aniž bychom byli vázáni na jakoukoli výlohu. Není jasné, kde přesně jsou tato data použita a proč není možné získat přístup k datům z předchozí tabulky, ale tato tabulka existuje a data se do ní zapisují, když je k produktu přidán obrázek. Tak to je vše.
Mediální soubor lze použít s různými rolemi (odpovídající kód atributu je uveden v závorce):
Základna (image)
Malý obrázek (small_image)
Miniatura (thumbnail)
Vzorek obrázku (swatch_image)
Propojení rolí s mediálním souborem je přesně to, co se děje v catalog_product_entity_varchar. Závazný kód je podobný kódu v "Základní vlastnosti produktu".
Po přidání obrázku k produktu v panelu administrátora to vypadá takto:
kategorie
Hlavní tabulky obsahující data podle kategorií:
catalog_category_entity: rejstřík kategorií;
catalog_category_product: spojení mezi produkty a kategoriemi;
catalog_category_entity_*: hodnoty atributů EAV;
Zpočátku v prázdné aplikaci Magento obsahuje registr kategorií 2 kategorie (zkrátil jsem názvy sloupců: crt - created_at, upd - updated_at):
Kategorie s id=1 je kořenem celého katalogu Magento a není dostupná ani v admin panelu, ani na titulní stránce. Kategorie s id=2 (Výchozí kategorie) je kořenová kategorie pro hlavní obchod hlavního webu (Hlavní webový obchod) vytvořené při nasazení aplikace (viz. Správce / Obchody / Všechny obchody). Navíc kořenová kategorie samotného obchodu také není k dispozici na přední straně, pouze její podkategorie.
Vzhledem k tomu, že tématem tohoto článku je stále import dat o produktech, nepoužiji při vytváření kategorií přímý vstup do databáze, ale použiji třídy, které poskytuje samotné Magento (modely a repozitáře). Přímý vstup do databáze se používá pouze k přidružení importovaného produktu ke kategorii (kategorie se shoduje s jejím názvem a ID kategorie se získá při porovnávání):
Produkty na panelu administrátora po provedení dalších akcí:
a vepředu:
Shrnutí
Stejná sada produktů (10 kusů) jako v předchozím článku se dováží minimálně o řád rychleji (1 sekunda versus 10). K přesnějšímu odhadu rychlosti potřebujete větší počet produktů – několik stovek, nebo ještě lépe tisíců. I při tak malé velikosti vstupních dat však můžeme usoudit, že využití nástrojů poskytovaných Magentem (modely a repozitáře) je významné (zdůrazňuji - hodně!) urychlit vývoj požadované funkcionality, ale zároveň výrazně (zdůrazňuji - hodně!) snížit rychlost, kterou se data dostávají do databáze.
V důsledku toho se ukázalo, že voda byla mokrá a není to žádné zjevení. Nyní však mám kód, se kterým si mohu pohrát a možná dospět k zajímavějším závěrům.