Magento 2: termékek importálása közvetlenül az adatbázisba

A előző cikkben 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 adatok importálásához , 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.

Magento 2: termékek importálása közvetlenül az adatbázisba

A két cikk megírásának eredményeként létrejött kódot meg lehet tekinteni a Magento modulban „flancer32/mage2_ext_demo_import“. Í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_id
  • sku

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).

Magento 2: termékek importálása közvetlenül az adatbázisba

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

Magento 2: termékek importálása közvetlenül az adatbázisba

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: EAV-attribútumok. Íme az alapvető termékattribútumok listája, amelyek szükségesek ahhoz, hogy a termék megfelelően megjelenjen a fronton:

  • name
  • price
  • leírás
  • short_description
  • status
  • tax_class_id
  • url_key
  • visibility

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:

Magento 2: termékek importálása közvetlenül az adatbázisba

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_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,
        /* 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 "Raktárkezelési rendszer CQRS és Event Sourcing alkalmazásával. Tervezés«.

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:

Magento 2: termékek importálása közvetlenül az adatbázisba

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.

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.

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

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:

Magento 2: termékek importálása közvetlenül az adatbázisba

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:

Magento 2: termékek importálása közvetlenül az adatbázisba

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 "elgentos/regenerate-catalog-urls«

" bővítmény használható

Magento 2: termékek importálása közvetlenül az adatbázisba

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:

Magento 2: termékek importálása közvetlenül az adatbázisba

Ö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

Megbízható hosting vásárlása weboldalak számára, DDoS védelemmel, VPS VDS szerverek. 🔥 Megbízható webtárhely vásárlása DDoS védelemmel, VPS VDS szerverek | ProHoster