Magento 2: importazione di prodotti da fonti esterne

Magento è una soluzione di e-commerce, ovvero è più orientata alla vendita di prodotti che alla gestione di contabilità di magazzino, logistica o finanza. Per queste ultime, altri applicativi (come i sistemi ERP) sono più adatti. Pertanto, spesso nell'uso pratico di Magento si presenta la necessità di integrare il negozio con questi altri sistemi (per esempio, con 1C).

In linea di massima, l'integrazione può essere ridotta alla replicazione dei dati su:

  • catalogo (prodotti, categorie);
  • dati di inventario (giacenze di prodotti nei magazzini e prezzi);
  • clienti;
  • ordini;

Magento offre per manipolare i dati nel database una classe separata di oggetti — repository. A causa della specificità di Magento, l'aggiunta di dati al database tramite repository è facile da codificare, ma avviene, per così dire, lentamente. In questa pubblicazione, esaminerò le fasi principali per l'aggiunta programmata di un prodotto in Magento 2 nel modo "classico" — utilizzando le classi repo.

I clienti e gli ordini vengono replicati, di solito, nell'altra direzione — da Magento verso sistemi ERP esterni. Quindi, per questi è più semplice, nel lato di Magento è sufficiente selezionare i dati corrispondenti, e poi — "dalla nostra parte le pallottole sono uscite«.

Principi di registrazione dei dati nel database

Attualmente la creazione di oggetti memorizzabili nel database in modo programmato in Magento avviene tramite Factory:

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

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

e la registrazione nel database — tramite Repository:

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

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

L'approccio che utilizza "Factory" e "Repository" può essere applicato a tutti i modelli principali nell'area tematica di Magento 2.

Informazioni di base sul prodotto

Esaminerò la struttura dei dati conforme alla versione Magento 2.3. Le informazioni di base sul prodotto si trovano nella tabella catalog_product_entity (registro dei prodotti):

entity_id
attribute_set_id
type_id
sku
has_options
required_options
created_at
updated_at

Mi limito a un tipo di prodotto (type_id='simple'), set di attributi di default (attribute_set_id=4) e ignoro gli attributi has_options e required_options. Poiché gli attributi entity_id, created_at e updated_at vengono generati automaticamente, in sostanza, ci basta per aggiungere un nuovo prodotto impostare sku. Faccio così:

/** @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 ricevo un'eccezione:

Il valore dell'attributo "Nome Prodotto" è vuoto. Imposta l'attributo e riprova.

Aggiungo al request il nome del prodotto e ricevo un messaggio che manca un attributo. Prezzo. Dopo aver aggiunto il prezzo, il prodotto viene salvato nel database:

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

Il nome del prodotto viene salvato nella tabella degli attributi varchar del prodotto (catalog_product_entity_varchar), il prezzo – nella tabella catalog_product_entity_decimal. Prima di aggiungere il prodotto, è consigliabile specificare esplicitamente che stiamo utilizzando il front-end amministrativo per importare i dati:

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

Attributi aggiuntivi

Gestire gli attributi aggiuntivi dei prodotti con Magento è un piacere. Il modello dati EAV per le entità principali (vedi tabella eav_entity_type) è una delle caratteristiche chiave di questa piattaforma. Aggiungiamo semplicemente gli attributi appropriati al modello di prodotto:

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

e al momento del salvataggio del modello tramite l'oggetto repo:

$repoProd->save($prod);

gli attributi aggiuntivi saranno anch'essi salvati nelle tabelle corrispondenti del database.

Dati dell'inventario

In parole semplici, la quantità del prodotto in magazzino. In Magento 2.3 le strutture nel database che descrivono il formato di archiviazione dei dati dell'inventario, differiscono significativamente da quelle precedenti. Tuttavia, aggiungere la quantità del prodotto in magazzino tramite il modello di prodotto non è molto più difficile rispetto all'aggiunta di altri attributi:

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

Media

In generale, il supporto multimediale del prodotto per il cliente nel negozio (e-commerce) è diverso dal supporto multimediale dello stesso prodotto per il personale nel sistema di contabilità interno (ERP). Nel primo caso, è preferibile mostrare "il prodotto" frontalmente, nel secondo – è sufficiente dare una visione generale del prodotto. Tuttavia, trasferire almeno l'immagine primaria del prodotto è abbastanza comune case durante l'importazione dei dati.

Quando si aggiunge un'immagine tramite l'admin, l'immagine viene prima salvata in una cartella temporanea (./pub/media/tmp/catalog/product) e solo al momento del salvataggio del prodotto viene spostata nella cartella multimediale (./pub/media/catalog/product). Inoltre, quando si aggiunge tramite l'admin, all'immagine vengono applicate le etichette 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);

Stranamente, i media vengono associati solo dopo il salvataggio preliminare del prodotto e il suo successivo recupero dal repository. È necessario specificare l'attributo. label quando si aggiunge una registrazione nella galleria media del prodotto (altrimenti si ottiene un'eccezione Indice non definito: label in .../module-catalog/Model/Product/Gallery/CreateHandler.php alla riga 516).

Categorie

Spesso la struttura delle categorie del negozio e dell'applicazione backend, o la loro collocazione, possono differire notevolmente. Le strategie per la migrazione dei dati delle categorie e dei prodotti in esse dipendono da molteplici fattori. In questo esempio seguirò la seguente:

  • le categorie del backend e del negozio sono mappate per nome;
  • se viene importata una categoria che non esiste nel negozio, viene creata sotto la categoria radice (Categoria predefinita) e il suo posizionamento successivo nel catalogo del negozio è previsto manualmente;
  • l'associazione del prodotto alla categoria avviene solo al momento della sua creazione nel negozio (primo import);

Le informazioni principali sulla categoria si trovano nella tabella catalog_category_entity (catalogo categorie). Creazione della categoria in Magento:

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

L'associazione del prodotto alla categoria è realizzata tramite l'ID della categoria e lo SKU del prodotto:

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

Totale

Scrivere codice per aggiungere un prodotto a Magento 2 in modo programmatico non è affatto complicato. Tutto quanto sopra è stato condensato in un modulo demo «flancer32/mage2_ext_demo_import«. Nel modulo c'è solo un comando da console fl32:import:prod, che importa i prodotti descritti nel file JSON «./etc/data/products.json«:

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

Le immagini da importare si trovano nella cartella ./etc/data/img.

Il tempo di importazione di 10 prodotti in questo modo è di circa 10 secondi sul mio laptop. Se si approfondisce questo concetto, non è difficile concludere che in un'ora si possono importare circa 3600 prodotti, mentre l'importazione di 100K prodotti può richiedere circa 30 ore. Sostituire il laptop con un server può migliorare notevolmente la situazione. Potrebbe anche aumentare di diversi fattori. Ma non a livelli incommensurabili. Forse questa lentezza è in parte una delle ragioni per cui è nato il progetto magento/async-import.

Una soluzione radicale per aumentare la velocità di importazione potrebbe essere la scrittura diretta nel database, ma in tal caso si perderebbero tutti i "benefit" legati all'estensibilità di Magento — dovrai fare tutto il "personale" da solo. Tuttavia, ne vale la pena. Se riesco, esaminerò l'approccio con la scrittura diretta nel database nel prossimo articolo.

Fonte: habr.com

Acquista hosting affidabile per siti web con protezione DDoS, VPS VDS server 🔥 Acquista hosting affidabile per siti web con protezione DDoS, VPS VDS server | ProHoster