In einem früheren Artikel habe ich den Prozess des Importierens von Produkten in Magento 2 auf die übliche Weise beschrieben - über Modelle und Repositorys. Das übliche Verfahren zeichnet sich durch eine sehr geringe Datenverarbeitungsgeschwindigkeit aus. Auf meinem Laptop kam ungefähr ein Produkt pro Sekunde heraus. In dieser Fortsetzung betrachte ich eine alternative Möglichkeit zum Importieren eines Produkts - durch direkte Aufzeichnung in der Datenbank unter Umgehung der Standardmechanismen von Magento 2 (Modelle, Fabriken, Repositorys). Die Reihenfolge der Schritte zum Importieren von Produkten kann an jede Programmiersprache angepasst werden, die mit MySQL arbeiten kann.
Haftungsausschluss : Magento verfügt über eine vorgefertigte Funktion zum Importieren von Daten , von der Sie höchstwahrscheinlich genug haben. Wenn Sie jedoch eine umfassendere Kontrolle über den Importvorgang benötigen, müssen Sie nicht nur eine CSV-Datei für das vorbereiten, was sie ist - willkommen bei cat.

Der Code, der sich aus dem Schreiben beider Artikel ergibt, kann im flancer32 / mage2_ext_demo_import Magento-Modul angezeigt werden. Hier sind einige der Einschränkungen, die ich befolgt habe, um den Code des Demomoduls zu vereinfachen:
- Produkte werden nur erstellt, nicht aktualisiert.
- Ein Lagerhaus
- Es werden nur Kategorienamen ohne deren Struktur importiert
- Datenstrukturen entsprechen Version 2.3
JSON zum Importieren eines einzelnen Produkts:
{ "sku": "MVA20D-UBV-3", "name": " 47-29 IEK", "desc": " ...", "desc_short": " 47-29 IEK ...", "price": 5.00, "qty": 25, "categories": [" 1", " 2"], "image_path": "mva20d_ubv_3.png" }
Übersicht über die wichtigsten Importschritte
- Produktregistrierung
- Produkt und Website verlinken
- grundlegende Produktattribute (EAV)
- Bestandsdaten (Menge des auf Lager befindlichen Produkts)
- Medien (Bilder)
- Link zu Katalogkategorien
Produktregistrierung
Grundlegende Produktinformationen finden Sie in catalog_product_entity
:
CREATE TABLE `catalog_product_entity` ( `entity_id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT 'Entity Id', `attribute_set_id` smallint(5) unsigned NOT NULL DEFAULT '0' COMMENT 'Attribute Set ID', `type_id` varchar(32) NOT NULL DEFAULT 'simple' COMMENT 'Type ID', `sku` varchar(64) DEFAULT NULL COMMENT 'SKU', `has_options` smallint(6) NOT NULL DEFAULT '0' COMMENT 'Has Options', `required_options` smallint(5) unsigned NOT NULL DEFAULT '0' COMMENT 'Required Options', `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT 'Creation Time', `updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT 'Update Time', PRIMARY KEY (`entity_id`), KEY `CATALOG_PRODUCT_ENTITY_ATTRIBUTE_SET_ID` (`attribute_set_id`), KEY `CATALOG_PRODUCT_ENTITY_SKU` (`sku`) )
Mindestinformationen zum Erstellen eines Eintrags in der Produktregistrierung:
zusätzlich:
type_id
- wenn nicht type_id
, wird 'simple' verwendet
Für die direkte Aufzeichnung in der Datenbank verwende ich den DB-Adapter von Magento selbst:
function create($sku, $typeId, $attrSetId) { $conn = $this->resource->getConnection(); $table = $this->resource->getTableName('catalog_product_entity'); $bind = [ 'sku' => $sku, 'type_id' => $typeId, 'attribute_set_id' => $attrSetId ]; $conn->insert($table, $bind); $result = $conn->lastInsertId($table); return $result; }
Nachdem Sie ein Produkt in catalog_product_entity
registriert catalog_product_entity
es im Admin-Bereich im Produktraster ( Katalog / Produkte ) catalog_product_entity
.

Produkt und Website verknüpfen
Die Beziehung des Produkts zur Website bestimmt, in welchen Geschäften und in welchen Vitrinen das Produkt vorne erhältlich sein wird.
function linkToWebsite($prodId, $websiteId) { $conn = $this->resource->getConnection(); $table = $this->resource->getTableName('catalog_product_website'); $bind = [ 'product_id' => $prodId, 'website_id' => $websiteId ]; $conn->insert($table, $bind); }

Grundlegende Produktattribute
Ein frisch registriertes Produkt hat noch keinen Namen oder eine Beschreibung. All dies erfolgt über die EAV-Attribute . Hier ist eine Liste grundlegender Produktattribute, die erforderlich sind, um sicherzustellen, dass das Produkt vorne korrekt angezeigt wird:
name
price
description
short_description
status
tax_class_id
url_key
visibility
So wird dem Produkt ein separates Attribut hinzugefügt (die Details zum Abrufen des Bezeichners und des Attributtyps anhand seines Codes werden weggelassen):
public function create($prodId, $attrCode, $attrValue) { $attrId = $attrType = if ($attrId) { $conn = $this->resource->getConnection(); $tblName = 'catalog_product_entity_' . $attrType; $table = $this->resource->getTableName($tblName); $bind = [ 'attribute_id' => $attrId, 'entity_id' => $prodId, 'store_id' => 0, 'value' => $attrValue ]; $conn->insert($table, $bind); } }
Bestimmen Sie anhand des Attributcodes die ID und den Datentyp ( datetime
/ datetime
, decimal
, int
, text
, varchar
). In die entsprechende Tabelle schreiben wir dann die Daten für die administrative Storefront ( store_id = 0
).
Nachdem wir dem Produkt die oben genannten Attribute hinzugefügt haben, wird dieses Bild im Admin-Bereich angezeigt:

Inventardaten
Ab Version 2.3 verfügt Magento gleichzeitig über zwei Tabellensätze, in denen Inventarinformationen (Produktmenge) gespeichert werden:
cataloginventory_*
: alte Struktur;inventory_*
: neue Struktur (MSI - Multi Source Inventory);
Sie müssen beiden Strukturen Inventardaten hinzufügen, weil Die neue Struktur ist noch nicht vollständig unabhängig von der alten (anscheinend wird die Tabelle cataloginventory_stock_status
als inventory_stock_1
für das default
in der neuen Struktur verwendet).
cataloginventory_
Bei der Bereitstellung von Magneto 2.3 haben wir zunächst zwei Einträge in store_website
, die zwei Sites entsprechen - dem administrativen und dem Hauptclient:
website_id|code |name |sort_order|default_group_id|is_default| ----------|-----|------------|----------|----------------|----------| 0|admin|Admin | 0| 0| 0| 1|base |Main Website| 0| 1| 1|
In der Tabelle cataloginventory_stock
haben wir nur einen Eintrag:
stock_id|website_id|stock_name| --------|----------|----------| 1| 0|Default |
Das heißt, in unserer alten Struktur gibt es nur ein "Lager" ( stock
) und es ist an die Verwaltungswebsite gebunden. Das Hinzufügen neuer sources
/ stocks
zum MSI über das Admin- stocks
(neue Struktur) führt nicht zu neuen Einträgen in cataloginventory_stock
.
Bestandsdaten zu Produkten in der alten Struktur werden zunächst in die folgenden Tabellen geschrieben:
cataloginventory_stock_item
cataloginventory_stock_status
cataloginventory_stock_item
function createOldItem($prodId, $qty) { $isQtyDecimal = (((int)$qty) != $qty); $isInStock = ($qty > 0); $conn = $this->resource->getConnection(); $table = $this->resource->getTableName('cataloginventory_stock_item'); $bind = [ 'product_id' => $prodId, 'stock_id' => 1, 'qty' => $qty, 'is_qty_decimal' => $isQtyDecimal, 'is_in_stock' => $isInStock, 'website_id' => 0 ]; $conn->insert($table, $bind); }
cataloginventory_stock_status
function createOldStatus($prodId, $qty) { $isInStock = ($qty > 0); $conn = $this->resource->getConnection(); $table = $this->resource->getTableName('cataloginventory_stock_status'); $bind = [ 'product_id' => $prodId, 'stock_id' => 1, 'qty' => $qty, 'stock_status' => \Magento\CatalogInventory\Api\Data\StockStatusInterface::STATUS_IN_STOCK, 'website_id' => 0 ]; $conn->insert($table, $bind); }
inventar_
Die neue Struktur zum Speichern von Inventardaten enthält zunächst 1 " Quelle " ( inventory_source
):
source_code|name |enabled|description |latitude|longitude|country_id|...| -----------|--------------|-------|--------------|--------|---------|----------|...| default |Default Source| 1|Default Source|0.000000| 0.000000|US |...|
und ein " Lager " ( inventory_stock
):
stock_id|name | --------|-------------| 1|Default Stock|
Eine „ Quelle “ ist ein physischer Speicher für Produkte (der Datensatz enthält physische Koordinaten und eine Postanschrift). Ein " Lager " ist eine logische Vereinigung mehrerer "Quellen" ( inventory_source_stock_link
)
link_id|stock_id|source_code|priority| -------|--------|-----------|--------| 1| 1|default | 1|
auf dessen Ebene ein Link zum Vertriebskanal besteht ( inventory_stock_sales_channel
)
type |code|stock_id| -------|----|--------| website|base| 1|
Gemessen an der Datenstruktur werden verschiedene Arten von Vertriebskanälen angenommen, aber standardmäßig wird nur die Verbindung " Lager " - " Website " verwendet (der Link zur Website wird durch die Website-Codebasis angegeben).
Ein „ Lager “ kann mit mehreren „ Quellen “ verknüpft werden, und eine „ Quelle “ kann mit mehreren „ Lagern “ verknüpft werden (Viele-zu-Viele-Beziehung). Ausnahmen sind default'ovye " source " und " warehouse ". Sie sind nicht an andere Entitäten gebunden (Einschränkung auf Codeebene - der Fehler " Link kann nicht in Bezug auf Standardquelle oder Standardbestand gespeichert werden " stürzt ab). Weitere Informationen zur MSI-Struktur in Magento 2 finden Sie im Artikel " Warehouse Management System mit CQRS und Event Sourcing. Design ".
Ich werde die Standardkonfiguration verwenden und alle Inventarinformationen zur default
hinzufügen, die in dem Vertriebskanal verwendet wird, der der Website mit dem store_website
(entspricht dem Client-Teil des Geschäfts - siehe store_website
):
function createNewItem($sku, $qty) { $conn = $this->resource->getConnection(); $table = $this->resource->getTableName('inventory_source_item'); $bind = [ 'source_code' => 'default', 'sku' => $sku, 'quantity' => $qty, 'status' => \Magento\InventoryApi\Api\Data\SourceItemInterface::STATUS_IN_STOCK ]; $conn->insert($table, $bind); }
Nach dem Hinzufügen von Inventardaten zum Produkt im Admin-Bereich erhalten wir dieses Bild:

Wenn Sie dem Produkt über das Admin-Panel "manuell" Bilder hinzufügen, werden die relevanten Informationen in den folgenden Tabellen aufgezeichnet:
catalog_product_entity_media_gallery
: Medienregistrierung (Bilder und Videodateien);catalog_product_entity_media_gallery_value
: Verknüpfen von Medien mit Produkten und Storefronts (Lokalisierung);catalog_product_entity_media_gallery_value_to_entity
: Binden von Medien nur an Produkte (vermutlich Standardmedieninhalt für das Produkt);catalog_product_entity_varchar
: Hier werden Rollen gespeichert, die das Bild verwenden.
und die Bilder selbst werden im Verzeichnis ./pub/media/catalog/product/x/y/
, wobei x
und y
der erste und zweite Buchstabe des Bilddateinamens sind. Beispielsweise muss die Datei image.png
als ./pub/media/catalog/product/i/m/image.png
werden, damit die Plattform sie als Image bei der Beschreibung von Produkten aus dem Katalog verwenden kann.
Wir registrieren die Mediendatei unter ./pub/media/catalog/product/
(der Vorgang des Platzierens der Datei in diesem Artikel wird nicht berücksichtigt):
function createMediaGallery($imgPathPrefixed) { $attrId = $conn = $this->resource->getConnection(); $table = $this->resource->getTableName('catalog_product_entity_media_gallery'); $bind = [ 'attribute_id' => $attrId, 'value' => $imgPathPrefixed, 'media_type' => 'image', 'disabled' => false ]; $conn->insert($table, $bind); $result = $conn->lastInsertId($table); return $result; }
Bei der Registrierung wird einer neuen Mediendatei eine Kennung zugewiesen.
Wir verknüpfen die registrierte Mediendatei mit dem entsprechenden Produkt für das Standard-Schaufenster:
function createGalleryValue($mediaId, $prodId) { $conn = $this->resource->getConnection(); $table = $this->resource->getTableName('catalog_product_entity_media_gallery_value'); $bind = [ 'value_id' => $mediaId, 'store_id' => 0, 'entity_id' => $prodId, 'label' => null, 'position' => 1, 'disabled' => false ]; $conn->insert($table, $bind); }
Wir verknüpfen die registrierte Mediendatei mit dem entsprechenden Produkt, ohne auf eine Storefront zu verweisen. Es ist nicht klar, wo genau diese Daten verwendet werden und warum es nicht möglich ist, auf die Daten der vorherigen Tabelle zuzugreifen, aber diese Tabelle existiert und die Daten werden beim Hinzufügen eines Bildes zum Produkt darauf geschrieben. Deshalb so.
function createGalleryValueToEntity($mediaId, $prodId) { $conn = $this->resource->getConnection(); $table = $this->resource->getTableName('catalog_product_entity_media_gallery_value_to_entity'); $bind = [ 'value_id' => $mediaId, 'entity_id' => $prodId ]; $conn->insert($table, $bind); }
catalog_product_entity_varchar
Eine Mediendatei kann mit verschiedenen Rollen verwendet werden (der Code des entsprechenden Attributs ist in Klammern angegeben):
- Basis (
image
) - Kleines Bild (
small_image
) - Vorschaubild (
thumbnail
) - Swatch Image (
swatch_image
)
Das Binden von Rollen an eine Mediendatei erfolgt nur in catalog_product_entity_varchar
. Der Bindungscode ähnelt dem Code im Abschnitt " Grundlegende Produktattribute ".
Nach dem Hinzufügen des Bildes zum Produkt im Admin-Bereich sieht es folgendermaßen aus:

Kategorien
Haupttabellen, die Daten nach Kategorie enthalten:
catalog_category_entity
: Register der Kategorien;catalog_category_product
: Zuordnung von Produkten und Kategorien;catalog_category_entity_*
: Werte von EAV-Attributen;
In einer leeren Magento-Anwendung enthält die Kategorieregistrierung zunächst zwei Kategorien (ich habe die Spaltennamen gekürzt: crt
- created_at
, upd
- updated_at
):
entity_id|attribute_set_id|parent_id|crt|upd|path|position|level|children_count| ---------|----------------|---------|---|---|----|--------|-----|--------------| 1| 3| 0|...|...|1 | 0| 0| 1| 2| 3| 1|...|...|1/2 | 1| 1| 0|
Die Kategorie mit id = 1 ist das Stammverzeichnis des gesamten Magento-Verzeichnisses und steht weder im Admin-Bereich noch auf der Vorderseite zur Verfügung. Die Kategorie mit der ID = 2 ( Standardkategorie ) ist die Stammkategorie für den Hauptspeicher der Hauptwebsite ( Hauptwebsite-Speicher ), die während der Anwendungsbereitstellung erstellt wurde (siehe Admin / Stores / All Stores ). Darüber hinaus ist auch die Stammkategorie des Geschäfts an der Vorderseite nicht verfügbar, nur die Unterkategorien.
Da das Thema dieses Artikels immer noch Produktdaten importiert, verwende ich beim Erstellen von Kategorien keine direkte Aufzeichnung in der Datenbank, sondern die von Magento selbst bereitgestellten Klassen (Modelle und Repositorys). Die direkte Aufzeichnung in der Datenbank wird nur zum Verknüpfen des importierten Produkts mit der Kategorie verwendet (die Kategorie wird anhand ihres Namens zugeordnet, die Kategorie-ID wird beim Abgleich extrahiert):
function create($prodId, $catId) { $conn = $this->resource->getConnection(); $table = $this->resource->getTableName('catalog_category_product'); $bind = [ 'category_id' => $catId, 'product_id' => $prodId, ]; $conn->insert($table, $bind); }
Nach dem Hinzufügen eines Produktlinks zu den Kategorien "Kategorie 1" und "Kategorie 2" sehen die Produktdetails im Admin-Bereich ungefähr so aus:

Zusätzliche Aktionen
Nach Abschluss des Datenimports müssen Sie die folgenden zusätzlichen Schritte ausführen:
./bin/magento indexer:reindex
: Ein Aufruf in der Konsole ./bin/magento indexer:reindex
;- URL-Regeneration für Produkte / Kategorien: Sie können die Erweiterung " elgentos / regenerate-catalog-urls " verwenden.
Produkte im Admin-Bereich nach Abschluss weiterer Schritte:

und vorne:

Zusammenfassung
Der gleiche Satz von Produkten (10 Stück) wie im vorherigen Artikel wird mindestens eine Größenordnung schneller importiert (1 Sekunde gegenüber 10). Für eine genauere Schätzung der Geschwindigkeit benötigen Sie eine größere Anzahl von Produkten - mehrere hundert und vorzugsweise Tausende. Trotzdem kann trotz einer so geringen Menge an Eingabedaten der Schluss gezogen werden, dass die Verwendung der von Magento bereitgestellten Tools (Modelle und Repositorys) die Entwicklung der erforderlichen Funktionalität erheblich beschleunigt (hervorheben - deutlich !), Aber erheblich (hervorheben - deutlich !) Reduziert Geschwindigkeit, mit der Daten in die Datenbank gelangen.
Infolgedessen stellte sich heraus, dass das Wasser nass war, und dies ist keine Offenbarung. Jetzt habe ich jedoch Code zum Spielen und möglicherweise interessantere Schlussfolgerungen.