Magento 2: importe produtos diretamente para o banco de dados
В artigo anterior Descrevi o processo de importação de produtos para o Magento 2 da maneira usual - por meio de modelos e repositórios. O método usual possui uma velocidade de processamento de dados muito baixa. Meu laptop estava produzindo cerca de um produto por segundo. Nesta continuação, considero uma forma alternativa de importar um produto - por entrada direta no banco de dados, contornando os mecanismos padrão do Magento 2 (modelos, fábricas, repositórios). A sequência de passos para importação de produtos pode ser adaptada a qualquer linguagem de programação que funcione com MySQL.
Aviso Legal: Magento tem funcionalidades prontas para importação de dados e, provavelmente, será o suficiente para você. Porém, se você precisa de um controle mais completo sobre o processo de importação, não se limitando a preparar um arquivo CSV para o que você possui, seja bem-vindo ao cat.
O código resultante da escrita de ambos os artigos pode ser visualizado no módulo Magento "flancer32/mage2_ext_demo_import". Aqui estão algumas restrições que segui para simplificar o código do módulo de demonstração:
Os produtos são apenas criados, não atualizados.
Um armazém
Somente nomes de categorias são importados, sem sua estrutura
As estruturas de dados estão em conformidade com a versão 2.3
JSON para importar um ú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"
}
Visão geral das principais etapas da importação
registro do próprio produto
conexão entre produto e site
atributos básicos do produto (EAV)
dados de estoque (quantidade de produto em estoque)
mídia (fotos)
conexão com categorias de catálogo
Registo de produto
Informações básicas do produto podem ser encontradas em 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`)
)
As informações mínimas necessárias para criar uma entrada no cadastro do produto são:
attribute_set_id
sku
adicional:
type_id — se não especificarmos, então 'simples' será usado
Para escrever diretamente no banco de dados, utilizo o adaptador DB do próprio Magento:
O produto recém-registrado ainda não possui nome ou descrição. Tudo isso é feito através Atributos EAV. Aqui está uma lista de atributos básicos do produto que são necessários para que o produto seja exibido corretamente na frente:
name
price
description
short_description
status
tax_class_id
url_key
visibility
Um atributo separado é adicionado a um produto como este (os detalhes para obter o identificador e o tipo do atributo de seu código são omitidos):
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 seu id e tipo de dados (datetime, decimal, int, text, varchar) e, em seguida, grave os dados da janela administrativa na tabela apropriada (store_id = 0).
Depois de adicionar os atributos acima ao produto, você obtém esta imagem no painel de administração:
Dados de inventário
A partir da versão 2.3 no Magento, existem dois conjuntos paralelos de tabelas que fornecem armazenamento de informações de estoque (quantidade de produtos):
cataloginventory_*: estrutura antiga;
inventory_*: nova estrutura (MSI – Multi Source Inventory);
Você precisa adicionar dados de inventário a ambas as estruturas, porque a nova estrutura ainda não é completamente independente da antiga (é muito provável que para default armazém na nova estrutura uma tabela está envolvida cataloginventory_stock_status como inventory_stock_1).
catálogoinventário_
Ao implantar o Magneto 2.3, inicialmente temos 2 entradas em store_website, que corresponde a dois sites - administrativo e cliente principal:
Ou seja, na nossa estrutura antiga existe apenas um “armazém” (stock) e está vinculado ao site administrativo. Adicionando novos através do painel de administração sources/stocks no MSI (nova estrutura) não resulta em novas entradas no cataloginventory_stock.
Os dados de estoque de produtos na estrutura antiga são inicialmente registrados em tabelas:
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);
}
inventário_
Inicialmente, a nova estrutura de armazenamento de dados de estoque contém 1 "fonte"(inventory_source):
«Fonte» representa o armazenamento físico dos produtos (o registro contém coordenadas físicas e endereço para correspondência). "Armazém"é uma união lógica de várias" fontes "(inventory_source_stock_link)
no nível em que ocorre a conexão com o canal de vendas (inventory_stock_sales_channel)
type |code|stock_id|
-------|----|--------|
website|base| 1|
A julgar pela estrutura de dados, são assumidos vários tipos de canais de vendas, mas por padrão apenas a conexão “estoque"-"site do Network Development Group"(o link para o site segue o código do site - base).
Um "armazém"pode ser vinculado a vários"fontes"e um "fonte" - para vários "armazéns"(relacionamento muitos-para-muitos). As exceções são padrão "fonte"E"armazém". Eles não são vinculados novamente a outras entidades (limitação no nível do código - o erro “Não é possível salvar o link relacionado à origem padrão ou ao estoque padrão"). Mais detalhes sobre a estrutura MSI no Magento 2 podem ser encontrados no artigo “Sistema de gerenciamento de armazém utilizando CQRS e Event Sourcing. Projeto".
Usarei a configuração padrão e adicionarei todas as informações de inventário à fonte default, que está envolvido no canal de vendas associado ao site com o código base (corresponde à fachada da loja - ver store_website):
Depois de adicionar dados de inventário ao produto no painel de administração, você terá esta imagem:
mídia
Ao adicionar “manualmente” uma imagem a um produto através do painel de administração, as informações relevantes são anotadas nas seguintes tabelas:
catalog_product_entity_media_gallery: registro de mídia (arquivos de imagens e vídeos);
catalog_product_entity_media_gallery_value: vinculação de mídia a produtos e vitrines (localização);
catalog_product_entity_media_gallery_value_to_entity: vinculando mídia apenas a produtos (presumivelmente conteúdo de mídia padrão para o produto);
catalog_product_entity_varchar: As funções nas quais a imagem é usada são armazenadas aqui;
e as próprias imagens são salvas no diretório ./pub/media/catalog/product/x/y/Onde x и y — a primeira e a segunda letras do nome do arquivo de imagem. Por exemplo, arquivo image.png deve ser salvo como ./pub/media/catalog/product/i/m/image.png, para que a plataforma possa utilizá-lo como imagem na descrição dos produtos do catálogo.
catalog_product_entity_media_gallery
Cadastro postado em ./pub/media/catalog/product/ arquivo de mídia (o processo de colocação do arquivo em si não é discutido neste artigo):
Associamos o arquivo de mídia cadastrado ao produto correspondente sem estarmos vinculados a nenhuma vitrine. Não está claro onde exatamente esses dados são usados e por que é impossível acessar os dados da tabela anterior, mas esta tabela existe e os dados são gravados nela quando uma imagem é adicionada ao produto. Então é isso.
Um arquivo de mídia pode ser usado com diferentes funções (o código do atributo correspondente é indicado entre parênteses):
Base(image)
Imagem pequena (small_image)
Miniatura (thumbnail)
Imagem de amostra (swatch_image)
Vincular funções a um arquivo de mídia é exatamente o que acontece em catalog_product_entity_varchar. O código de ligação é semelhante ao código no "Atributos básicos do produto".
Depois de adicionar uma imagem ao produto no painel de administração, ele ficará assim:
categoria
Principais tabelas contendo dados por categoria:
catalog_category_entity: cadastro de categorias;
catalog_category_product: conexão entre produtos e categorias;
catalog_category_entity_*: Valores de atributos EAV;
Inicialmente, em uma aplicação Magento vazia, o registro de categorias contém 2 categorias (encurtei os nomes das colunas: crt - created_at, upd - updated_at):
A categoria com id=1 é a raiz de todo o catálogo Magento e não está disponível nem no painel de administração nem na página inicial. Categoria com id=2 (Categoria Padrão) é a categoria raiz da loja principal do site principal (Loja principal do site) criado quando o aplicativo é implantado (consulte. Administrador / Lojas / Todas as lojas). Além disso, a categoria raiz da loja em si também não está disponível na frente, apenas suas subcategorias.
Como o tema deste artigo ainda é importação de dados de produtos, não utilizarei a entrada direta no banco de dados na criação de categorias, mas utilizarei as classes fornecidas pelo próprio Magento (modelos e repositórios). A entrada direta no banco de dados é usada apenas para associar o produto importado a uma categoria (a categoria é correspondida por seu nome e o ID da categoria é recuperado durante a correspondência):
Depois de adicionar um link de produto às categorias “Categoria 1” e “Categoria 2”, os detalhes do produto no painel de administração são mais ou menos assim:
Ações adicionais
Assim que a importação de dados for concluída, você precisará concluir as seguintes etapas adicionais:
indexação de dados: chamada no console ./bin/magento indexer:reindex;
Produtos no painel de administração após realizar ações adicionais:
e na frente:
Resumo
O mesmo conjunto de produtos (10 peças) do artigo anterior é importado pelo menos uma ordem de grandeza mais rápida (1 segundo versus 10). Para estimar a velocidade com mais precisão, você precisa de um número maior de produtos - várias centenas, ou melhor ainda, milhares. Porém, mesmo com um tamanho tão pequeno de dados de entrada, podemos concluir que o uso das ferramentas disponibilizadas pelo Magento (modelos e repositórios) é significativo (enfatizo - muito!) acelerar o desenvolvimento da funcionalidade necessária, mas ao mesmo tempo significativamente (enfatizo - muito!) reduz a velocidade com que os dados chegam ao banco de dados.
Como resultado, a água ficou molhada e isso não é uma revelação. No entanto, agora tenho o código para brincar e talvez chegar a algumas conclusões mais interessantes.