Magento 2: Produkter direkt an d'Datebank importéieren

В fréieren Artikel Ech beschriwwen de Prozess fir Produkter an Magento 2 z'importéieren op déi üblech Manéier - duerch Modeller a Repositories. Déi üblech Method huet eng ganz niddereg Dateveraarbechtungsgeschwindegkeet. Mäi Laptop huet ongeféier ee Produkt pro Sekonn produzéiert. An dëser Fortsetzung betruechten ech eng alternativ Manéier fir e Produkt z'importéieren - duerch direkten Entrée an d'Datebank, andeems d'Standard Magento 2 Mechanismen (Modeller, Fabriken, Repositories) ëmgoen. D'Sequenz vun de Schrëtt fir Produkter ze importéieren kann un all Programméierungssprooch ugepasst ginn, déi mat MySQL funktionéiere kann.

Verzichterklärung: Magento huet prett-feieren Funktionalitéit fir Datenimport an, Wahrscheinlechkeet, et wäert genuch fir Iech ginn. Wann Dir awer méi komplett Kontroll iwwer den Importprozess braucht, net limitéiert op d'Virbereedung vun enger CSV-Datei fir wat Dir hutt, wëllkomm op d'Kaz.

Magento 2: Produkter direkt an d'Datebank importéieren

De Code deen aus der Schreiwen vun deenen zwee Artikelen entstinn kann am Magento Modul gekuckt ginn "flancer32/mage2_ext_demo_import". Hei sinn e puer Restriktiounen déi ech gefollegt hunn fir den Demo Modul Code ze vereinfachen:

  • Produkter ginn nëmmen erstallt, net aktualiséiert.
  • Ee Lagerhaus
  • Nëmmen Kategorie Nimm ginn importéiert, ouni hir Struktur
  • Datestrukture entspriechen der Versioun 2.3

JSON fir en eenzegt Produkt z'importéieren:

{
  "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"
}

Iwwersiicht vun den Haapt Etappe vun Import

  • Aschreiwung vum Produkt selwer
  • Verbindung tëscht Produkt a Websäit
  • Basis Produktattributer (EAV)
  • Inventardaten (Quantitéit vum Produkt op Lager)
  • Medien (Fotoen)
  • Verbindung mat Katalog Kategorien

Produit Aschreiwung

Basis Produktinformatioun kann fonnt ginn an 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`)
)

D'Mindest Informatioun déi néideg ass fir eng Entrée am Produktregister ze kreéieren ass:

  • attribute_set_id
  • sku

zousätzlech:

  • type_id - wa mir et net spezifizéieren, da gëtt 'einfach' benotzt

Fir direkt an d'Datebank ze schreiwen, benotzen ech den DB Adapter vu Magento selwer:

function create($sku, $typeId, $attrSetId)
{
    /** @var MagentoFrameworkAppResourceConnection $this->resource */
    /** @var MagentoFrameworkDBAdapterPdoMysql $conn */
    $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;
}

No der Enregistréiere vum Produit mat catalog_product_entity et gëtt siichtbar am Admin Panel, am Produktraster (Katalog / Produkter).

Magento 2: Produkter direkt an d'Datebank importéieren

Relatioun tëscht Produit an Websäit

D'Associatioun vum Produkt mam Site bestëmmt a wéi enge Geschäfter an Affichage de Produit op der Front verfügbar ass.

function linkToWebsite($prodId, $websiteId)
{
    /** @var MagentoFrameworkAppResourceConnection $this->resource */
    /** @var MagentoFrameworkDBAdapterPdoMysql $conn */
    $conn = $this->resource->getConnection();
    $table = $this->resource->getTableName('catalog_product_website');
    $bind = [
        'product_id' => $prodId,
        'website_id' => $websiteId
    ];
    $conn->insert($table, $bind);
}

Magento 2: Produkter direkt an d'Datebank importéieren

Basis Produit Attributer

Dat nei registréiert Produkt huet nach keen Numm oder Beschreiwung. All dëst gëtt duerchgefouert EAV Attributer. Hei ass eng Lëscht mat Basis Produktattributer déi gebraucht ginn fir datt de Produkt richteg op der viischter ugewise gëtt:

  • name
  • price
  • description
  • short_description
  • status
  • tax_class_id
  • url_key
  • visibility

E separaten Attribut gëtt un e Produkt wéi dëst bäigefüügt (d'Detailer fir den Identifizéierer an den Typ vum Attribut aus sengem Code ze kréien sinn ausgelooss):

public function create($prodId, $attrCode, $attrValue)
{
    $attrId = /* get attribute ID by attribute code */
    $attrType = /* get attribute type [datetime|decimal|int|text|varchar]) by attribute code */
    if ($attrId) {
        /** @var MagentoFrameworkAppResourceConnection $this->resource */
        /** @var MagentoFrameworkDBAdapterPdoMysql $conn */
        $conn = $this->resource->getConnection();
        $tblName = 'catalog_product_entity_' . $attrType;
        $table = $this->resource->getTableName($tblName);
        $bind = [
            'attribute_id' => $attrId,
            'entity_id' => $prodId,
            /* put all attributes to default store view with id=0 (admin) */
            'store_id' => 0,
            'value' => $attrValue
        ];
        $conn->insert($table, $bind);
    }
}

Mat dem Attributcode bestëmmen mir seng ID an Datentyp (datetime, decimal, int, text, varchar), da schreift d'Donnéeën fir d'administrativ Fënster an déi entspriechend Tabell (store_id = 0).

Nodeems Dir déi uewe genannten Attributer zum Produkt bäigefüügt hutt, kritt Dir dëst Bild an der Admin Panel:

Magento 2: Produkter direkt an d'Datebank importéieren

Inventar Daten

Vun der Versioun 2.3 a Magento un, ginn et zwee parallel Sets vun Dëscher déi d'Lagerung vun Inventarinformatioun ubidden (Produktquantitéit):

  • cataloginventory_*: al Struktur;
  • inventory_*: nei Struktur (MSI - Multi Source Inventar);

Dir musst Inventardaten op béid Strukturen addéieren, well déi nei Struktur ass nach net komplett onofhängeg vun der aler (et ass ganz wahrscheinlech datt fir default Lager an der neier Struktur ass en Dësch involvéiert cataloginventory_stock_status wéi inventory_stock_1).

Kataloginventar_

Wann Dir Magneto 2.3 ofsetzt, hu mir am Ufank 2 Entréen an store_website, dat entsprécht zwee Siten - administrativ an Haaptcliente:

website_id|code |name        |sort_order|default_group_id|is_default|
----------|-----|------------|----------|----------------|----------|
         0|admin|Admin       |         0|               0|         0|
         1|base |Main Website|         0|               1|         1|

Dësch cataloginventory_stock mir hunn nëmmen eng Entrée:

stock_id|website_id|stock_name|
--------|----------|----------|
       1|         0|Default   |

Dat ass, an eiser aler Struktur gëtt et nëmmen een "Lagerhaus" (stock) an et ass mat der administrativer Websäit verlinkt. Füügt nei duerch den Admin Panel sources/stocks an MSI (nei Struktur) féiert net zu neien Entréen an cataloginventory_stock.

Inventardaten iwwer Produkter an der aler Struktur ginn ufanks an Tabellen opgeholl:

  • cataloginventory_stock_item
  • cataloginventory_stock_status

cataloginventory_stock_item

function createOldItem($prodId, $qty)
{
    $isQtyDecimal = (((int)$qty) != $qty);
    $isInStock = ($qty > 0);
    /** @var MagentoFrameworkAppResourceConnection $this->resource */
    /** @var MagentoFrameworkDBAdapterPdoMysql $conn */
    $conn = $this->resource->getConnection();
    $table = $this->resource->getTableName('cataloginventory_stock_item');
    $bind = [
        'product_id' => $prodId,
        /* we use one only stock in 'cataloginventory' structure by default */
        'stock_id' => 1,
        'qty' => $qty,
        'is_qty_decimal' => $isQtyDecimal,
        'is_in_stock' => $isInStock,
        /* default stock is bound to admin website (see `cataloginventory_stock`) */
        'website_id' => 0
    ];
    $conn->insert($table, $bind);
}

cataloginventory_stock_status

function createOldStatus($prodId, $qty)
{
    $isInStock = ($qty > 0);
    /** @var MagentoFrameworkAppResourceConnection $this->resource */
    /** @var MagentoFrameworkDBAdapterPdoMysql $conn */
    $conn = $this->resource->getConnection();
    $table = $this->resource->getTableName('cataloginventory_stock_status');
    $bind = [
        'product_id' => $prodId,
        /* we use one only stock in 'cataloginventory' structure by default */
        'stock_id' => 1, 
        'qty' => $qty,
        'stock_status' => MagentoCatalogInventoryApiDataStockStatusInterface::STATUS_IN_STOCK,
        /* default stock is bound to admin website (see `cataloginventory_stock`) */
        'website_id' => 0 
    ];
    $conn->insert($table, $bind);
}

Inventar_

Am Ufank enthält déi nei Struktur fir Inventardaten ze späicheren 1 "Quell"(inventory_source):

source_code|name          |enabled|description   |latitude|longitude|country_id|...|
-----------|--------------|-------|--------------|--------|---------|----------|...|
default    |Default Source|      1|Default Source|0.000000| 0.000000|US        |...|

an een"Lager"(inventory_stock):

stock_id|name         |
--------|-------------|
       1|Default Stock|

«Source» representéiert déi kierperlech Lagerung fir Produkter (de Rekord enthält kierperlech Koordinaten a Mailadress). "Lager"ass eng logesch Unioun vu verschiddene "Quellen" (inventory_source_stock_link)

link_id|stock_id|source_code|priority|
-------|--------|-----------|--------|
      1|       1|default    |       1|

um Niveau op deem d'Verbindung zum Verkafskanal geschitt (inventory_stock_sales_channel)

type   |code|stock_id|
-------|----|--------|
website|base|       1|

No der Datestruktur beurteelen, ginn verschidden Aarte vu Verkafskanäl ugeholl, awer par défaut nëmmen d'Verbindung "rembourséiere"-"Websäit"(de Link op d'Websäit follegt de Websäitcode - base).

Eent "Lager"kann op e puer verbonne ginn"zu Quellen"an een"Quell"- zu e puer"Lagerhaiser"(vill-zu-vill Relatioun). D'Ausnahmen sinn Standard "Quell"An"Lager". Si sinn net mat aneren Entitéite verlinkt (Begrenzung um Codeniveau - de Feeler "Kann de Link net am Zesummenhang mat Standardquell oder Default Stock späicheren"). Méi Detailer iwwer d'MSI Struktur am Magento 2 fannt Dir am Artikel "Warehouse Management System benotzt CQRS an Event Sourcing. Design".

Ech wäert d'Standardkonfiguratioun benotzen an all Inventarinformatioun un d'Quell addéieren default, deen am Verkafskanal involvéiert ass mat der Websäit mam Code base (entsprécht dem Frontend vum Geschäft - kuckt store_website):

function createNewItem($sku, $qty)
{
    /** @var MagentoFrameworkAppResourceConnection $this->resource */
    /** @var MagentoFrameworkDBAdapterPdoMysql $conn */
    $conn = $this->resource->getConnection();
    $table = $this->resource->getTableName('inventory_source_item');
    $bind = [
        'source_code' => 'default',
        'sku' => $sku,
        'quantity' => $qty,
        'status' => MagentoInventoryApiApiDataSourceItemInterface::STATUS_IN_STOCK
    ];
    $conn->insert($table, $bind);
}

Nodeems Dir Inventardaten zum Produkt an der Admin Panel bäigefüügt hutt, kritt Dir dëst Bild:

Magento 2: Produkter direkt an d'Datebank importéieren

Medien

Wann "manuell" e Bild un e Produkt duerch den Admin Panel bäigefüügt gëtt, gëtt déi relevant Informatioun an de folgenden Tabellen opgeschriwwen:

  • catalog_product_entity_media_gallery: Medienregistrierung (Biller a Videodateien);
  • catalog_product_entity_media_gallery_value: Medien mat Produkter a Vitrine verbannen (Lokaliséierung);
  • catalog_product_entity_media_gallery_value_to_entity: Verlinkt Medien nëmme mat Produkter (viraussiichtlech Standard Medieninhalt fir de Produit);
  • catalog_product_entity_varchar: D'Rollen an deenen d'Bild benotzt gëtt ginn hei gespäichert;

an d'Biller selwer ginn an den Dossier gespäichert ./pub/media/catalog/product/x/y/wou x и y - déi éischt an zweet Buschtawen vum Bilddatei Numm. Zum Beispill, Fichier image.png soll gespäichert ginn als ./pub/media/catalog/product/i/m/image.png, sou datt d'Plattform et als Bild benotze kann wann Dir Produkter aus dem Katalog beschreiwen.

Registréiert gepost an ./pub/media/catalog/product/ Mediendatei (de Prozess fir d'Datei selwer ze placéieren gëtt net an dësem Artikel diskutéiert):

function createMediaGallery($imgPathPrefixed)
{
    $attrId = /* get attribute ID by attribute code 'media_gallery' */
    /** @var MagentoFrameworkAppResourceConnection $this->resource */
    /** @var MagentoFrameworkDBAdapterPdoMysql $conn */
    $conn = $this->resource->getConnection();
    $table = $this->resource->getTableName('catalog_product_entity_media_gallery');
    $bind = [
        'attribute_id' => $attrId,
        'value' => $imgPathPrefixed,
        /* 'image' or 'video' */
        'media_type' => 'image',
        'disabled' => false
    ];
    $conn->insert($table, $bind);
    $result = $conn->lastInsertId($table);
    return $result;
}

Wann registréiert ass, gëtt eng nei Mediendatei en Identifizéierer zougewisen.

Mir associéieren déi registréiert Mediendatei mam entspriechende Produkt fir de Standard Storefront:

function createGalleryValue($mediaId, $prodId)
{
    /** @var MagentoFrameworkAppResourceConnection $this->resource */
    /** @var MagentoFrameworkDBAdapterPdoMysql $conn */
    $conn = $this->resource->getConnection();
    $table = $this->resource->getTableName('catalog_product_entity_media_gallery_value');
    $bind = [
        'value_id' => $mediaId,
        /* use admin store view by default */
        'store_id' => 0,
        'entity_id' => $prodId,
        'label' => null,
        /* we have one only image */
        'position' => 1,
        'disabled' => false
    ];
    $conn->insert($table, $bind);
}

Mir associéieren déi registréiert Mediendatei mam entspriechende Produkt ouni un all Storefront gebonnen ze sinn. Et ass net kloer wou genau dës Donnéeën benotzt ginn a firwat et onméiglech ass op d'Donnéeën aus der viregter Tabelle ze kommen, awer dës Tabell existéiert an d'Donnéeën ginn drop geschriwwe wann e Bild zum Produkt bäigefüügt gëtt. Also dat ass et.

function createGalleryValueToEntity($mediaId, $prodId)
{
    /** @var MagentoFrameworkAppResourceConnection $this->resource */
    /** @var MagentoFrameworkDBAdapterPdoMysql $conn */
    $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

Eng Mediendatei ka mat verschiddene Rollen benotzt ginn (de entspriechende Attributcode gëtt an Klammeren uginn):

  • Base (image)
  • Kleng Bild (small_image)
  • Thumbnail (thumbnail)
  • Swatch Bild (swatch_image)

Rollen op eng Mediendatei verknëppelen ass genau dat wat geschitt an catalog_product_entity_varchar. De verbindleche Code ass ähnlech wéi de Code am "Basis Produit Attributer".

Nodeems Dir e Bild zum Produkt an der Admin Panel bäigefüügt hutt, gesäit et esou aus:

Magento 2: Produkter direkt an d'Datebank importéieren

Kategorien

Haapttabellen mat Daten no Kategorie:

  • catalog_category_entity: Register vun Kategorien;
  • catalog_category_product: Verbindung tëscht Produkter a Kategorien;
  • catalog_category_entity_*: EAV Attribut Wäerter;

Am Ufank, an enger eidel Magento Applikatioun, enthält d'Kategorie Registry 2 Kategorien (ech hunn d'Kolonnnimm verkierzt: 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|

D'Kategorie mat id = 1 ass d'Wuerzel vum ganze Magento Katalog an ass weder an der Admin Panel oder op der éischter Säit verfügbar. Kategorie mat id=2 (Standard Kategorie) ass d'Rootkategorie fir den Haaptgeschäft vun der Haaptsäit (Haaptsäit Store) erstallt wann d'Applikatioun ofgebaut gëtt (kuckt. Admin / Stores / All Stores). Ausserdeem ass d'Rootkategorie vum Geschäft selwer och net op der viischter, nëmmen seng Ënnerkategorien.

Well d'Thema vun dësem Artikel nach ëmmer Daten iwwer Produkter importéiert, wäert ech net direkten Entrée an d'Datebank benotzen wann Dir Kategorien erstellt, awer d'Klassen benotzen déi vum Magento selwer geliwwert gëtt (Modeller a Repositories). Direkten Entrée an d'Datebank gëtt nëmme benotzt fir den importéierte Produkt mat enger Kategorie ze associéieren (d'Kategorie gëtt mat hirem Numm ugepasst, an d'Kategorie-ID gëtt wärend dem Matching zréckgezunn):

function create($prodId, $catId)
{
    /** @var MagentoFrameworkAppResourceConnection $this->resource */
    /** @var MagentoFrameworkDBAdapterPdoMysql $conn */
    $conn = $this->resource->getConnection();
    $table = $this->resource->getTableName('catalog_category_product');
    $bind = [
        'category_id' => $catId,
        'product_id' => $prodId,
    ];
    $conn->insert($table, $bind);
}

Nodeems Dir e Produktlink an d'Kategorien "Kategorie 1" an "Kategorie 2" bäigefüügt hutt, kucken d'Produktdetailer an der Admin Panel sou eppes aus:

Magento 2: Produkter direkt an d'Datebank importéieren

Zousätzlech Aktiounen

Wann den Datenimport fäerdeg ass, musst Dir déi folgend zousätzlech Schrëtt ausfëllen:

  • daten Indexéierung: ruffen an der Konsol ./bin/magento indexer:reindex;
  • URLen fir Produkter / Kategorien regeneréieren: Dir kënnt d'Extensioun "elgentos/regenerate-catalog-urls«

Produkter am Admin Panel nodeems Dir zousätzlech Aktiounen ausféiert:

Magento 2: Produkter direkt an d'Datebank importéieren

an un der viischter:

Magento 2: Produkter direkt an d'Datebank importéieren

Summary

Deeselwechte Set vu Produkter (10 Stécker) wéi am virege Artikel gëtt op d'mannst eng Uerdnung vun der Gréisst méi séier importéiert (1 Sekonn géint 10). Fir d'Geschwindegkeet méi genau ze schätzen, brauch Dir eng méi grouss Zuel vu Produkter - e puer honnert, oder besser nach Dausende. Wéi och ëmmer, och mat sou enger klenger Gréisst vun Inputdaten, kënne mir schléissen datt d'Benotzung vun den Tools, déi vum Magento geliwwert ginn (Modeller a Repositories) bedeitend ass (ech betounen - vill!) beschleunegt d'Entwécklung vun der erfuerderter Funktionalitéit, awer gläichzäiteg wesentlech (ech betounen - vill!) reduzéieren d'Geschwindegkeet mat där d'Donnéeën an d'Datebank kommen.

Als Resultat huet d'Waasser sech als naass erausgestallt an dëst ass keng Offenbarung. Wéi och ëmmer, elo hunn ech de Code fir mat ze spillen a vläicht zu e puer méi interessant Conclusiounen ze kommen.

Source: will.com