A A termékek importálási folyamatát a Magento 2-ben a szokásos módon írtam le — modellek és tárolók segítségével. A szokásos módszer meglehetősen lassú adatok feldolgozására. A laptopomon körülbelül egy termék másodpercenként került feldolgozásra. Ebben a folytatásban egy alternatív termékimportálási módszert vizsgálok — közvetlen adatbázis-írással, megkerülve a Magento 2 szabványos mechanizmusait (modellek, gyárak, tárolók). Azok a lépések, amelyek biztosítják a termékek importálását, bármilyen programozási nyelvre adaptálhatók, amely képes MySQL-lal dolgozni.
Megjegyzés: A Magento rendelkezik beépített funkcióval az , ami valószínűleg elegendő lesz az Ön számára. Azonban, ha nagyobb ellenőrzésre van szüksége az importálási folyamat felett, amely nem korlátozódik a CSV-fájl előkészítésére, üdvözöljük a cikk alatt.

A két cikk megírásának eredményeként létrejött kódot meg lehet tekinteni a Magento modulban „“. Íme néhány korlátozás, amelyet figyelembe vettem a demo modul kódjának egyszerűsítése érdekében:
- A termékek csak létrejönnek, nem frissülnek.
- Egy raktár
- Csak a kategóriák nevei importálódnak, anélkül, hogy a struktúrájuk is szerepelne
- Az adatszerkezetek a 2.3-as verziónak megfelelően készültek
JSON a külön termék importálásához:
{
"sku": "MVA20D-UBV-3",
"name": "Záródugó a plombáláshoz VÁ47-29 IEK",
"desc": "Hozzáférés biztosítása a készülékekhez ...",
"desc_short": "A VÁ47-29 IEK plombálásához készült záródugó ...",
"price": 5.00,
"qty": 25,
"categories": ["Kategória 1", "Kategória 2"],
"image_path": "mva20d_ubv_3.png"
}Az importálás fő lépéseinek áttekintése
- a termék bejegyzésének regisztrálása
- a termék és a weboldal kapcsolata
- a termék alapvető attribútumai (EAV)
- készletadatok (a termék mennyisége a raktárban)
- média (képek)
- kapcsolat a katalógus kategóriáival
A termék regisztrálása
A termék alapvető információja a 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`)
)A minimálisan szükséges információ a termékregisztrációs bejegyzés létrehozásához:
attribute_set_idsku
további:
type_id— ha nem adjuk meg, akkor ‘simple’ használható
Közvetlen bejegyzéshez a Magento saját DB-adapterét használom:
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;
}A termék regisztrálása után a catalog_product_entity láthatóvá válik az admin felületen, a termékek rácsában (Catalog / Products).

A termék és a weboldal kapcsolata
A termék weboldallal való kapcsolata határozza meg, mely boltokban és milyen bemutatókon érhető el a termék a fronton.
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);
}
Alapvető termék attribútumok
A frissen regisztrált terméknek még nincs neve és leírása. Mindez a következőn keresztül történik: . Íme az alapvető termékattribútumok listája, amelyek szükségesek ahhoz, hogy a termék megfelelően megjelenjen a fronton:
namepriceleírásshort_descriptionstatustax_class_idurl_keyvisibility
Egy külön attribútumot így adhatunk hozzá a termékhez (kihagyva az azonosító és attribútumtípus lekérésének részleteit a kód alapján):
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,
\/** minden attribútumot az alapértelmezett bolt nézethez id=0 (admin) *\/
'store_id' => 0,
'value' => $attrValue
];
$conn->insert($table, $bind);
}
}Az attribútum kódja alapján meghatározzuk az id-ját és az adatok típusát (datetime, decimal, egész, szöveg, varchar), majd a megfelelő táblába írjuk be az adatokat az admin bemutatóhoz (store_id = 0).
A fenti attribútumok hozzáadása után a következő kép jelenik meg az admin felületen:

Készletadatok
A Magento 2.3 verziótól kezdődően párhuzamosan két adatbázistábla áll rendelkezésre, amelyek az inventárium információinak tárolását biztosítják (termékmennyiség):
cataloginventory_*: régi struktúra;inventory_*: új struktúra (MSI — Több Forrású Készlet);
Az inventáriumi adatokat mindkét struktúrába be kell adni, mivel az új struktúra még nem teljesen független a régitől (úgy tűnik, hogy a alapértelmezett új struktúrában a raktárhoz a következő tábla van hozzárendelve: cataloginventory_stock_status mint inventory_stock_1).
cataloginventory_
A Magneto 2.3 telepítésekor kezdetben 2 bejegyzés található a store_website, ami megfelel két webhelynek — az adminisztratívnak és a fő ügyfélwebhelynek:
website_id|code |name |sort_order|default_group_id|is_default|
----------|-----|------------|----------|----------------|----------|
0|admin|Admin | 0| 0| 0|
1|base |Fő Weboldal| 0| 1| 1|A táblában cataloginventory_stock csak egy bejegyzés található:
stock_id|website_id|stock_name|
--------|----------|----------|
1| 0|Alapértelmezett|Tehát a régi struktúrában csak egy «raktár» van (stock) és ez az adminisztratív webhelyhez van csatolva. Új raktárak adminisztrációs felületen keresztüli hozzáadása a sources/names_to MSI-be (új struktúra) nem vezet új bejegyzések megjelenéséhez. cataloginventory_stock.
A régi struktúrában található termékek inventáriumi adatainak kezdetben a következő táblákban kell szerepelniük:
cataloginventory_stock_itemcataloginventory_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,
/* default 'cataloginventory' struktúrában egyetlen raktárat használunk */
'stock_id' => 1,
'qty' => $qty,
'is_qty_decimal' => $isQtyDecimal,
'is_in_stock' => $isInStock,
/* az alapértelmezett raktár az admin webhelyhez van kötve (lásd `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,
/* alapértelmezett 'cataloginventory' struktúrában egyetlen raktárat használunk */
'stock_id' => 1,
'qty' => $qty,
'stock_status' => MagentoCatalogInventoryApiDataStockStatusInterface::STATUS_IN_STOCK,
/* az alapértelmezett raktár az admin webhelyhez van kötve (lásd `cataloginventory_stock`) */
'website_id' => 0
];
$conn->insert($table, $bind);
}inventory_
Az új struktúra kezdetben 1 «forrás» (inventory_source):
source_code|name |enabled|description |latitude|longitude|country_id|...|
-----------|--------------|-------|--------------|--------|---------|----------|...|
default |Alapértelmezett forrás| 1|Alapértelmezett forrás|0.000000| 0.000000|US |...|és egy "raktár» (inventory_stock):
stock_id|name |
--------|-------------|
1|Alapértelmezett készlet|«Forrás" egy fizikai tároló a termékekhez (a rekord fizikai koordinátákat és postai címet tartalmaz). "Raktár" logikai összefogása több "forrásnak" (inventory_source_stock_link)
link_id|stock_id|source_code|priority|
-------|--------|-----------|--------|
1| 1|default | 1|azon a szinten, ahol a kapcsolódás történik az értékesítési csatornához (inventory_stock_sales_channel)
type |code|stock_id|
-------|----|--------|
website|base| 1|A struktúra alapján különböző típusú értékesítési csatornák feltételezhetők, de alapértelmezés szerint csak a "stock«-«website" (a weboldal hivatkozása a weboldal kódján keresztül — base).
Egy "raktár" több "forráshoz", és egy "forrás" -hez több "raktár" (több-több viszony). Kivételt képeznek az alapértelmezett "forrásés a "raktár". Ezek nem köthetők más entitásokhoz (kód szintű korlátozás — hibaüzenet: "Can not save link related to Default Source or Default Stock"). A Magento 2 MSI struktúrájáról részletesebben az "«.
Az alapértelmezett konfigurációt fogom használni, és minden készletinformációt hozzáadok a forráshoz, alapértelmezett, amely az értékesítési csatornában van, amely a weboldalhoz kapcsolódik, kódja: base (a bolt ügyféloldalához tartozik — lásd. 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);
}Miután a készletadatokat hozzáadtuk a termékhez az admin felületen, ilyen kép alakul ki:

Média
A termékhez történő "kézi" kép hozzáadásakor az adminisztrációs felületen a megfelelő információk a következő táblákba kerülnek:
catalog_product_entity_media_gallery: média-nyilvántartás (képek és videófájlok);catalog_product_entity_media_gallery_value: média hozzárendelés a termékekhez és vitrinhez (lokalizáció);catalog_product_entity_media_gallery_value_to_entity: média hozzárendelés csak a termékekhez (feltehetőleg az alapértelmezett média tartalom a termékhez);catalog_product_entity_varchar: itt tárolják a szerepeket, amelyekben a kép használatban van;
a képek pedig a következő könyvtárba kerülnek .\/pub\/media\/catalog\/product\/x\/y\/, ahol x és y — a fájlnevének első két betűje. Például a fájl image.png el kell menteni mint ./pub/media/catalog/product/i/m/image.png, hogy a platform felhasználhassa azt képként a katalógusból származó termékek leírása során.
catalog_product_entity_media_gallery
A: .\/pub\/media\/catalog\/product\/ media fájl (a fájl elhelyezésének folyamata ebben a cikkben nem tárgyalt):
function createMediaGallery($imgPathPrefixed)
{
$attrId =
/* az attribútum azonosító lekérdezése az 'media_gallery' attribútumkód alapján */
/** @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' vagy 'video' */
'media_type' => 'image',
'disabled' => false
];
$conn->insert($table, $bind);
$result = $conn->lastInsertId($table);
return $result;
}Új médiafájl regisztrálásakor azonosítót kap.
catalog_product_entity_media_gallery_value
Kapcsoljuk a regisztrált médiafájlt a megfelelő termékhez az alapértelmezett bolt számára:
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,
/* alapértelmezésként admin bolt nézet használata */
'store_id' => 0,
'entity_id' => $prodId,
'label' => null,
/* csak egy képet tartunk */
'position' => 1,
'disabled' => false
];
$conn->insert($table, $bind);
}catalog_product_entity_media_gallery_value_to_entity
Kapcsoljuk a regisztrált médiafájlt a megfelelő termékhez anélkül, hogy bármilyen bolthoz kapcsolnánk. Nem világos, hogy ezek az adatok pontosan hol használatosak, és miért nem lehet hivatkozni a korábbi tábla adataira, de ez a táblázat létezik és az adatok ide kerülnek az kép termékhez való hozzáadásakor. Tehát így működik.
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
A médiafájl különböző szerepekkel használható (a megfelelő attribútumkód zárójelben van):
- Base (
kép) - Small Image (
small_image) - Thumbnail (
thumbnail) - Swatch Image (
swatch_image)
A szerepek összekapcsolása a médiafájllal itt történik catalog_product_entity_varchar. Az összekapcsolás kódja hasonló ahhoz a kódhoz, amely a 'Alapvető termék attribútumok«.
A termékhez a adminisztrációs felületen kép hozzáadása után így néz ki:

Kategóriák
A fő táblák, amelyek a kategóriák adatait tartalmazzák:
catalog_category_entity: a kategóriák regisztere;catalog_category_product: a termékek és kategóriák kapcsolata;catalog_category_entity_*: az EAV-attribútumok értékei;
Kezdetben, egy üres Magento alkalmazásban a kategóriák regiszterében 2 kategória található (a oszlopneveket lerövidítettem: crt — ASOF JOIN, 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|Az id=1 kategória a teljes Magento katalógus gyökere, és nem elérhető sem az adminisztrációs felületen, sem a front-end-en. Az id=2 kategória (Default Category) a főbolt fő webhelyének gyökérkategóriája (Main Website Store), amely a alkalmazás telepítésekor jön létre (lásd: Admin / Stores / All Stores). Ráadásul a bolt gyökérkategóriája a front-end-en szintén nem elérhető, csak a al-kategóriái.
Mivel a cikk témája végül is az adatok termékekhez való importálása, ezért nem fogok közvetlen írást használni az adatbázisba a kategóriák létrehozásakor, hanem a Magento által biztosított osztályokat fogom használni (modellek és adattárak). A közvetlen írás az adatbázisba csak az importált termék és a kategória összekapcsolására használható (a kategória azonosítása a neve alapján történik, a társítás során a kategória azonosítója kerül lekérdezésre):
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);
}Miután a termékek és kategóriák összekapcsolása megtörtént a "Kategória 1" és "Kategória 2" esetében, a termék részletei az adminisztrációs felületen körülbelül így néznek ki:

További lépések
Az adatok importálása után a következő további lépéseket kell végrehajtani:
- az adatok indexelése: konzolban hívás
./bin/magento indexer:reindex; - URL-ek regenerálása a termékek/kategóriák számára: a "«
" bővítmény használható

A termékek az adminisztrációs felületen a további lépések végrehajtása után: és a front-end-en:

Összefoglaló
Ugyanaz a termékkészlet (10 darab), mint a korábbi cikkben, legalábbis tízszer gyorsabban importálódik (1 másodperc a 10-hez képest). A sebesség pontosabb értékeléséhez több termékre van szükség — több százra, de inkább ezerre. Mindazonáltal még egy ilyen kicsi bemeneti adathalmaz esetén is levonható a következtetés, hogy a Magento által biztosított eszközkészlet (modellek és tárolók) jelentősen (hangsúlyozom — jelentősen!) felgyorsítja a szükséges funkciók fejlesztését, de ezzel jelentősen (hangsúlyozom — jelentősen!) csökkenti az adatok beérkezési sebességét az adatbázisba.
Ennek eredményeként kiderült, hogy a víz nedves, és ez nem meglepetés. Mindazonáltal most van egy kód, amivel tovább játszadozhatok, és talán érdekesebb következtetéseket vonhatok le.
Forrás: habr.com
