Magento 2: importa produtos directamente na base de datos
В artigo anterior Describín o proceso de importación de produtos a Magento 2 do xeito habitual: a través de modelos e repositorios. O método habitual ten unha velocidade de procesamento de datos moi baixa. O meu portátil producía aproximadamente un produto por segundo. Nesta continuación, considero unha forma alternativa de importar un produto: mediante a entrada directa na base de datos, evitando os mecanismos estándar de Magento 2 (modelos, fábricas, repositorios). A secuencia de pasos para importar produtos pódese adaptar a calquera linguaxe de programación que poida funcionar con MySQL.
retratação: Magento ten unha funcionalidade preparada para importación de datos e, moi probablemente, será suficiente para ti. Non obstante, se necesitas un control máis completo sobre o proceso de importación, sen limitarse a preparar un ficheiro CSV para o que tes, benvido a cat.
O código resultante de escribir ambos artigos pódese ver no módulo de Magento "flancer32/mage2_ext_demo_import". Aquí tes algunhas restricións que seguín para simplificar o código do módulo de demostración:
Os produtos só se crean, non se actualizan.
Un almacén
Só se importan os nomes de categoría, sen a súa estrutura
As estruturas de datos cumpren coa versión 2.3
JSON para importar un único produto:
{
"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ón xeral das principais etapas da importación
rexistro do propio produto
conexión entre o produto e o sitio web
Atributos básicos do produto (EAV)
datos de inventario (cantidade de produto en stock)
medios (fotos)
conexión con categorías de catálogo
Rexistro do produto
A información básica do produto pódese atopar en 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 información mínima necesaria para crear unha entrada no rexistro de produtos é:
attribute_set_id
sku
adicional:
type_id — se non o especificamos, empregarase "simple".
Para escribir directamente na base de datos, uso o adaptador de base de datos de Magento:
O produto recentemente rexistrado aínda non ten un nome nin descrición. Todo isto faise a través Atributos EAV. Aquí tes unha lista de atributos básicos do produto que son necesarios para que o produto se mostre correctamente na parte frontal:
name
price
description
short_description
status
tax_class_id
url_key
visibility
Engádese un atributo separado a un produto coma este (omítense os detalles para obter o identificador e o tipo do atributo do seu código):
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);
}
}
Usando o código do atributo, determinamos o seu id e o tipo de datos (datetime, decimal, int, text, varchar), escriba os datos para a xanela administrativa na táboa apropiada (store_id = 0).
Despois de engadir os atributos anteriores ao produto, obtén esta imaxe no panel de administración:
Datos de inventario
A partir da versión 2.3 en Magento, hai dous conxuntos paralelos de táboas que proporcionan almacenamento de información de inventario (cantidade de produto):
cataloginventory_*: estrutura antiga;
inventory_*: nova estrutura (MSI - Multi Source Inventory);
Debe engadir datos de inventario a ambas estruturas, porque a nova estrutura aínda non é completamente independente da antiga (é moi probable que para default almacén na nova estrutura está implicada unha mesa cataloginventory_stock_status como inventory_stock_1).
catalogo inventario_
Cando implementamos Magneto 2.3 inicialmente temos 2 entradas store_website, que corresponde a dous sitios: administrativo e cliente principal:
É dicir, na nosa antiga estrutura só hai un "almacén" (stock) e está vinculado á páxina web administrativa. Engadindo novos a través do panel de administración sources/stocks en MSI (nova estrutura) non dá lugar a novas entradas en cataloginventory_stock.
Os datos de inventario dos produtos da antiga estrutura rexístranse inicialmente en táboas:
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);
}
inventario_
Inicialmente, a nova estrutura para almacenar datos de inventario contén 1 "fonte'(inventory_source):
«Orixe» representa o almacenamento físico dos produtos (o rexistro contén as coordenadas físicas e o enderezo postal). "Almacén"é unha unión lóxica de varias "fontes" (inventory_source_stock_link)
no nivel no que se produce a conexión coa canle de vendas (inventory_stock_sales_channel)
type |code|stock_id|
-------|----|--------|
website|base| 1|
A xulgar pola estrutura de datos, asúmense varios tipos de canles de venda, pero por defecto só a conexión "stock"-""(a ligazón ao sitio web segue o código do sitio web - base).
Un"almacén"pode estar ligado a varios"fontes"e un"fonte"- a varios"almacéns"(relación de moitos a moitos). As excepcións son por defecto "fonte"E"almacén". Non están ligados de novo a outras entidades (limitación a nivel de código - o erro "Non se pode gardar a ligazón relacionada coa fonte predeterminada ou o stock predeterminado"). Podes atopar máis detalles sobre a estrutura MSI en Magento 2 no artigo "Sistema de xestión de almacén mediante CQRS e Event Sourcing. Deseño«.
Usarei a configuración predeterminada e engadirei toda a información do inventario á fonte default, que está implicado na canle de vendas asociada ao sitio web co código base (corresponde á parte frontal da tenda - ver store_website):
Despois de engadir datos de inventario ao produto no panel de administración, obtén esta imaxe:
Medios
Cando se engade "manualmente" unha imaxe a un produto a través do panel de administración, a información relevante escríbese nas seguintes táboas:
catalog_product_entity_media_gallery: rexistro multimedia (imaxes e ficheiros de vídeo);
catalog_product_entity_media_gallery_value: vinculación de medios a produtos e vitrinas (localización);
catalog_product_entity_media_gallery_value_to_entity: vinculación de medios só a produtos (presumiblemente contido multimedia predeterminado para o produto);
catalog_product_entity_varchar: aquí gárdanse os roles nos que se usa a imaxe;
e as propias imaxes gárdanse no directorio ./pub/media/catalog/product/x/y/onde x и y — a primeira e a segunda letras do nome do ficheiro de imaxe. Por exemplo, arquivo image.png debe gardarse como ./pub/media/catalog/product/i/m/image.png, para que a plataforma poida utilizalo como imaxe á hora de describir produtos do catálogo.
catalog_product_entity_media_gallery
Rexistrarse publicado en ./pub/media/catalog/product/ ficheiro multimedia (o proceso de colocación do ficheiro non se discute neste artigo):
Asociamos o ficheiro multimedia rexistrado co produto correspondente sen estar vinculados a ningún escaparate. Non está claro onde se usan exactamente estes datos e por que é imposible acceder aos datos da táboa anterior, pero esta táboa existe e os datos escriben nela cando se engade unha imaxe ao produto. Entón é iso.
Pódese usar un ficheiro multimedia con diferentes roles (o código de atributo correspondente indícase entre parénteses):
Base (image)
Imaxe pequena (small_image)
Miniatura (thumbnail)
Imaxe de mostra (swatch_image)
Enlazar roles a un ficheiro multimedia é exactamente o que ocorre en catalog_product_entity_varchar. O código vinculante é semellante ao código do "Atributos básicos do produto«.
Despois de engadir unha imaxe ao produto no panel de administración, ten o seguinte aspecto:
Категории
Táboas principais que conteñen datos por categoría:
catalog_category_entity: rexistro de categorías;
catalog_category_product: conexión entre produtos e categorías;
catalog_category_entity_*: valores de atributos EAV;
Inicialmente, nunha aplicación Magento baleira, o rexistro de categorías contén 2 categorías (acurtei os nomes das columnas: crt - created_at, upd - updated_at):
A categoría con id=1 é a raíz de todo o catálogo de Magento e non está dispoñible nin no panel de administración nin na portada. Categoría con id=2 (Categoría predeterminada) é a categoría raíz para a tenda principal do sitio principal (Tenda web principal) creado cando se implanta a aplicación (ver. Administración / Tendas / Todas as tendas). Ademais, a categoría raíz da propia tenda tampouco está dispoñible na parte frontal, só as súas subcategorías.
Dado que o tema deste artigo aínda é a importación de datos sobre produtos, non vou utilizar a entrada directa na base de datos ao crear categorías, senón que utilizarei as clases que proporciona o propio Magento (modelos e repositorios). A entrada directa na base de datos utilízase só para asociar o produto importado cunha categoría (a categoría corresponde co seu nome e obtén o identificador da categoría durante a coincidencia):
Produtos no panel de administración despois de realizar accións adicionais:
e na fronte:
Resumo
O mesmo conxunto de produtos (10 pezas) que no artigo anterior impórtase polo menos unha orde de magnitude máis rápido (1 segundo fronte a 10). Para estimar con máis precisión a velocidade, necesitas un número maior de produtos: varios centos, ou mellor aínda miles. Non obstante, aínda cun tamaño tan pequeno de datos de entrada, podemos concluír que o uso das ferramentas proporcionadas por Magento (modelos e repositorios) é significativo (subliño - moi!) acelerar o desenvolvemento da funcionalidade necesaria, pero ao mesmo tempo significativamente (subliño - moi!) Reduce a velocidade á que os datos entran na base de datos.
Como resultado, a auga resultou mollada e isto non é unha revelación. Non obstante, agora teño o código co que xogar e quizais chegue a algunhas conclusións máis interesantes.