Magento 2 : importer des produits depuis des sources externes

Magento est une solution e-commerce, c'est-à-dire qu'elle est davantage axée sur la vente de produits que sur les aspects connexes comme la gestion des stocks, la logistique ou la comptabilité financière. D'autres applications (comme les systèmes ERP) sont mieux adaptées pour ces derniers. Par conséquent, il est assez fréquent que l'utilisation de Magento nécessite l'intégration de la boutique avec ces autres systèmes (par exemple, avec 1C).

En gros, l'intégration peut être réduite à la réplication des données concernant :

  • le catalogue (produits, catégories) ;
  • les données d'inventaire (stocks de produits et prix) ;
  • les clients ;
  • les commandes ;

Magento propose une classe distincte d'objets pour manipuler les données dans la base — dépôts. Étant donné la spécificité de Magento, l'ajout de données à la base via des dépôts (repositories) est facile à coder, mais se fait, disons, de manière un peu lente. Dans cette publication, j'examine les étapes principales pour ajouter un produit à Magento 2 de manière « classique » — en utilisant des classes de dépôt.

Les clients et les commandes sont généralement répliqués dans l'autre sens — de Magento vers les systèmes ERP externes. C'est donc plus simple, du côté de Magento, il suffit de sélectionner les données correspondantes, puis — «de notre côté, les balles ont été tirées«.

Principes d'enregistrement des données dans la base

À l'heure actuelle, la création d'objets enregistrables dans la base par programmation dans Magento s'effectue via Factory:

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

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

et l'enregistrement dans la base — via Repository:

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

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

L'approche utilisant « Factory » et « Repository » peut être appliquée à tous les modèles principaux dans le domaine de Magento 2.

Informations de base sur le produit

J'examine la structure de données correspondant à la version Magento 2.3. Les informations les plus fondamentales sur le produit se trouvent dans la table catalog_product_entity (registre des produits) :

entity_id
attribute_set_id
type_id
sku
has_options
required_options
created_at
updated_at

Je me limite à un type de produit (type_id='simple'), un ensemble d'attributs par défaut (attribute_set_id=4) et j'ignore les attributs has_options et required_options. Comme les attributs entity_id, created_at et updated_at sont générés automatiquement, en réalité, pour ajouter un nouveau produit, il nous suffit de spécifier sku. Je procède ainsi :

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

et je reçois une exception :

La valeur de l'attribut "Nom du produit" est vide. Définissez l'attribut et réessayez.

J'ajoute le nom du produit à la demande et je reçois un message indiquant qu'il manque un attribut. Prix. Après avoir ajouté le prix, le produit est enregistré dans la base :

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

Le nom du produit est enregistré dans la table des attributs varchar du produit (catalog_product_entity_varchar), le prix dans la table catalog_product_entity_decimal. Avant d'ajouter le produit, il est souhaitable d'indiquer expressément que nous utilisons la vitrine administrative pour l'importation des données :

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

Attributs supplémentaires

La gestion des attributs supplémentaires des produits via Magento est un véritable plaisir. Le modèle de données EAV pour les entités principales (voir la table eav_entity_type) est l'une des caractéristiques clés de cette plateforme. Il suffit d'ajouter les attributs correspondants au modèle du produit :

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

et lors de la sauvegarde du modèle via l'objet de référentiel :

$repoProd->save($prod);

les attributs supplémentaires seront également enregistrés dans les tables appropriées de la base de données.

Données d'inventaire

En termes simples, il s'agit de la quantité de produit en stock. Dans Magento 2.3, les structures de la base de données décrivant le format de stockage des données d'inventaire, diffèrent significativement de ce qui était proposé auparavant. Cependant, l'ajout de la quantité de produit en stock via le modèle de produit n'est pas beaucoup plus compliqué que l'ajout d'autres attributs :

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

Média

En général, le suivi média d'un produit pour le client dans le magasin (e-commerce) diffère du suivi média de ce même produit pour un employé dans le système interne de comptabilité (ERP). Dans le premier cas, il est souhaitable de montrer le produit sous son meilleur jour, dans le second, il suffit de donner une vue d'ensemble du produit. Néanmoins, le transfert d'au moins l'image primaire du produit est une pratique assez courante case lors de l'importation des données.

Lors de l'ajout d'une image via l'interface d'administration, l'image est d'abord enregistrée dans le répertoire temporaire (./pub/media/tmp/catalog/product) et seulement lors de la sauvegarde du produit, elle est déplacée dans le répertoire média (./pub/media/catalog/product). De plus, lors de l'ajout via l'interface d'administration, l'image reçoit les étiquettes 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);

Pourquoi les médias ne sont-ils associés qu'après sauvegarde préalable du produit et récupération de celui-ci depuis le référentiel ? Il est nécessaire de spécifier l'attribut. label lors de l'ajout d'un enregistrement dans la galerie multimédia du produit (sinon, une exception est générée Index indéfini : label dans .../module-catalog/Model/Product/Gallery/CreateHandler.php à la ligne 516).

Catégories

La structure des catégories du magasin et de l'application backend ou le placement des produits en elles peuvent souvent varier considérablement. Les stratégies de transfert des données sur les catégories et les produits dans celles-ci dépendent de nombreux facteurs. Dans cet exemple, je m'en tiens à ce qui suit :

  • les catégories du backend et du magasin sont associées par leur nom ;
  • si une catégorie qui n'existe pas dans le magasin est importée, elle est créée sous la catégorie racine (Catégorie par défaut) et son positionnement ultérieur dans le catalogue du magasin doit être effectué manuellement ;
  • l'association d'un produit à une catégorie se fait uniquement lors de sa création dans le magasin (premier import) ;

Les informations principales sur la catégorie se trouvent dans la table catalog_category_entity (catalogue des catégories). Créer une catégorie dans Magento :

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

L'association d'un produit à une catégorie est effectuée par l'ID de la catégorie et le SKU du produit :

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

Au total

Écrire du code pour ajouter un produit dans Magento 2 par voie programmatique n'est pas très compliqué. Tout ce qui précède a été rassemblé dans un module de démonstration «flancer32/mage2_ext_demo_import». Le module contient uniquement une commande en ligne fl32:import:prod, qui importe les produits décrits dans le fichier JSON «./etc/data/products.json«:

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

Les images à importer se trouvent dans le répertoire ./etc/data/img.

Le temps d'importation de 10 produits de cette manière est d'environ 10 secondes sur mon ordinateur portable. Si l'on développe cette idée, il n'est pas difficile de conclure qu'il est possible d'importer environ 3600 produits par heure, et que l'importation de 100K produits pourrait prendre environ 30 heures. Remplacer l'ordinateur portable par un serveur peut réduire la situation de manière significative. Peut-être même de plusieurs fois. Mais pas d'ordres de grandeur. Cette lenteur pourrait en partie être l'une des raisons de l'émergence du projet magento/async-import.

Une solution radicale pour augmenter la vitesse d'importation pourrait être l'écriture directe dans la base de données, mais dans ce cas, toutes les « fonctionnalités » concernant l'extensibilité de Magento sont perdues - il faudra tout faire soi-même. Cependant, cela en vaut la peine. Si possible, j'examinerai l'approche de l'écriture directe dans la BDD dans le prochain article.

Source : habr.com

Acheter un hébergement fiable pour les sites avec protection DDoS, serveurs VPS VDS 🔥 Acheter un hébergement fiable pour les sites avec protection DDoS, serveurs VPS VDS | ProHoster