Magento 2:从外部来源导入产品

Magento 是一种电子商务解决方案,即其目的更多的是销售产品,而不是伴随销售的仓储、物流或财务会计。 其他应用程序(例如 ERP 系统)更适合随附的应用程序。 因此,在使用 Magento 的实践中,经常会出现将商店与这些其他系统(例如 1C)集成的任务。

总的来说,集成可以通过以下方式简化为数据复制:

  • 目录(产品、类别);
  • 库存数据(仓库中的产品余额和价格);
  • 客户;
  • 命令;

Magento 提供了一个单独的对象类来操作数据库中的数据 - 储存库。 由于 Magento 的特殊性,通过存储库将数据添加到数据库很容易编码,但可以说很慢。 在本出版物中,我考虑了以“经典”方式以编程方式将产品添加到 Magento 2 的主要阶段 - 使用存储库类。

客户和订单通常会从另一个方向复制 - 从 Magento 到外部 ERP 系统。 因此,使用它们更简单,在 Magento 端你只需要选择适当的数据,然后“子弹从我们身边飞出«。

将数据记录到数据库的原理

目前,在 Magento 中以编程方式创建保存在数据库中的对象是通过 工厂:

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

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

写入数据库是通过 存储库 :

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

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

“工厂”和“存储库”方法可用于 Magento 2 领域中的所有主要模型。

产品基本信息

我正在寻找与 Magento 2.3 版本匹配的数据结构。 该产品最基本的信息见表 catalog_product_entity (产品注册):

entity_id
attribute_set_id
type_id
sku
has_options
required_options
created_at
updated_at

我仅限于一种类型的产品(type_id='simple'),一组默认属性(attribute_set_id=4) 并忽略属性 has_options и required_options。 既然属性 entity_id, created_at и updated_at 都是自动生成的,那么,其实要添加一个新的产品,我们只需要设置 sku。 我这样做:

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

我得到一个例外:

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

我将产品名称添加到请求中并收到一条消息,指出缺少该属性 Price。 添加价格后,产品将添加到数据库中:

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

产品名称存储在产品 varchar 属性表中(catalog_product_entity_varchar), 价格 - 表中 catalog_product_entity_decimal。 在添加产品之前,建议明确表明我们正在使用管理店面导入数据:

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

附加属性

使用 Magento 处理附加产品属性是一种乐趣。 主要实体的EAV数据模型(见表 eav_entity_type)是该平台的主要功能之一。 我们只需将适当的属性添加到产品模型中即可:

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

通过 repo 对象保存模型时:

$repoProd->save($prod);

附加属性也将存储在相应的数据库表中。

库存数据

简单来说 - 库存产品的数量。 在 Magento 2.3 中,数据库中描述存储库存数据格式的结构是 显着不同 从之前发生的事情来看。 然而,通过产品模型添加产品的库存数量并不比添加其他属性困难多少:

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

媒体

通常,商店(电子商务)中客户对产品的媒体支持与内部会计系统(ERP)中员工对同一产品的媒体支持不同。 在第一种情况下,建议面对面展示产品;在第二种情况下,给出产品的总体概念就足够了。 然而,至少传输产品的主图像是很常见的。 case 导入数据时。

通过管理面板添加图像时,图像首先保存在临时目录中(./pub/media/tmp/catalog/product)并且仅在保存时将产品移动到媒体目录(./pub/media/catalog/product)。 此外,当通过管理面板添加时,图像会被标记 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);

由于某种原因,仅在首次保存产品并再次从存储库检索它后才链接媒体。 并且需要指定属性 label 将条目添加到产品媒体库时(否则我们会得到异常 Undefined index: label in .../module-catalog/Model/Product/Gallery/CreateHandler.php on line 516).

类别

通常,商店的类别结构和后端应用程序或产品在其中的放置可能会有很大差异。 迁移有关类别和其中产品的数据的策略取决于许多因素。 在此示例中,我坚持以下原则:

  • 后端和商店类别通过名称进行比较;
  • 如果导入的类别不在商店中,则会在根类别下创建该类别(Default Category)并且其在商店目录中的进一步定位是手动假定的;
  • 仅当产品在商店中创建时(首次导入),产品才会被分配到类别;

该类别的基本信息见表 catalog_category_entity (类别目录)。 在 Magento 中创建类别:

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

使用类别 ID 和产品 SKU 将产品链接到类别:

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

在总

编写代码以编程方式将产品添加到 Magento 2 非常容易。 我已将上述所有内容合并到一个演示模块中“flancer32/mage2_ext_demo_import”。 模块中只有一个控制台命令 fl32:import:prod,导入 JSON 文件中描述的产品“./etc/data/products.json“:

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

导入的图片在目录中 ./etc/data/img.

在我的笔记本电脑上,使用此方法导入 10 个产品的时间约为 10 秒。 如果我们进一步发展这个想法,很容易得出这样的结论:每小时大约可以导入3600个产品,导入100K个产品大约需要30个小时。 用服务器替换笔记本电脑可以让您在某种程度上缓解这种情况。 甚至可能有好几次。 但不是几个数量级。 或许这种快与慢在某种程度上就是该项目出现的原因之一 magento/异步导入.

提高导入速度的根本解决方案可能是直接输入数据库,但在这种情况下,所有有关 Magento 可扩展性的“好东西”都会丢失 - 您将必须自己“高级”完成所有事情。 然而,这是值得的。 如果可行的话,我会在下一篇文章中考虑直接写入数据库的方法。

来源: habr.com

添加评论