Magento 2: voer produkte direk in die databasis in

В vorige artikel Ek het die proses om produkte in Magento 2 in te voer op die gewone manier beskryf – deur modelle en bewaarplekke. Die gewone metode het 'n baie lae dataverwerkingspoed. My skootrekenaar het ongeveer een produk per sekonde geproduseer. In hierdie voortsetting oorweeg ek 'n alternatiewe manier om 'n produk in te voer - deur direkte toegang tot die databasis, om die standaard Magento 2-meganismes (modelle, fabrieke, bewaarplekke) te omseil. Die volgorde van stappe om produkte in te voer kan aangepas word by enige programmeertaal wat met MySQL kan werk.

Vrywaring: Magento het klaargemaakte funksionaliteit vir data invoer en, heel waarskynlik, sal dit genoeg wees vir jou. As jy egter meer volledige beheer oor die invoerproses benodig, nie beperk tot die voorbereiding van 'n CSV-lêer vir wat jy het nie, welkom om te kat.

Magento 2: voer produkte direk in die databasis in

Die kode wat voortspruit uit die skryf van beide artikels kan in die Magento-module bekyk word "flancer32/mage2_ext_demo_import". Hier is 'n paar beperkings wat ek gevolg het om die demo-module-kode te vereenvoudig:

  • Produkte word slegs geskep, nie opgedateer nie.
  • Een pakhuis
  • Slegs kategoriename word ingevoer, sonder hul struktuur
  • Datastrukture voldoen aan weergawe 2.3

JSON vir die invoer van 'n enkele produk:

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

Oorsig van die hoofstadia van invoer

  • registrasie van die produk self
  • verband tussen produk en webwerf
  • basiese produk eienskappe (EAV)
  • voorraaddata (hoeveelheid produk in voorraad)
  • media (prente)
  • verband met kataloguskategorieë

Produk Registrasie

Basiese produkinligting kan gevind word 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`)
)

Die minimum inligting wat benodig word om 'n inskrywing in die produkregister te skep, is:

  • attribute_set_id
  • sku

bykomende:

  • type_id - as ons dit nie spesifiseer nie, sal 'eenvoudig' gebruik word

Om direk na die databasis te skryf, gebruik ek die DB-adapter van Magento self:

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;
}

Na die registrasie van die produk met catalog_product_entity dit word sigbaar in die administrasiepaneel, in die produkrooster (Katalogus/Produkte).

Magento 2: voer produkte direk in die databasis in

Verwantskap tussen produk en webwerf

Die assosiasie van die produk met die webwerf bepaal in watter winkels en uitstallings die produk aan die voorkant beskikbaar sal wees.

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: voer produkte direk in die databasis in

Basiese produk eienskappe

Die nuut geregistreerde produk het nog nie 'n naam of beskrywing nie. Dit alles word deur gedoen EAV eienskappe. Hier is 'n lys van basiese produkeienskappe wat nodig is om die produk korrek op die voorkant te vertoon:

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

'n Aparte eienskap word by 'n produk soos hierdie gevoeg (die besonderhede van die verkryging van die identifiseerder en tipe kenmerk uit sy kode word weggelaat):

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);
    }
}

Deur die kenmerkkode te gebruik, bepaal ons sy id en datatipe (datetime, decimal, int, text, varchar), skryf dan die data vir die administratiewe venster in die toepaslike tabel (store_id = 0).

Nadat u die bogenoemde eienskappe by die produk gevoeg het, kry u hierdie prentjie in die administrasiepaneel:

Magento 2: voer produkte direk in die databasis in

Voorraaddata

Vanaf weergawe 2.3 in Magento is daar twee parallelle stelle tabelle wat die berging van voorraadinligting (produkhoeveelheid) verskaf:

  • cataloginventory_*: ou struktuur;
  • inventory_*: nuwe struktuur (MSI - Multi Source Inventaris);

Jy moet voorraaddata by beide strukture voeg, want die nuwe struktuur is nog nie heeltemal onafhanklik van die ou een nie (dit is baie waarskynlik dat vir default pakhuis in die nuwe struktuur 'n tafel is betrokke cataloginventory_stock_status as inventory_stock_1).

katalogusvoorraad_

Wanneer Magneto 2.3 ontplooi word, het ons aanvanklik 2 inskrywings in store_website, wat ooreenstem met twee webwerwe - administratiewe en hoofkliënt:

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

Tafel cataloginventory_stock ons het net een inskrywing:

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

Dit wil sê, in ons ou struktuur is daar net een "pakhuis" (stock) en dit is gekoppel aan die administratiewe webwerf. Voeg nuwes by deur die administrasiepaneel sources/stocks in MSI (nuwe struktuur) lei nie tot nuwe inskrywings in nie cataloginventory_stock.

Voorraaddata oor produkte in die ou struktuur word aanvanklik in tabelle aangeteken:

  • 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);
}

voorraad_

Aanvanklik bevat die nuwe struktuur vir die stoor van voorraaddata 1 "bron"(inventory_source):

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

en een"winkel"(inventory_stock):

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

«Bron» verteenwoordig die fisiese berging vir produkte (die rekord bevat fisiese koördinate en posadres). "Pakhuis"is 'n logiese vereniging van verskeie "bronne" (inventory_source_stock_link)

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

op die vlak waarop die verbinding met die verkoopskanaal plaasvind (inventory_stock_sales_channel)

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

Te oordeel aan die datastruktuur, word verskeie tipes verkoopskanale aanvaar, maar by verstek slegs die verbinding "voorraad"-"webwerf"(die skakel na die webwerf volg die webwerf-kode - base).

Een"winkel"kan aan verskeie gekoppel word"bronne"en een"bron"- aan verskeie"pakhuise"(baie-tot-baie-verhouding). Die uitsonderings is standaard "bron"En"winkel". Hulle word nie weer aan ander entiteite gekoppel nie (beperking op kodevlak - die fout "Kan nie skakel stoor wat verband hou met verstekbron of verstekvoorraad nie"). Meer besonderhede oor die MSI-struktuur in Magento 2 kan gevind word in die artikel "Pakhuisbestuurstelsel wat CQRS en Event Sourcing gebruik. Ontwerp«.

Ek sal die verstekkonfigurasie gebruik en alle voorraadinligting by die bron voeg default, wat betrokke is by die verkoopskanaal wat verband hou met die webwerf met die kode base (kom ooreen met die voorkant van die winkel - sien 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);
}

Nadat u voorraaddata by die produk in die administrasiepaneel gevoeg het, kry u hierdie prentjie:

Magento 2: voer produkte direk in die databasis in

media

Wanneer 'n prent deur die administrasiepaneel "handmatig" by 'n produk gevoeg word, word die relevante inligting in die volgende tabelle neergeskryf:

  • catalog_product_entity_media_gallery: mediaregister (prente en videolêers);
  • catalog_product_entity_media_gallery_value: koppeling van media aan produkte en vertoonvensters (lokalisering);
  • catalog_product_entity_media_gallery_value_to_entity: skakel media slegs aan produkte (vermoedelik verstek media-inhoud vir die produk);
  • catalog_product_entity_varchar: Die rolle waarin die beeld gebruik word, word hier gestoor;

en die beelde self word in die gids gestoor ./pub/media/catalog/product/x/y/Waar x и y — die eerste en tweede letters van die prentlêernaam. Byvoorbeeld, lêer image.png moet gestoor word as ./pub/media/catalog/product/i/m/image.png, sodat die platform dit as 'n beeld kan gebruik wanneer produkte uit die katalogus beskryf word.

Register geplaas in ./pub/media/catalog/product/ medialêer (die proses om die lêer self te plaas word nie in hierdie artikel bespreek nie):

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;
}

Wanneer dit geregistreer is, word 'n identifiseerder aan 'n nuwe medialêer toegeken.

Ons assosieer die geregistreerde medialêer met die ooreenstemmende produk vir die verstek winkelfront:

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);
}

Ons assosieer die geregistreerde medialêer met die ooreenstemmende produk sonder om aan enige winkelfront gekoppel te wees. Dit is nie duidelik waar presies hierdie data gebruik word en hoekom dit onmoontlik is om toegang tot die data van die vorige tabel te kry nie, maar hierdie tabel bestaan ​​en die data word daarheen geskryf wanneer 'n prentjie by die produk gevoeg word. So dit is dit.

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

'n Medialêer kan met verskillende rolle gebruik word (die ooreenstemmende kenmerkkode word tussen hakies aangedui):

  • Basis(image)
  • Klein prent (small_image)
  • Kleinkiekie (thumbnail)
  • Swatch-prent (swatch_image)

Om rolle aan 'n medialêer te koppel is presies wat in gebeur catalog_product_entity_varchar. Die bindingskode is soortgelyk aan die kode in die "Basiese produk eienskappe«.

Nadat 'n prent by die produk in die administrasiepaneel gevoeg is, lyk dit soos volg:

Magento 2: voer produkte direk in die databasis in

Категории

Hooftabelle wat data volgens kategorie bevat:

  • catalog_category_entity: register van kategorieë;
  • catalog_category_product: verband tussen produkte en kategorieë;
  • catalog_category_entity_*: EAV-kenmerkwaardes;

Aanvanklik, in 'n leë Magento-toepassing, bevat die kategorieregister 2 kategorieë (ek het die kolomname verkort: 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 met id=1 is die wortel van die hele Magento-katalogus en is nie in die administrasiepaneel of op die voorblad beskikbaar nie. Kategorie met id=2 (standaard Kategorie) is die wortelkategorie vir die hoofwerf se hoofwinkel (Hoof webwerfwinkel) geskep wanneer die toepassing ontplooi word (sien. Admin / Winkels / Alle winkels). Boonop is die wortelkategorie van die winkel self ook nie aan die voorkant beskikbaar nie, slegs sy subkategorieë.

Aangesien die onderwerp van hierdie artikel steeds die invoer van data oor produkte is, sal ek nie direkte toegang tot die databasis gebruik wanneer ek kategorieë skep nie, maar sal die klasse gebruik wat deur Magento self verskaf word (modelle en bewaarplekke). Direkte inskrywing in die databasis word slegs gebruik om die ingevoerde produk met 'n kategorie te assosieer (die kategorie word deur sy naam gepas, en die kategorie-ID word tydens passing herwin):

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);
}

Nadat 'n produkskakel by die kategorieë "Kategorie 1" en "Kategorie 2" gevoeg is, lyk die produkbesonderhede in die administrasiepaneel iets soos volg:

Magento 2: voer produkte direk in die databasis in

Bykomende aksies

Sodra die data-invoer voltooi is, moet jy die volgende bykomende stappe voltooi:

  • data-indeksering: roep die konsole in ./bin/magento indexer:reindex;
  • hergenereer URL's vir produkte/kategorieë: jy kan die uitbreiding "elgentos/regenerate-catalog-urls«

Produkte in die administrasiepaneel nadat bykomende handelinge uitgevoer is:

Magento 2: voer produkte direk in die databasis in

en aan die voorkant:

Magento 2: voer produkte direk in die databasis in

Opsomming

Dieselfde stel produkte (10 stukke) as in die vorige artikel word ten minste 'n orde van grootte vinniger ingevoer (1 sekonde teenoor 10). Om die spoed meer akkuraat te skat, benodig jy 'n groter aantal produkte - 'n paar honderd, of beter nog duisende. Selfs met so 'n klein grootte van insetdata kan ons egter aflei dat die gebruik van die gereedskap wat deur Magento verskaf word (modelle en bewaarplekke) betekenisvol is (ek beklemtoon - baie!) versnel die ontwikkeling van die vereiste funksionaliteit, maar terselfdertyd aansienlik (ek beklemtoon - baie!) verminder die spoed waarteen data in die databasis kom.

Dit het tot gevolg gehad dat die water nat geword het en dit is nie 'n openbaring nie. Nou het ek egter die kode om mee te speel en dalk tot 'n paar meer interessante gevolgtrekkings te kom.

Bron: will.com