Magento 2: importació de productes directament a la base de dades
В article anterior Vaig descriure el procés d'importació de productes a Magento 2 de la manera habitual: mitjançant models i repositoris. El mètode habitual té una velocitat de processament de dades molt baixa. El meu ordinador portàtil produïa aproximadament un producte per segon. En aquesta continuació, considero una forma alternativa d'importar un producte: mitjançant l'entrada directa a la base de dades, obviant els mecanismes estàndard de Magento 2 (models, fàbriques, dipòsits). La seqüència de passos per importar productes es pot adaptar a qualsevol llenguatge de programació que pugui funcionar amb MySQL.
renúncia: Magento té una funcionalitat preparada per a importació de dades i, molt probablement, et serà suficient. Tanmateix, si necessiteu un control més complet sobre el procés d'importació, sense limitar-vos a preparar un fitxer CSV per al que teniu, benvingut a cat.
El codi resultant d'escriure ambdós articles es pot veure al mòdul Magento "flancer32/mage2_ext_demo_import". Aquí hi ha algunes restriccions que vaig seguir per simplificar el codi del mòdul de demostració:
Els productes només es creen, no s'actualitzen.
Un magatzem
Només s'importen els noms de categories, sense la seva estructura
Les estructures de dades compleixen la versió 2.3
JSON per importar un sol producte:
{
"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"
}
Visió general de les principals etapes d'importació
registre del propi producte
connexió entre el producte i el lloc web
Atributs bàsics del producte (EAV)
dades d'inventari (quantitat de producte en estoc)
mitjans de comunicació (fotos)
connexió amb categories de catàleg
Registre del producte
La informació bàsica del producte es pot trobar 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`)
)
La informació mínima necessària per crear una entrada al registre del producte és:
attribute_set_id
sku
addicionals:
type_id — si no ho especifiquem, s'utilitzarà "simple".
Per escriure directament a la base de dades, faig servir l'adaptador de base de dades del mateix Magento:
El producte recentment registrat encara no té un nom ni una descripció. Tot això es fa a través Atributs EAV. Aquí hi ha una llista dels atributs bàsics del producte que es necessiten perquè el producte es mostri correctament a la part frontal:
name
price
description
short_description
status
tax_class_id
url_key
visibility
S'afegeix un atribut independent a un producte com aquest (s'ometen els detalls per obtenir l'identificador i el tipus d'atribut del seu codi):
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);
}
}
Utilitzant el codi d'atribut, determinem el seu identificador i el tipus de dades (datetime, decimal, int, text, varchar), després escriviu les dades de la finestra administrativa a la taula adequada (store_id = 0).
Després d'afegir els atributs anteriors al producte, obtindreu aquesta imatge al tauler d'administració:
Dades d'inventari
A partir de la versió 2.3 de Magento, hi ha dos conjunts paral·lels de taules que proporcionen emmagatzematge d'informació d'inventari (quantitat de producte):
cataloginventory_*: estructura antiga;
inventory_*: nova estructura (MSI - Multi Source Inventory);
Heu d'afegir dades d'inventari a ambdues estructures, perquè la nova estructura encara no és completament independent de l'antiga (és molt probable que per default magatzem a la nova estructura està implicada una taula cataloginventory_stock_status en qualitat inventory_stock_1).
cataloginventory_
En desplegar Magneto 2.3 inicialment tenim 2 entrades store_website, que correspon a dos llocs: administratiu i client principal:
És a dir, a la nostra antiga estructura només hi ha un "magatzem" (stock) i està enllaçat al web administratiu. Afegint-ne de nous a través del tauler d'administració sources/stocks a MSI (nova estructura) no dóna lloc a noves entrades a cataloginventory_stock.
Les dades d'inventari dels productes de l'estructura antiga es registren inicialment en taules:
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);
}
inventari_
Inicialment, la nova estructura per emmagatzemar dades d'inventari conté 1 "font'(inventory_source):
«Font» representa l'emmagatzematge físic dels productes (el registre conté les coordenades físiques i l'adreça postal). "Magatzem"és una unió lògica de diverses "fonts" (inventory_source_stock_link)
al nivell en què es produeix la connexió amb el canal de venda (inventory_stock_sales_channel)
type |code|stock_id|
-------|----|--------|
website|base| 1|
A jutjar per l'estructura de dades, s'assumeixen diversos tipus de canals de venda, però per defecte només la connexió "valors"-""(l'enllaç al lloc web segueix el codi del lloc web - base).
Un"magatzem"pot estar vinculat a diversos"fonts"i un"font"-a diversos"magatzems"(relació de molts a molts). Les excepcions són per defecte "font"I"magatzem". No es tornen a enllaçar amb altres entitats (limitació a nivell de codi - l'error "No es pot desar l'enllaç relacionat amb la font predeterminada o l'estoc predeterminat"). Es poden trobar més detalls sobre l'estructura MSI de Magento 2 a l'article "Sistema de gestió de magatzems mitjançant CQRS i Event Sourcing. Disseny".
Faré servir la configuració predeterminada i afegiré tota la informació de l'inventari a la font default, que participa en el canal de venda associat al lloc web amb el codi base (correspon a la part davantera de la botiga - vegeu store_website):
Després d'afegir dades d'inventari al producte al tauler d'administració, obtindreu aquesta imatge:
Mitjans de comunicació
Quan s'afegeix "manualment" una imatge a un producte a través del tauler d'administració, la informació rellevant s'anota a les taules següents:
catalog_product_entity_media_gallery: registre de mitjans (imatges i fitxers de vídeo);
catalog_product_entity_media_gallery_value: enllaçar mitjans amb productes i aparadors (localització);
catalog_product_entity_media_gallery_value_to_entity: enllaçar contingut multimèdia només amb productes (presumiblement contingut multimèdia predeterminat per al producte);
catalog_product_entity_varchar: aquí s'emmagatzemen els rols en què s'utilitza la imatge;
i les imatges es guarden al directori ./pub/media/catalog/product/x/y/On x и y — la primera i la segona lletra del nom del fitxer d'imatge. Per exemple, fitxer image.png s'ha de guardar com a ./pub/media/catalog/product/i/m/image.png, perquè la plataforma la pugui utilitzar com a imatge a l'hora de descriure productes del catàleg.
catalog_product_entity_media_gallery
Registre publicat a ./pub/media/catalog/product/ fitxer multimèdia (el procés de col·locar el fitxer en si no es tracta en aquest article):
Associem el fitxer multimèdia registrat amb el producte corresponent sense estar lligats a cap aparador. No està clar on s'utilitzen exactament aquestes dades i per què és impossible accedir a les dades de la taula anterior, però aquesta taula existeix i les dades s'escriuen quan s'afegeix una imatge al producte. Així que això és tot.
Un fitxer multimèdia es pot utilitzar amb diferents rols (el codi d'atribut corresponent s'indica entre parèntesis):
Base (image)
Imatge petita (small_image)
Miniatura (thumbnail)
Imatge de mostra (swatch_image)
Enllaçar rols a un fitxer multimèdia és exactament el que passa a catalog_product_entity_varchar. El codi d'enllaç és similar al codi del "Atributs bàsics del producte".
Després d'afegir una imatge al producte al tauler d'administració, té aquest aspecte:
Категории
Taules principals que contenen dades per categories:
catalog_category_entity: registre de categories;
catalog_category_product: connexió entre productes i categories;
catalog_category_entity_*: valors d'atribut EAV;
Inicialment, en una aplicació Magento buida, el registre de categories conté 2 categories (he escurçat els noms de les columnes: crt - created_at, upd - updated_at):
La categoria amb id=1 és l'arrel de tot el catàleg de Magento i no està disponible ni al tauler d'administració ni a la pàgina principal. Categoria amb id=2 (Categoria per defecte) és la categoria arrel de la botiga principal del lloc principal (Botiga web principal) creat quan es desplega l'aplicació (vegeu. Administrador / Botigues / Totes les botigues). A més, la categoria arrel de la botiga en si no està disponible a la part davantera, només les seves subcategories.
Com que el tema d'aquest article encara és la importació de dades de productes, no utilitzaré l'entrada directa a la base de dades en crear categories, sinó que faré servir les classes proporcionades pel mateix Magento (models i repositoris). L'entrada directa a la base de dades només s'utilitza per associar el producte importat amb una categoria (la categoria coincideix amb el seu nom i l'identificador de la categoria es recupera durant la concordança):
Després d'afegir un enllaç de producte a les categories "Categoria 1" i "Categoria 2", els detalls del producte al tauler d'administració tenen un aspecte semblant a això:
Accions addicionals
Un cop finalitzada la importació de dades, heu de completar els passos addicionals següents:
indexació de dades: trucada a la consola ./bin/magento indexer:reindex;
Productes al tauler d'administració després de realitzar accions addicionals:
i al davant:
Resum
El mateix conjunt de productes (10 peces) que a l'article anterior s'importa almenys un ordre de magnitud més ràpid (1 segon enfront de 10). Per estimar amb més precisió la velocitat, necessiteu un nombre més gran de productes: diversos centenars, o millor encara milers. No obstant això, fins i tot amb una mida tan petita de dades d'entrada, podem concloure que l'ús de les eines proporcionades per Magento (models i repositoris) és important (subratllo: molt!) accelerar el desenvolupament de la funcionalitat requerida, però al mateix temps significativament (subratllo: molt!) reduir la velocitat a la qual les dades entren a la base de dades.
Com a resultat, l'aigua va resultar humida i això no és una revelació. Tanmateix, ara tinc el codi per jugar i potser arribar a algunes conclusions més interessants.