Magento 2: Tuo tuotteet suoraan tietokantaan

В edellinen artikkeli Kuvasin tuotteiden tuontiprosessia Magento 2:een tavalliseen tapaan - mallien ja arkistojen kautta. Tavallisella menetelmällä on erittäin alhainen tietojenkäsittelynopeus. Kannettavani tuotti noin yhden tuotteen sekunnissa. Tässä jatkossa harkitsen vaihtoehtoista tapaa tuoda tuote - syöttämällä suoraan tietokantaan ohittaen tavalliset Magento 2 -mekanismit (mallit, tehtaat, arkistot). Tuotteiden tuontivaiheiden järjestys voidaan mukauttaa mille tahansa ohjelmointikielelle, joka voi toimia MySQL:n kanssa.

Vastuun kieltäminen: Magentolla on valmiita toimintoja tietojen tuonti ja todennäköisesti se riittää sinulle. Jos kuitenkin tarvitset täydellisemmän hallinnan tuontiprosessista, etkä rajoitu CSV-tiedoston valmisteluun, tervetuloa cat.

Magento 2: Tuo tuotteet suoraan tietokantaan

Molempien artikkelien kirjoittamisesta saatu koodi on nähtävissä Magento-moduulissa "flancer32/mage2_ext_demo_import". Tässä on joitain rajoituksia, joita noudatin demomoduulin koodin yksinkertaistamiseksi:

  • Tuotteet vain luodaan, ei päivitetä.
  • Yksi varasto
  • Vain luokkien nimet tuodaan ilman niiden rakennetta
  • Tietorakenteet ovat version 2.3 mukaisia

JSON yhden tuotteen tuontia varten:

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

Yleiskatsaus tuonnin päävaiheisiin

  • itse tuotteen rekisteröinti
  • tuotteen ja verkkosivuston välinen yhteys
  • tuotteen perusominaisuudet (EAV)
  • varastotiedot (tuotteen määrä varastossa)
  • media (kuvat)
  • yhteys luetteloiden luokkiin

Tuoterekisteröinti

Tuotteen perustiedot löytyvät osoitteesta 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`)
)

Tuoterekisterin merkinnän luomiseen vaadittavat vähimmäistiedot ovat:

  • attribute_set_id
  • sku

lisää:

  • type_id - jos emme määritä sitä, käytetään "yksinkertaista".

Kirjoittaakseni suoraan tietokantaan käytän itse Magenton DB-sovitinta:

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

Kun olet rekisteröinyt tuotteen catalog_product_entity se tulee näkyviin hallintapaneelissa, tuoteruudukossa (Luettelo/Tuotteet).

Magento 2: Tuo tuotteet suoraan tietokantaan

Tuotteen ja verkkosivuston välinen suhde

Tuotteen yhdistäminen sivustoon määrittää, missä myymälöissä ja esittelyissä tuote on saatavilla etupuolella.

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: Tuo tuotteet suoraan tietokantaan

Tuotteen perusominaisuudet

Äskettäin rekisteröidyllä tuotteella ei ole vielä nimeä tai kuvausta. Kaikki tämä tehdään läpi EAV-attribuutit. Tässä on luettelo tuotteen perusominaisuuksista, joita tarvitaan, jotta tuote näkyy oikein etupuolella:

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

Tällaiseen tuotteeseen lisätään erillinen attribuutti (tunnisteen ja attribuutin tyypin saamisen tiedot sen koodista jätetään pois):

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

Määritämme attribuuttikoodin avulla sen tunnuksen ja tietotyypin (datetime, decimal, int, text, varchar), kirjoita sitten hallintaikkunan tiedot sopivaan taulukkoon (store_id = 0).

Kun olet lisännyt yllä olevat attribuutit tuotteeseen, saat tämän kuvan hallintapaneeliin:

Magento 2: Tuo tuotteet suoraan tietokantaan

Varastotiedot

Magenton versiosta 2.3 alkaen on kaksi rinnakkaista taulukkosarjaa, jotka tarjoavat varastotietojen (tuotemäärän) tallentamisen:

  • cataloginventory_*: vanha rakenne;
  • inventory_*: uusi rakenne (MSI - Multi Source Inventory);

Sinun on lisättävä varastotiedot molempiin rakenteisiin, koska uusi rakenne ei ole vielä täysin riippumaton vanhasta (on hyvin todennäköistä, että varten default varasto uudessa rakenteessa on mukana pöytä cataloginventory_stock_status kuin inventory_stock_1).

katalogivarasto_

Magneto 2.3:n käyttöönoton yhteydessä meillä on aluksi kaksi merkintää store_website, joka vastaa kahta sivustoa - hallinnollista ja pääasiakasta:

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

Pöytä cataloginventory_stock meillä on vain yksi merkintä:

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

Eli vanhassa rakenteessamme on vain yksi "varasto" (stock) ja se on linkitetty hallinnolliselle verkkosivustolle. Uusien lisääminen hallintapaneelin kautta sources/stocks MSI:ssä (uusi rakenne) ei johda uusiin merkintöihin cataloginventory_stock.

Vanhan rakenteen tuotteiden varastotiedot kirjataan aluksi taulukoihin:

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

inventaario_

Aluksi uusi varastotietojen tallennusrakenne sisältää 1 "lähde"(inventory_source):

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

ja yksi "varasto"(inventory_stock):

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

«Lähde» edustaa tuotteiden fyysistä tallennustilaa (tietue sisältää fyysiset koordinaatit ja postiosoitteen). "Varasto"on looginen liitto useista "lähteistä" (inventory_source_stock_link)

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

sillä tasolla, jolla yhteys myyntikanavaan tapahtuu (inventory_stock_sales_channel)

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

Tietorakenteen perusteella oletetaan erityyppisiä myyntikanavia, mutta oletusarvoisesti vain yhteys "Varastossa"-"verkkosivusto"(linkki verkkosivustolle seuraa verkkosivuston koodia - base).

Yksi "varasto"voidaan yhdistää useisiin"lähteille"ja yksi "lähde"- useille"varastot"(Monet moneen -suhde). Poikkeukset ovat oletusarvoja"lähde"Ja"varasto". Niitä ei ole linkitetty uudelleen muihin entiteeteihin (rajoitus kooditasolla - virhe "Ei voi tallentaa oletuslähteeseen tai oletusvarastoon liittyvää linkkiä"). Lisätietoja Magento 2:n MSI-rakenteesta löytyy artikkelista "Varastonhallintajärjestelmä CQRS:n ja Event Sourcingin avulla. Design".

Käytän oletuskokoonpanoa ja lisään kaikki varastotiedot lähteeseen default, joka on mukana myyntikanavassa, joka liittyy koodin sisältävään verkkosivustoon base (vastaa myymälän etuosaa - katso 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);
}

Kun olet lisännyt varastotiedot tuotteeseen hallintapaneelissa, saat seuraavan kuvan:

Magento 2: Tuo tuotteet suoraan tietokantaan

Tiedotusvälineet

Kun "manuaalisesti" lisätään kuva tuotteeseen hallintapaneelin kautta, asiaankuuluvat tiedot kirjoitetaan seuraaviin taulukoihin:

  • catalog_product_entity_media_gallery: mediarekisteri (kuvat ja videotiedostot);
  • catalog_product_entity_media_gallery_value: median linkittäminen tuotteisiin ja esittelyihin (lokalisointi);
  • catalog_product_entity_media_gallery_value_to_entity: median linkittäminen vain tuotteisiin (oletettavasti tuotteen oletusmediasisältö);
  • catalog_product_entity_varchar: Roolit, joissa kuvaa käytetään, tallennetaan tähän;

ja itse kuvat tallennetaan hakemistoon ./pub/media/catalog/product/x/y/Missä x и y — kuvatiedoston nimen ensimmäinen ja toinen kirjain. Esimerkiksi tiedosto image.png tulee tallentaa nimellä ./pub/media/catalog/product/i/m/image.png, jotta alusta voi käyttää sitä kuvana kuvaillessaan tuotteita luettelosta.

Ilmoittautuminen lähetetty ./pub/media/catalog/product/ mediatiedosto (itse tiedoston sijoittamisprosessia ei käsitellä tässä artikkelissa):

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

Kun uusi mediatiedosto rekisteröidään, sille annetaan tunniste.

Yhdistämme rekisteröidyn mediatiedoston oletusmyymälän vastaavaan tuotteeseen:

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

Yhdistämme rekisteröidyn mediatiedoston vastaavaan tuotteeseen olematta sidottu mihinkään myymälään. Ei ole selvää, missä tarkalleen näitä tietoja käytetään ja miksi edellisen taulukon tietoihin ei pääse käsiksi, mutta tämä taulukko on olemassa ja tiedot kirjoitetaan siihen, kun tuotteeseen lisätään kuva. Joten se siitä.

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

Mediatiedostoa voidaan käyttää eri rooleissa (vastaava attribuuttikoodi on merkitty suluissa):

  • Perus (image)
  • Pieni kuva (small_image)
  • Pikkukuva (thumbnail)
  • Swatch Image (swatch_image)

Roolien linkittäminen mediatiedostoon tapahtuu juuri siinä catalog_product_entity_varchar. Sidoskoodi on samanlainen kuin "Tuotteen perusominaisuudet".

Kun tuotteeseen on lisätty kuva hallintapaneelissa, se näyttää tältä:

Magento 2: Tuo tuotteet suoraan tietokantaan

Категории

Päätaulukot, jotka sisältävät tiedot luokittain:

  • catalog_category_entity: luokkarekisteri;
  • catalog_category_product: tuotteiden ja luokkien välinen yhteys;
  • catalog_category_entity_*: EAV-määritteen arvot;

Aluksi tyhjässä Magento-sovelluksessa luokkarekisteri sisältää 2 luokkaa (lyhensin sarakkeiden nimet: 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|

Kategoria, jonka tunnus on id=1, on koko Magento-luettelon juuri, eikä se ole käytettävissä hallintapaneelissa tai etusivulla. Luokka, jonka id=2 (Oletusluokka) on pääsivuston pääkaupan juuriluokka (Pääsivuston kauppa) luotu, kun sovellus otetaan käyttöön (katso. Admin / Kaupat / Kaikki kaupat). Lisäksi itse myymälän juuriluokka ei ole saatavilla edestä, vain sen alakategoriat.

Koska tämän artikkelin aiheena on edelleen tuotetietojen tuominen, en käytä luokkien luomisessa suoraa pääsyä tietokantaan, vaan käytän Magenton itsensä tarjoamia luokkia (malleja ja arkistot). Suoraa pääsyä tietokantaan käytetään vain tuodun tuotteen liittämiseen luokkaan (luokka vastaa sen nimeä ja luokkatunnus haetaan täsmäämisen yhteydessä):

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

Kun olet lisännyt tuotelinkin luokkiin "Category 1" ja "Category 2", tuotteen tiedot hallintapaneelissa näyttävät tältä:

Magento 2: Tuo tuotteet suoraan tietokantaan

Muita toimia

Kun tietojen tuonti on valmis, sinun on suoritettava seuraavat lisävaiheet:

  • tietojen indeksointi: soita konsolissa ./bin/magento indexer:reindex;
  • uusien URL-osoitteiden luominen tuotteille/luokille: voit käyttää laajennusta "elgentos/regenerate-catalog-urls«

Tuotteet hallintapaneelissa lisätoimintojen suorittamisen jälkeen:

Magento 2: Tuo tuotteet suoraan tietokantaan

ja edessä:

Magento 2: Tuo tuotteet suoraan tietokantaan

Yhteenveto

Sama tuotesarja (10 kpl) kuin edellisessä artikkelissa tuodaan vähintään suuruusluokkaa nopeammin (1 sekunti vs. 10). Nopeuden tarkempaan arvioimiseen tarvitaan suurempi määrä tuotteita - useita satoja tai vielä parempi tuhansia. Jopa näin pienellä syöttötiedon koolla voimme kuitenkin päätellä, että Magenton tarjoamien työkalujen (mallit ja arkistot) käyttö on merkittävää (korostan - paljon!) nopeuttaa vaaditun toiminnallisuuden kehitystä, mutta samalla merkittävästi (korostan - paljon!) hidastaa nopeutta, jolla tiedot pääsevät tietokantaan.

Tämän seurauksena vesi osoittautui märäksi, eikä tämä ole ilmestys. Nyt minulla on kuitenkin koodi, jolla leikkiä ja ehkä tehdä mielenkiintoisempia johtopäätöksiä.

Lähde: will.com