Magento 2: importoni produkte direkt në bazën e të dhënave

В artikulli i mëparshëm Unë e përshkrova procesin e importimit të produkteve në Magento 2 në mënyrën e zakonshme - përmes modeleve dhe depove. Metoda e zakonshme ka një shpejtësi shumë të ulët të përpunimit të të dhënave. Laptopi im po prodhonte rreth një produkt në sekondë. Në këtë vazhdim, unë konsideroj një mënyrë alternative për të importuar një produkt - duke hyrë direkt në bazën e të dhënave, duke anashkaluar mekanizmat standardë Magento 2 (modele, fabrika, depo). Sekuenca e hapave për importimin e produkteve mund të përshtatet me çdo gjuhë programimi që mund të punojë me MySQL.

Mohim përgjegjësie: Magento ka funksionalitet të gatshëm për importimi i të dhënave dhe, ka shumë të ngjarë, do të jetë e mjaftueshme për ju. Sidoqoftë, nëse keni nevojë për kontroll më të plotë mbi procesin e importit, pa u kufizuar në përgatitjen e një skedari CSV për atë që keni, mirë se vini në cat.

Magento 2: importoni produkte direkt në bazën e të dhënave

Kodi që rezulton nga shkrimi i të dy artikujve mund të shihet në modulin Magento "flancer32/mage2_ext_demo_import". Këtu janë disa kufizime që kam ndjekur për të thjeshtuar kodin e modulit demo:

  • Produktet krijohen vetëm, nuk përditësohen.
  • Një magazinë
  • Vetëm emrat e kategorive importohen, pa strukturën e tyre
  • Strukturat e të dhënave përputhen me versionin 2.3

JSON për importimin e një produkti të vetëm:

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

Pasqyrë e fazave kryesore të importit

  • regjistrimin e vetë produktit
  • lidhje mes produktit dhe faqes së internetit
  • atributet bazë të produktit (EAV)
  • të dhënat e inventarit (sasia e produktit në magazinë)
  • media (foto)
  • lidhje me kategoritë e katalogut

Regjistrimi i produktit

Informacioni bazë i produktit mund të gjendet në 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`)
)

Informacioni minimal i kërkuar për të krijuar një hyrje në regjistrin e produktit është:

  • attribute_set_id
  • sku

shtesë:

  • type_id — nëse nuk e specifikojmë, atëherë do të përdoret 'i thjeshtë'

Për të shkruar drejtpërdrejt në bazën e të dhënave, unë përdor përshtatësin DB të vetë Magento:

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

Pas regjistrimit të produktit me catalog_product_entity ai bëhet i dukshëm në panelin e administratorit, në rrjetin e produktit (Katalog/Produkte).

Magento 2: importoni produkte direkt në bazën e të dhënave

Marrëdhënia midis produktit dhe faqes në internet

Lidhja e produktit me sitin përcakton se në cilat dyqane dhe ekspozita produkti do të jetë i disponueshëm në pjesën e përparme.

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: importoni produkte direkt në bazën e të dhënave

Atributet bazë të produktit

Produkti i sapo regjistruar nuk ka ende një emër ose përshkrim. E gjithë kjo bëhet përmes Atributet EAV. Këtu është një listë e atributeve bazë të produktit që nevojiten në mënyrë që produkti të shfaqet saktë në pjesën e përparme:

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

Një atribut i veçantë i shtohet një produkti si ky (të dhënat e marrjes së identifikuesit dhe llojit të atributit nga kodi i tij janë hequr):

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

Duke përdorur kodin e atributit, ne përcaktojmë ID-në e tij dhe llojin e të dhënave (datetime, decimal, int, text, varchar), më pas shkruani të dhënat për dritaren administrative në tabelën përkatëse (store_id = 0).

Pas shtimit të atributeve të mësipërme në produkt, ju merrni këtë foto në panelin e administratorit:

Magento 2: importoni produkte direkt në bazën e të dhënave

Të dhënat e inventarit

Duke filluar nga versioni 2.3 në Magento, ekzistojnë dy grupe paralele tabelash që ofrojnë ruajtjen e informacionit të inventarit (sasia e produktit):

  • cataloginventory_*: strukturë e vjetër;
  • inventory_*: struktura e re (MSI - Inventari me shumë burime);

Ju duhet të shtoni të dhënat e inventarit në të dy strukturat, sepse struktura e re nuk është ende plotësisht e pavarur nga e vjetra (ka shumë të ngjarë që për default magazina në strukturën e re është përfshirë një tavolinë cataloginventory_stock_status si inventory_stock_1).

kataloginventari_

Kur vendosim Magneto 2.3 ne fillimisht kemi 2 hyrje store_website, e cila korrespondon me dy faqe - klienti administrativ dhe kryesor:

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

Tabela cataloginventory_stock kemi vetëm një hyrje:

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

Kjo do të thotë, në strukturën tonë të vjetër ka vetëm një "depo" (stock) dhe është i lidhur me faqen e internetit administrative. Shtimi i të rejave përmes panelit të administratorit sources/stocks në MSI (struktura e re) nuk rezulton në hyrje të reja në cataloginventory_stock.

Të dhënat e inventarit për produktet në strukturën e vjetër fillimisht regjistrohen në tabela:

  • cataloginventory_stock_item
  • cataloginventory_stock_status

kataloginventari_stock_artikull

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

statusi i katalogut të stokut

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

inventari_

Fillimisht, struktura e re për ruajtjen e të dhënave të inventarit përmban 1 "burim'(inventory_source):

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

dhe nje"depo'(inventory_stock):

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

«Burim» përfaqëson ruajtjen fizike të produkteve (rekord përmban koordinatat fizike dhe adresën postare). "Magazina"është një bashkim logjik i disa "burimeve" (inventory_source_stock_link)

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

në nivelin në të cilin ndodh lidhja me kanalin e shitjes (inventory_stock_sales_channel)

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

Duke gjykuar nga struktura e të dhënave, supozohen lloje të ndryshme të kanaleve të shitjes, por si parazgjedhje vetëm lidhja "aksioneve"-" "(lidhja në faqen e internetit ndjek kodin e faqes së internetit - base).

nje"depo"mund të lidhet me disa"burime"dhe një"burim" - për disa "magazina"(marrëdhënie shumë-me-shumë). Përjashtimet janë të paracaktuara "burim"Dhe"depo". Ata nuk janë rilidhur me entitete të tjera (kufizimi në nivelin e kodit - gabimi "Nuk mund të ruhet lidhja në lidhje me Burimin e paracaktuar ose Stokun e paracaktuar"). Më shumë detaje rreth strukturës MSI në Magento 2 mund të gjenden në artikullin "Sistemi i menaxhimit të magazinës duke përdorur CQRS dhe Event Sourcing. Dizajn".

Unë do të përdor konfigurimin e paracaktuar dhe do të shtoj të gjithë informacionin e inventarit në burim default, e cila është e përfshirë në kanalin e shitjeve të lidhur me faqen e internetit me kodin base (korrespondon me pjesën e përparme të dyqanit - shih 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);
}

Pas shtimit të të dhënave të inventarit te produkti në panelin e administratorit, ju merrni këtë foto:

Magento 2: importoni produkte direkt në bazën e të dhënave

media

Kur shtoni "me dorë" një imazh në një produkt përmes panelit të administratorit, informacioni përkatës shkruhet në tabelat e mëposhtme:

  • catalog_product_entity_media_gallery: regjistri i mediave (skedarët e imazheve dhe videove);
  • catalog_product_entity_media_gallery_value: lidhja e mediave me produktet dhe ekspozitat (lokalizimi);
  • catalog_product_entity_media_gallery_value_to_entity: lidhja e mediave vetëm me produktet (me sa duket përmbajtje e paracaktuar e medias për produktin);
  • catalog_product_entity_varchar: Këtu ruhen rolet në të cilat përdoret imazhi;

dhe vetë imazhet ruhen në drejtori ./pub/media/catalog/product/x/y/Ku x и y — shkronjat e para dhe të dyta të emrit të skedarit të imazhit. Për shembull, skedari image.png duhet të ruhen si ./pub/media/catalog/product/i/m/image.png, në mënyrë që platforma ta përdorë atë si imazh kur përshkruan produktet nga katalogu.

Regjistrohu postuar në ./pub/media/catalog/product/ skedari mediatik (procesi i vendosjes së skedarit në vetvete nuk diskutohet në këtë artikull):

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

Kur regjistrohet, një skedari të ri mediatik i caktohet një identifikues.

Ne e lidhim skedarin e regjistruar të medias me produktin përkatës për vitrinën e paracaktuar:

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

Ne e lidhim skedarin e medias së regjistruar me produktin përkatës pa u lidhur me ndonjë vitrinë. Nuk është e qartë se ku përdoren saktësisht këto të dhëna dhe pse është e pamundur të aksesohen të dhënat nga tabela e mëparshme, por kjo tabelë ekziston dhe të dhënat shkruhen në të kur produkti i shtohet një fotografi. Pra, kjo është ajo.

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

katalog_produkt_entitet_varchar

Një skedar media mund të përdoret me role të ndryshme (kodi përkatës i atributit tregohet në kllapa):

  • bazë(image)
  • Imazhi i vogël (small_image)
  • miniaturë (thumbnail)
  • Swatch Image (swatch_image)

Lidhja e roleve me një skedar media është pikërisht ajo që ndodh në catalog_product_entity_varchar. Kodi detyrues është i ngjashëm me kodin në "Atributet bazë të produktit".

Pas shtimit të një imazhi në produktin në panelin e administratorit, duket kështu:

Magento 2: importoni produkte direkt në bazën e të dhënave

Kategoritë

Tabelat kryesore që përmbajnë të dhëna sipas kategorive:

  • catalog_category_entity: regjistri i kategorive;
  • catalog_category_product: lidhja ndërmjet produkteve dhe kategorive;
  • catalog_category_entity_*: vlerat e atributeve EAV;

Fillimisht, në një aplikacion bosh Magento, regjistri i kategorive përmban 2 kategori (unë shkurtova emrat e kolonave: 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 me id=1 është rrënja e të gjithë katalogut Magento dhe nuk është e disponueshme as në panelin e administratorit, as në faqen e parë. Kategoria me id=2 (Kategoria e paracaktuar) është kategoria rrënjësore për dyqanin kryesor të faqes kryesore (Dyqani kryesor i faqes në internet) krijuar kur aplikacioni vendoset (shih. Admin / Dyqanet / Të gjitha Dyqanet). Për më tepër, kategoria rrënjësore e vetë dyqanit gjithashtu nuk është e disponueshme në pjesën e përparme, por vetëm nënkategoritë e saj.

Meqenëse tema e këtij artikulli është ende importimi i të dhënave për produktet, unë nuk do të përdor hyrjen e drejtpërdrejtë në bazën e të dhënave gjatë krijimit të kategorive, por do të përdor klasat e ofruara nga vetë Magento (modele dhe depo). Hyrja e drejtpërdrejtë në bazën e të dhënave përdoret vetëm për të lidhur produktin e importuar me një kategori (kategoria përputhet me emrin e saj dhe id i kategorisë merret gjatë përputhjes):

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

Pas shtimit të një lidhje produkti në kategoritë "Kategoria 1" dhe "Kategoria 2", detajet e produktit në panelin e administratorit duken diçka si kjo:

Magento 2: importoni produkte direkt në bazën e të dhënave

Aksione shtesë

Pasi të përfundojë importimi i të dhënave, duhet të kryeni hapat e mëposhtëm shtesë:

  • indeksimi i të dhënave: telefononi në tastierë ./bin/magento indexer:reindex;
  • rigjenerimi i URL-ve për produkte/kategori: mund të përdorni shtesën "elgentos/regenerate-catalog-urls«

Produktet në panelin e administratorit pas kryerjes së veprimeve shtesë:

Magento 2: importoni produkte direkt në bazën e të dhënave

dhe në pjesën e përparme:

Magento 2: importoni produkte direkt në bazën e të dhënave

Përmbledhje

I njëjti grup produktesh (10 copë) si në artikullin e mëparshëm importohet të paktën një rend i madhësisë më shpejt (1 sekondë kundrejt 10). Për të vlerësuar më saktë shpejtësinë, keni nevojë për një numër më të madh produktesh - disa qindra, ose më mirë akoma mijëra. Sidoqoftë, edhe me një madhësi kaq të vogël të të dhënave hyrëse, mund të konkludojmë se përdorimi i mjeteve të ofruara nga Magento (modele dhe depo) është domethënës (theksoj - shumë!) përshpejtoni zhvillimin e funksionalitetit të kërkuar, por në të njëjtën kohë në mënyrë të konsiderueshme (theksoj - shumë!) zvogëloni shpejtësinë me të cilën të dhënat futen në bazën e të dhënave.

Si rezultat, uji doli të ishte i lagësht dhe kjo nuk është një zbulim. Megjithatë, tani kam kodin për të luajtur dhe ndoshta për të arritur në disa përfundime më interesante.

Burimi: www.habr.com