Magento 2: import produktů z externích zdrojů

Magento je e-commerce řešení, které je více zaměřené na prodej produktů než na související skladové, logistické nebo finanční účetnictví. Pro tyto účely jsou lepší jiná aplikace (například ERP systémy). Proto je při používání Magento často potřeba integrovat obchod s těmito jinými systémy (například s 1C).

V podstatě lze integraci zúžit na replikaci dat podle:

  • katalogu (produkty, kategorie);
  • inventárních údajů (zásoby produktů na skladech a ceny);
  • zákazníkům;
  • objednávkám;

Magento pro manipulaci s daty v databázi nabízí speciální třídu objektů — repozitáře. Vzhledem k specifikům Magento je přidání dat do databáze skrze repozitáře snadno kódovatelné, ale probíhá, řekněme, pomalu. V tomto článku se zabývám hlavními kroky programového přidávání produktu do Magento 2 "klasickým" způsobem — pomocí repo tříd.

Zákazníci a objednávky se obvykle replikují na druhou stranu — z Magento do externích ERP systémů. Proto je to snazší, na straně Magento stačí vybrat příslušná data, a pak — "z naší strany kulky vyletěly«.

Principy zápisu dat do databáze

V současné době se vytváření objektů, které se ukládají do databáze, programovým způsobem v Magento provádí přes Factory:

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

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

a zápis do databáze — přes Repository:

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

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

Přístup s použitím "Factory" a "Repository" lze použít pro všechny základní modely v oboru Magento 2.

Základní informace o produktu

Zabývám se datovou strukturou odpovídající verzi Magento 2.3. Nejzákladnější informace o produktu se nachází v tabulce catalog_product_entity (registr produktů):

entity_id
attribute_set_id
type_id
sku
has_options
required_options
created_at
updated_at

Omezuji se na jeden typ produktu (type_id='simple'), výchozí sadu atributů (attribute_set_id=4) a ignoruji atributy has_options a required_options. Protože atributy entity_id, created_at a updated_at se generují automaticky, pak nám pro přidání nového produktu stačí zadat sku. Dělám to takto:

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

a dostávám výjimku:

Hodnota atributu "Název produktu" je prázdná. Nastavte atribut a zkuste to znovu.

Přidávám do žádosti název produktu a dostávám zprávu, že chybí atribut Cena. Po přidání ceny je produkt uložen do databáze:

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

Název produktu se ukládá do tabulky varchar atributů produktu (catalog_product_entity_varchar), cena — v tabulce catalog_product_entity_decimal. Před přidáním produktu je žádoucí výslovně uvést, že používáme administrativní rozhraní pro import dat:

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

Další atributy

Zpracování dalších atributů produktů pomocí Magento je skutečná radost. EAV model dat pro hlavní entity (viz tabulka eav_entity_type) — jedna z klíčových vlastností této platformy. Jednoduše přidáváme odpovídající atributy k modelu produktu:

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

a při ukládání modelu přes repozitář:

$repoProd->save($prod);

další atributy budou také uloženy v odpovídajících tabulkách databáze.

Inventární data

Jednoduše — množství produktu na skladu. Ve struktuře databáze Magento 2.3, která popisuje formát uchovávání inventárních dat, významně se liší od předchozího systému. Přesto přidání množství produktu na skladu přes model produktu není o mnoho složitější než přidání dalších atributů:

/** @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

Obecně se mediální reprezentace produktu pro zákazníka v obchodě (e-commerce) liší od mediální reprezentace téhož produktu pro zaměstnance ve vnitřním systému (ERP). V prvním případě je žádoucí ukázat „zboží tváří v tvář“, v druhém stačí poskytnout obecnou představu o produktu. Nicméně, přenos alespoň základního obrázku produktu je poměrně rozšířený case při importu dat.

Při přidání obrázku přes administraci se obrázek nejprve ukládá do dočasného adresáře (./pub/media/tmp/catalog/product) a až při uložení produktu se přesune do mediálního adresáře (./pub/media/catalog/product). Při přidání přes administraci jsou obrázku také přiřazeny tagy obrázek, 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);

Z nějakého důvodu se média přiřazují pouze po předchozím uložení produktu a znovuzískání z repozitáře. Je nutné uvést atribut label při přidávání záznamu do mediální galerie produktu (jinak dojde k výjimce Nedefinovaný index: label v .../module-catalog/Model/Product/Gallery/CreateHandler.php na řádku 516).

Kategorie

Struktura kategorií obchodu a backendové aplikace, nebo umístění v nich produktů, se často může výrazně lišit. Strategie přenosu dat o kategoriích a produktech v nich závisí na mnoha faktorech. V tomto příkladu se držím následujícího:

  • kategorie backendu a obchodu se mapují podle názvu;
  • pokud je importována kategorie, která v obchodě není, je vytvořena pod kořenovou kategorií (Default Category) a její další umístění v katalogu obchodu se předpokládá ručně;
  • přiřazení produktu ke kategorii se provádí pouze při jeho vytvoření v obchodě (při prvním importu);

Hlavní informace o kategorii se nachází v tabulce catalog_category_entity (katalog kategorií). Vytvoření kategorie v Magento:

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

Přiřazení produktu ke kategorii se provádí podle ID kategorie a SKU produktu:

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

Celkem

Napsat kód pro přidání produktu do Magento 2 programově není příliš složité. Vše, co bylo výše uvedeno, jsem shrnul do demo modulu „flancer32/mage2_ext_demo_import“. V modulu je pouze jeden příkaz pro terminál fl32:import:prod, který importuje produkty popsané v JSON souboru „./etc/data/products.json«:

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

Obrázky pro import se nacházejí v katalogu ./etc/data/img.

Doba importu 10 produktů tímto způsobem činí přibližně 10 sekund na mém notebooku. Pokud se na tuto myšlenku podíváte hlouběji, není těžké dojít k závěru, že za hodinu lze importovat přibližně 3600 produktů, což znamená, že na import 100K produktů může být potřeba přibližně 30 hodin. Výměna notebooku za server situaci poněkud zlepšuje. Možná dokonce mnohonásobně. Ale ne o řády. Je možné, že tato rychlost je do určité míry jednou z příčin vzniku projektu magento/async-import.

Radikálním řešením pro zvýšení rychlosti importu může být přímý zápis do databáze, ale v tomto případě jsou ztraceny všechny „vymoženosti“ týkající se rozšiřitelnosti Magento - všechno rozšířené budete muset dělat sami. Přesto to stojí za to. Pokud se to podaří, podívám se na přístup s přímým zápisem do databáze v dalším článku.

Zdroj: habr.com

Koupit spolehlivý hosting pro webové stránky s ochranou proti DDoS, VPS VDS servery 🔥 Koupit spolehlivý hosting pro webové stránky s ochranou proti DDoS, VPS VDS servery | ProHoster