Magento 2: importación de produtos de fontes externas

Magento é unha solución de comercio electrónico, é dicir. está máis orientado á venda de produtos que ao almacenamento, a loxística ou a contabilidade financeira que acompañan as vendas. Outras aplicacións (por exemplo, sistemas ERP) son máis adecuadas para as aplicacións que se acompañan. Por iso, con bastante frecuencia na práctica de usar Magento xorde a tarefa de integrar unha tenda con estes outros sistemas (por exemplo, 1C).

En xeral, a integración pódese reducir á replicación de datos mediante:

  • catálogo (produtos, categorías);
  • datos de inventario (saldos de produtos en almacén e prezos);
  • clientes;
  • ordes;

Magento ofrece unha clase separada de obxectos para manipular datos na base de datos: repositorios. Debido ás características específicas de Magento, engadir datos á base de datos a través de repositorios é fácil de codificar, pero é, digamos, lento. Nesta publicación, considero as principais etapas de engadir programaticamente un produto a Magento 2 de forma "clásica": usando clases de repositorio.

Os clientes e pedidos adoitan replicarse na outra dirección: desde Magento ata sistemas ERP externos. Polo tanto, é máis sinxelo con eles, no lado de Magento só tes que seleccionar os datos axeitados e despois "as balas voaron do noso lado«.

Principios de rexistro de datos nunha base de datos

Polo momento, a creación de obxectos gardados na base de datos mediante programación en Magento realízase mediante fábrica:

function __construct (MagentoCmsModelBlockFactory $blockFactory) {
    $this->blockFactory = $blockFactory;
}

/** @var MagentoCmsModelBlock $block */
$block = $this->blockFactory->create();

e a escritura na base de datos realízase mediante Repositorio:

function __construct (MagentoCmsApiBlockRepositoryInterface $blockRepo) {
    $this->blockRepo = $blockRepo;
}

$this->blockRepo->save($block);

O enfoque "Fábrica" ​​e "Repositorio" pódese usar para todos os modelos principais do dominio Magento 2.

Información básica do produto

Estou mirando unha estrutura de datos que coincide coa versión 2.3 de Magento. A información máis básica sobre o produto está na táboa catalog_product_entity (rexistro de produtos):

entity_id
attribute_set_id
type_id
sku
has_options
required_options
created_at
updated_at

Estou limitado a un tipo de produto (type_id='simple'), un conxunto de atributos predeterminados (attribute_set_id=4) e ignorar atributos has_options и required_options. Xa que os atributos entity_id, created_at и updated_at son xerados automaticamente, entón, de feito, para engadir un novo produto, só temos que configurar sku. Eu fago isto:

/** @var MagentoCatalogApiDataProductInterfaceFactory $factProd */
/** @var MagentoCatalogApiProductRepositoryInterface $repoProd */
/** @var MagentoCatalogApiDataProductInterface $prod */
$prod = $factProd->create();
$prod->setAttributeSetId(4);
$prod->setTypeId('simple');
$prod->setSku($sku);
$repoProd->save($prod);

e teño unha excepción:

The "Product Name" attribute value is empty. Set the attribute and try again.

Engado o nome do produto á solicitude e recibo unha mensaxe de que falta o atributo Price. Despois de engadir o prezo, o produto engádese á base de datos:

$prod = $factProd->create();
$prod->setAttributeSetId(4);
$prod->setTypeId('simple');
$prod->setSku($sku);
$prod->setName($name);
$prod->setPrice($price);
$repoProd->save($prod);

O nome do produto gárdase na táboa de atributos varchar do produto (catalog_product_entity_varchar), prezo - na táboa catalog_product_entity_decimal. Antes de engadir un produto, é recomendable indicar explícitamente que estamos a usar o escaparate administrativo para importar datos:

/** @var MagentoStoreModelStoreManagerInterface $manStore */
$manStore->setCurrentStore(0);

Atributos adicionais

Procesar atributos adicionais do produto usando Magento é un pracer. Modelo de datos EAV para entidades principais (ver táboa eav_entity_type) é unha das características fundamentais desta plataforma. Simplemente engadimos os atributos axeitados ao modelo de produto:

$prodEntity->setData('description', $desc);
$prodEntity->setData('short_description', $desc_short);
// или
$prodEntity->setDescription($desc);
$prodEntity->setShortDescription($desc_short);

e ao gardar o modelo a través do obxecto repo:

$repoProd->save($prod);

tamén se almacenarán atributos adicionais nas táboas de bases de datos correspondentes.

Datos de inventario

En termos sinxelos - a cantidade de produto en stock. En Magento 2.3, as estruturas da base de datos que describen o formato para almacenar os datos de inventario son significativamente diferentes do que pasou antes. Non obstante, engadir a cantidade dun produto en stock a través do modelo de produto non é moito máis difícil que engadir outros atributos:

/** @var MagentoCatalogModelProduct $prodEntity */
/** @var MagentoCatalogApiProductRepositoryInterface $repoProd */
$inventory = [
    'is_in_stock' => true,
    'qty' => 1234
];
$prodEntity->setData('quantity_and_stock_status', $inventory);
$repoProd->save($prodEntity);

Medios

Como regra xeral, o soporte multimedia para un produto para un cliente nunha tenda (comercio electrónico) difire do soporte multimedia para o mesmo produto para un empregado nun sistema de contabilidade interna (ERP). No primeiro caso, é recomendable mostrar o produto cara a cara; no segundo, abonda con dar unha idea xeral do produto. Non obstante, transferir polo menos a imaxe principal dun produto é bastante común. case ao importar datos.

Ao engadir unha imaxe a través do panel de administración, a imaxe gárdase primeiro nun directorio temporal (./pub/media/tmp/catalog/product) e só cando se garda o produto móvese ao directorio multimedia (./pub/media/catalog/product). Ademais, cando se engade a través do panel de administración, a imaxe é etiquetada image, small_image, thumbnail, swatch_image.

/** @var MagentoCatalogApiProductRepositoryInterface $repoProd */
/** @var MagentoCatalogModelProductGalleryCreateHandler $hndlGalleryCreate */
/* $imagePath = '/path/to/file.png';  $imagePathRelative = '/f/i/file.png' */
$imagePathRelative = $this->imagePlaceToTmpMedia($imagePath);
/* reload product with gallery data */
$product = $repoProd->get($sku);
/* add image to product's gallery */
$gallery['images'][] = [
    'file' => $imagePathRelative,
    'media_type' => 'image'
    'label' => ''
];
$product->setData('media_gallery', $gallery);
/* set usage areas */
$product->setData('image', $imagePathRelative);
$product->setData('small_image', $imagePathRelative);
$product->setData('thumbnail', $imagePathRelative);
$product->setData('swatch_image', $imagePathRelative);
/* create product's gallery */
$hndlGalleryCreate->execute($product);

Por algún motivo, o medio está ligado só despois de gardar primeiro o produto e recuperalo de novo do repositorio. E cómpre especificar o atributo label ao engadir unha entrada á galería multimedia do produto (se non, obtemos unha excepción Undefined index: label in .../module-catalog/Model/Product/Gallery/CreateHandler.php on line 516).

Категории

A miúdo, a estrutura de categorías da tenda e a aplicación de backend ou a colocación dos produtos nelas poden diferir significativamente. As estratexias para migrar datos sobre categorías e produtos dentro delas dependen de moitos factores. Neste exemplo fírome ao seguinte:

  • as categorías de backend e tenda compáranse polo nome;
  • se se importa unha categoría que non está na tenda, créase na categoría raíz (Default Category) e o seu posterior posicionamento no catálogo da tenda asúmese manualmente;
  • un produto atribúese a unha categoría só cando se crea na tenda (primeira importación);

A información básica sobre a categoría está na táboa catalog_category_entity (catálogo de categorías). Creando unha categoría en Magento:

/** @var MagentoCatalogApiDataCategoryInterfaceFactory $factCat */
/** @var MagentoCatalogApiCategoryRepositoryInterface $repoCat */
$cat = $factCat->create();
$cat->setName($name);
$cat->setIsActive(true);
$repoCat->save($cat);

A vinculación dun produto a unha categoría realízase mediante o ID de categoría e o SKU do produto:

/** @var MagentoCatalogModelCategoryProductLinkFactory $factCatProdLink */
/** @var MagentoCatalogApiCategoryLinkRepositoryInterface $repoCatLink */
$link = $factCatProdLink->create();
$link->setCategoryId($catMageId);
$link->setSku($prodSku);
$repoCatLink->save($link);

En total

Escribir código para engadir un produto mediante programación a Magento 2 é bastante sinxelo. Combinei todo o indicado anteriormente nun módulo de demostración "flancer32/mage2_ext_demo_import". Só hai un comando de consola no módulo fl32:import:prod, que importa os produtos descritos no ficheiro JSON "./etc/data/products.json":

[
  {
    "sku": "...",
    "name": "...",
    "desc": "...",
    "desc_short": "...",
    "price": ...,
    "qty": ...,
    "categories": ["..."],
    "image_path": "..."
  }
]

As imaxes para importar están no catálogo ./etc/data/img.

O tempo para importar 10 produtos usando este método é duns 10 segundos no meu portátil. Se desenvolvemos máis esta idea, é fácil chegar á conclusión de que se poden importar uns 3600 produtos por hora e que pode levar unhas 100 horas importar 30 produtos. Substituír un portátil por un servidor permítelle suavizar un pouco a situación. Quizais incluso varias veces. Pero non por ordes de magnitude. Quizais esta velocidade e lentitude sexa en certa medida un dos motivos da aparición do proxecto magento/async-import.

Unha solución radical para aumentar a velocidade de importación podería ser a entrada directa na base de datos, pero neste caso pérdense todas as "buques" sobre a extensibilidade de Magento: terás que facer todo "avanzado" ti mesmo. Non obstante, paga a pena. Se funciona, considerarei o enfoque coa escritura directa na base de datos no seguinte artigo.

Fonte: www.habr.com

Engadir un comentario