Magento 2: Produkte aus externen Quellen importieren

Magento ist eine E-Commerce-Lösung, d.h. zielt eher auf den Verkauf von Produkten als auf die absatzbegleitende Lagerhaltung, Logistik oder Finanzbuchhaltung ab. Andere Anwendungen (zum Beispiel ERP-Systeme) eignen sich besser als begleitende Anwendungen. Daher stellt sich in der Praxis der Magento-Nutzung häufig die Aufgabe, einen Shop mit diesen anderen Systemen (z. B. 1C) zu integrieren.

Im Großen und Ganzen kann die Integration auf die Datenreplikation reduziert werden durch:

  • Katalog (Produkte, Kategorien);
  • Bestandsdaten (Produktbestände in Lagern und Preise);
  • Kunden;
  • Aufträge;

Magento bietet eine separate Klasse von Objekten zum Bearbeiten von Daten in der Datenbank – Lagerstätten. Aufgrund der Besonderheiten von Magento ist das Hinzufügen von Daten zur Datenbank über Repositorys einfach zu programmieren, aber, sagen wir mal, langsam. In dieser Veröffentlichung betrachte ich die Hauptphasen des programmgesteuerten Hinzufügens eines Produkts zu Magento 2 auf „klassische“ Weise – mithilfe von Repo-Klassen.

Kunden und Bestellungen werden meist in die andere Richtung repliziert – von Magento in externe ERP-Systeme. Daher ist es mit ihnen einfacher, auf der Magento-Seite müssen Sie nur die entsprechenden Daten auswählen und dann „Kugeln flogen von unserer Seite«.

Prinzipien der Datenaufzeichnung in einer Datenbank

Derzeit erfolgt die programmgesteuerte Erstellung von in der Datenbank gespeicherten Objekten in Magento über Fabrikplanung:

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

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

und das Schreiben in die Datenbank erfolgt über Dokumente:

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

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

Der „Factory“- und „Repository“-Ansatz kann für alle wichtigen Modelle im Magento-2-Bereich genutzt werden.

Grundlegende Produktinformationen

Ich schaue mir eine Datenstruktur an, die der Magento 2.3-Version entspricht. Die grundlegendsten Informationen zum Produkt finden Sie in der Tabelle catalog_product_entity (Produktregister):

entity_id
attribute_set_id
type_id
sku
has_options
required_options
created_at
updated_at

Ich bin auf einen Produkttyp beschränkt (type_id='simple'), eine Reihe von Standardattributen (attribute_set_id=4) und ignorieren Sie Attribute has_options и required_options. Da die Attribute entity_id, created_at и updated_at werden automatisch generiert. Um ein neues Produkt hinzuzufügen, müssen wir es lediglich festlegen sku. Ich mache das:

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

und ich bekomme eine Ausnahme:

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

Ich füge den Produktnamen zur Anfrage hinzu und erhalte die Meldung, dass das Attribut fehlt Price. Nach dem Hinzufügen des Preises wird das Produkt zur Datenbank hinzugefügt:

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

Der Produktname wird in der Varchar-Attributtabelle des Produkts gespeichert (catalog_product_entity_varchar), Preis - in der Tabelle catalog_product_entity_decimal. Bevor Sie ein Produkt hinzufügen, empfiehlt es sich, explizit anzugeben, dass wir die administrative Storefront zum Importieren von Daten verwenden:

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

Zusätzliche Attribute

Die Verarbeitung zusätzlicher Produktattribute mit Magento ist ein Vergnügen. EAV-Datenmodell für Hauptentitäten (siehe Tabelle eav_entity_type) ist eines der Hauptmerkmale dieser Plattform. Wir fügen dem Produktmodell einfach die entsprechenden Attribute hinzu:

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

und beim Speichern des Modells über das Repo-Objekt:

$repoProd->save($prod);

Zusätzliche Attribute werden ebenfalls in den entsprechenden Datenbanktabellen gespeichert.

Inventurdaten

Vereinfacht ausgedrückt: die Menge des vorrätigen Produkts. In Magento 2.3 gibt es Strukturen in der Datenbank, die das Format zum Speichern von Inventardaten beschreiben deutlich anders von dem, was vorher passiert ist. Allerdings ist das Hinzufügen der Menge eines vorrätigen Produkts über das Produktmodell nicht viel schwieriger als das Hinzufügen anderer Attribute:

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

Medien

In der Regel unterscheidet sich die mediale Betreuung eines Produkts für einen Kunden in einer Filiale (E-Commerce) von der medialen Betreuung desselben Produkts für einen Mitarbeiter in einem internen Buchhaltungssystem (ERP). Im ersten Fall empfiehlt es sich, das Produkt von Angesicht zu Angesicht zu zeigen, im zweiten Fall reicht es aus, einen allgemeinen Überblick über das Produkt zu geben. Allerdings ist die Übertragung zumindest des primären Bildes eines Produkts durchaus üblich. case beim Importieren von Daten.

Wenn Sie ein Bild über das Admin-Panel hinzufügen, wird das Bild zunächst in einem temporären Verzeichnis gespeichert (./pub/media/tmp/catalog/product) und erst beim Speichern wird das Produkt in das Medienverzeichnis verschoben (./pub/media/catalog/product). Wenn das Bild über das Admin-Panel hinzugefügt wird, wird es außerdem mit Tags versehen 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);

Aus irgendeinem Grund werden die Medien erst verknüpft, nachdem das Produkt zunächst gespeichert und erneut aus dem Repository abgerufen wurde. Und Sie müssen das Attribut angeben label beim Hinzufügen eines Eintrags zur Produktmediengalerie (andernfalls erhalten wir eine Ausnahme Undefined index: label in .../module-catalog/Model/Product/Gallery/CreateHandler.php on line 516).

Kategorie

Oftmals kann sich die Kategorienstruktur des Shops und der Backend-Anwendung bzw. die Platzierung der Produkte darin deutlich unterscheiden. Strategien zur Migration von Daten zu Kategorien und darin enthaltenen Produkten hängen von vielen Faktoren ab. In diesem Beispiel bleibe ich bei Folgendem:

  • Backend- und Store-Kategorien werden namentlich verglichen;
  • Wenn eine Kategorie importiert wird, die nicht im Store vorhanden ist, wird sie unter der Stammkategorie erstellt (Default Category) und seine weitere Positionierung im Filialkatalog wird manuell übernommen;
  • Ein Produkt wird erst dann einer Kategorie zugeordnet, wenn es im Shop angelegt wird (erster Import);

Grundlegende Informationen zur Kategorie finden Sie in der Tabelle catalog_category_entity (Kategorienkatalog). Erstellen einer Kategorie in Magento:

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

Die Verknüpfung eines Produkts mit einer Kategorie erfolgt über die Kategorie-ID und die Produkt-SKU:

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

Insgesamt

Das Schreiben von Code zum programmgesteuerten Hinzufügen eines Produkts zu Magento 2 ist recht einfach. Ich habe alles oben Gesagte in einem Demo-Modul zusammengefasst“lancer32/mage2_ext_demo_import". Es gibt nur einen Konsolenbefehl im Modul fl32:import:prod, wodurch die in der JSON-Datei beschriebenen Produkte importiert werden../etc/data/products.json„:

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

Bilder zum Import finden Sie im Katalog ./etc/data/img.

Der Import von 10 Produkten mit dieser Methode dauert auf meinem Laptop etwa 10 Sekunden. Wenn wir diese Idee weiterentwickeln, kommt man leicht zu dem Schluss, dass etwa 3600 Produkte pro Stunde importiert werden können und der Import von 100 Produkten etwa 30 Stunden dauern kann. Durch den Ersatz eines Laptops durch einen Server können Sie die Situation etwas entschärfen. Vielleicht sogar mehrmals. Aber nicht um Größenordnungen. Vielleicht ist diese Geschwindigkeit und Langsamkeit in gewisser Weise einer der Gründe für die Entstehung des Projekts magento/async-import.

Eine radikale Lösung zur Erhöhung der Importgeschwindigkeit könnte der direkte Eintrag in die Datenbank sein, allerdings gehen in diesem Fall alle „Goodies“ hinsichtlich der Erweiterbarkeit von Magento verloren – Sie müssen alles „Erweiterte“ selbst erledigen. Es lohnt sich jedoch. Wenn es klappt, werde ich im nächsten Artikel über den Ansatz mit direktem Schreiben in die Datenbank nachdenken.

Source: habr.com

Kommentar hinzufügen