Magento 2: Produkte aus externen Quellen importieren

Magento ist eine E-Commerce-Lösung, die stĂ€rker auf den Verkauf von Produkten ausgerichtet ist als auf begleitende Lager-, Logistik- oder Finanzbuchhaltungsfunktionen. FĂŒr letztere sind andere Anwendungen (wie ERP-Systeme) besser geeignet. Daher tritt in der Praxis der Verwendung von Magento hĂ€ufig die Notwendigkeit auf, den Shop mit diesen anderen Systemen (z. B. 1C) zu integrieren.

Beim Großen und Ganzen kann die Integration auf die Replikation von Daten beschrĂ€nkt werden, und zwar:

  • Katalog (Produkte, Kategorien);
  • Bestandsdaten (LagerbestĂ€nde und Preise);
  • Kunden;
  • Bestellungen;

Magento bietet zur Manipulation von Daten in der Datenbank eine spezielle Objektklasse an — Repository. Aufgrund der spezifischen Merkmale von Magento ist das HinzufĂŒgen von Daten zur Datenbank ĂŒber Repositories leicht codebar, erfolgt jedoch, sagen wir mal, nicht besonders schnell. In diesem Beitrag betrachte ich die grundlegenden Schritte zur programmatischen HinzufĂŒgung eines Produkts in Magento 2 auf die „klassische“ Weise – unter Verwendung von Repository-Klassen.

Kunden und Bestellungen werden in der Regel in die andere Richtung repliziert — von Magento in externe ERP-Systeme. Daher ist es einfacher, auf der Magento-Seite einfach die entsprechenden Daten auszuwĂ€hlen, und dann — „von unserer Seite flogen die Kugeln«.

Prinzipien der Datenspeicherung in der Datenbank

Aktuell erfolgt die Erstellung von in der Datenbank gespeicherten Objekten programmgesteuert in Magento ĂŒber Factory:

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

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

und die Speicherung in der Datenbank — ĂŒber Repository:

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

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

Der Ansatz mit der Verwendung von „Factory“ und „Repository“ kann fĂŒr alle Hauptmodelle im Themenbereich Magento 2 verwendet werden.

Grundinformationen zum Produkt

Ich betrachte die Datenstruktur, die der Version Magento 2.3 entspricht. Die grundlegendsten Informationen zum Produkt befinden sich in der Tabelle catalog_product_entity (Produktregister):

entity_id
attribute_set_id
type_id
sku
has_options
required_options
created_at
updated_at

Ich beschrĂ€nke mich auf einen Produkttyp (type_id='simple'), einem Satz von Standardattributen (attribute_set_id=4) und ignoriere die Attribute has_options und required_options. Da die Attribute entity_id, created_at und updated_at werden automatisch generiert, sodass es im Grunde genommen ausreicht, um ein neues Produkt hinzuzufĂŒgen, nur zu sku. Ich mache es so:

/** @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 erhalte eine Ausnahme:

Der "Produktname"-Attributwert ist leer. Setzen Sie das Attribut und versuchen Sie es erneut.

Ich fĂŒge im Antrag den Produktnamen hinzu und erhalte die Nachricht, dass ein Attribut fehlt. Preis. Nach der Preisangabe wird das Produkt in der Datenbank abgelegt:

$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), der Preis wird in der Tabelle catalog_product_entity_decimal. Vor dem HinzufĂŒgen des Produkts sollte klar angegeben werden, dass wir das Admin-Frontend fĂŒr den Datenimport verwenden:

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

ZusÀtzliche Attribute

Die Verarbeitung zusĂ€tzlicher Produktattribute mit Magento ist ein VergnĂŒgen. Das EAV-Datenmodell fĂŒr die HauptentitĂ€ten (siehe Tabelle eav_entity_type) ist eines der Hauptmerkmale dieser Plattform. Einfach die entsprechenden Attribute zum Produktmodell hinzufĂŒgen:

$prodEntity->setData('description', $desc);
$prodEntity->setData('short_description', $desc_short);
// oder
$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.

Bestandsdaten

Einfach gesagt – die Menge des Produkts auf Lager. In Magento 2.3 unterscheiden sich die Datenbankstrukturen, die das Format zur Speicherung der Bestandsdaten beschreiben, deutlich von dem, was zuvor war. Dennoch ist das HinzufĂŒgen der Produktmenge auf Lager ĂŒber das Produktmodell nicht viel komplizierter 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 Begleitung des Produkts fĂŒr den Kunden im GeschĂ€ft (E-Commerce) von der medialen Begleitung desselben Produkts fĂŒr Mitarbeiter im internen Buchhaltungssystem (ERP). Im ersten Fall ist es wĂŒnschenswert, das „Produkt ansprechend zu prĂ€sentieren“, wĂ€hrend im zweiten Fall eine allgemeine Vorstellung vom Produkt ausreicht. Dennoch ist der Transfer zumindest des primĂ€ren Produktbildes – ein durchaus gĂ€ngiger Fall beim Import von Daten.

Beim HinzufĂŒgen eines Bildes ĂŒber das Admin-Panel wird das Bild zunĂ€chst im temporĂ€ren Verzeichnis gespeichert (./pub/media/tmp/catalog/product) und wird erst beim Speichern des Produkts in das Medienverzeichnis verschoben (./pub/media/catalog/product). Zudem werden beim HinzufĂŒgen ĂŒber das Admin-Panel Bildtags festgelegt. image, kleines_Bild, Miniaturansicht, Farbvarianten_Bild.

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

Irgendwie wird das Medium nur nach dem vorherigen Speichern des Produkts und dessen erneuter Abruf aus dem Repository hinzugefĂŒgt. Außerdem muss das Attribut angegeben werden. Bezeichnung beim HinzufĂŒgen eines Eintrags zur Mediengalerie des Produkts (ansonsten erhalten wir eine Ausnahme: Undefined index: label in .../module-catalog/Model/Product/Gallery/CreateHandler.php in Zeile 516).

Kategorien

Oft unterscheiden sich die Struktur der Kategorien im Shop und der Backend-Anwendung oder deren Produktplatzierung erheblich. Die Strategien zum Übertragen von Daten ĂŒber Kategorien und Produkte hĂ€ngen von vielen Faktoren ab. In diesem Beispiel halte ich mich an Folgendes:

  • Die Kategorien im Backend und im Shop werden nach ihrem Namen zugeordnet;
  • Wenn eine Kategorie importiert wird, die im Shop nicht vorhanden ist, wird sie unter der Wurzelkategorie erstellt (Standardkategorie) und ihre weitere Positionierung im Katalog des Shops erfolgt manuell;
  • Die Zuweisung des Produkts zur Kategorie erfolgt nur bei seiner Erstellung im Shop (erstem Import);

Die Hauptinformationen zur Kategorie befinden sich in der Tabelle catalog_category_entity (Katalog der Kategorien). Erstellung einer Kategorie in Magento:

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

Die Zuordnung eines Produkts zur Kategorie erfolgt ĂŒber die Kategorie-ID und die SKU des Produkts:

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

Gesamt

Es ist nicht besonders schwierig, einen Code zum programmgesteuerten HinzufĂŒgen eines Produkts in Magento 2 zu schreiben. Alles, was oben gesagt wurde, habe ich in ein Demomodul "flancer32/mage2_ext_demo_import" zusammengefasst. Im Modul gibt es nur einen Konsolenbefehl fl32:import:prod, der Produkte importiert, die in der JSON-Datei "./etc/data/products.json«:

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

Die Bilder fĂŒr den Import befinden sich im Verzeichnis ./etc/data/img.

Die Importzeit fĂŒr 10 Produkte auf diese Weise betrĂ€gt etwa 10 Sekunden auf meinem Laptop. Wenn man diesen Gedanken weiterfĂŒhrt, ist es nicht schwer zu dem Schluss zu kommen, dass man pro Stunde etwa 3600 Produkte importieren kann, und der Import von 100.000 Produkten kann ungefĂ€hr 30 Stunden in Anspruch nehmen. Der Austausch des Laptops gegen einen Server kann die Situation etwas verbessern. Vielleicht sogar um ein Vielfaches. Aber nicht um GrĂ¶ĂŸenordnungen. Möglicherweise ist diese langsame Geschwindigkeit teilweise eine der Ursachen fĂŒr das Projekt magento/async-import.

Eine drastische Lösung zur Steigerung der Importgeschwindigkeit könnte die direkte Speicherung in der Datenbank sein, aber dabei gehen alle Vorteile der Skalierbarkeit von Magento verloren – alles, was ĂŒber die grundlegenden Funktionen hinausgeht, mĂŒsste man selbst implementieren. Dennoch ist es das wert. Falls möglich, werde ich in einem zukĂŒnftigen Artikel den Ansatz mit direkter Datenbankeintragung nĂ€her betrachten.

Quelle: habr.com

Kaufen Sie zuverlĂ€ssiges Hosting fĂŒr Websites mit DDoS-Schutz, VPS VDS-Servern đŸ”„ Kaufen Sie zuverlĂ€ssiges Hosting fĂŒr Websites mit DDoS-Schutz, VPS VDS-Servern | ProHoster