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.

Клиенты и заказы реплицируются, обычно, в другую сторону — из Magento во внешние ERP-системы. Поэтому с ними попроще, на стороне Magento нужно просто выбрать соответствующие данные, а дальше — «с нашей стороны пули вылетели«.

Принципы записи данных в базу

На данный момент создание сохраняемых в базе объектов программным способом в Magento делается через Factory:

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

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

а запись в базу — через Repository:

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

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

Подход с использованием «Factory» и «Repository» можно использовать для всех основных моделей в предметной области Magento 2.

Базовая информация о продукте

Я рассматриваю структуру данных, соответствующую версии Magento 2.3. Самая основная информация о продукте находится в таблице catalog_product_entity (реестр продуктов):

entity_id
attribute_set_id
type_id
sku
has_options
required_options
created_at
updated_at

Ограничиваюсь одним типом продукта (type_id='simple'), набором атрибутов по-умолчанию (attribute_set_id=4) и игнорирую атрибуты has_options und required_options. Так как атрибуты 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-Server 🔥 Kaufen Sie zuverlässiges Hosting für Websites mit DDoS-Schutz, VPS VDS-Server | ProHoster