Magento 2: importi i produkteve direkt në bazën e të dhënave

NĂ« artikulli i mĂ«parshĂ«m UnĂ« pĂ«rshkrova procesin e importit tĂ« produkteve nĂ« Magento 2 nĂ« mĂ«nyrĂ«n standarde — pĂ«rmes modeleve dhe repozitorĂ«ve. MĂ«nyra e zakonshme karakterizohet nga njĂ« shpejtĂ«si shumĂ« e ulĂ«t pĂ«r pĂ«rpunimin e tĂ« dhĂ«nave. NĂ« laptopin tim, rezultonte rreth njĂ« produkt nĂ« sekondĂ«. NĂ« kĂ«tĂ« vazhdim, unĂ« shqyrtoj njĂ« mĂ«nyrĂ« alternative tĂ« importit tĂ« produktit — shkrimin direkt nĂ« bazĂ«, duke anashkaluar mekanizmat standard tĂ« Magento 2 (modelet, fabrikat, repozitorĂ«t). Renditja e hapave qĂ« sigurojnĂ« importin e produkteve mund tĂ« pĂ«rshtatet pĂ«r çdo gjuhĂ« programimi qĂ« mund tĂ« punojĂ« me MySQL.

ShĂ«nim ligjor: NĂ« Magento ekziston funksionalitet i ndĂ«rtuar pĂ«r importimin e tĂ« dhĂ«nave dhe, shumĂ« gjasĂ«, ju do ta keni mjaft. MegjithatĂ«, nĂ«se ju nevojitet mĂ« shumĂ« kontroll mbi procesin e importit, qĂ« nuk kufizohet vetĂ«m nĂ« pĂ«rgatitjen e skedarĂ«ve CSV pĂ«r atĂ« qĂ« Ă«shtĂ« — mirĂ«seerdhĂ«t nĂ«n kĂ«tĂ« pĂ«rmbajtje.

Magento 2: importi i produkteve direkt në bazën e të dhënave

Kodi që mbetet nga shkrimi i të dy artikujve mund të shihet në moduline Magento "flancer32/mage2_ext_demo_import". Ja disa kufizime që kam ndjekur për të thjeshtuar kodin e modulit demo:

  • Produktet krijohen vetĂ«m, nuk pĂ«rditĂ«sohen.
  • NjĂ« depo
  • Importohen vetĂ«m emrat e kategorive, pa strukturĂ«n e tyre
  • Strukturat e tĂ« dhĂ«nave pĂ«rputhen me versionin 2.3

JSON për importimin e një produkti të veçantë:

{
  "sku": "MVA20D-UBV-3",
  "name": "Kapaku për vulosjen VA47-29 IEK",
  "desc": "Sigurimi i aksesit në pajisje ...",
  "desc_short": "Kapaku për vulosjen VA47-29 IEK është i destinuar për ...",
  "price": 5.00,
  "qty": 25,
  "categories": ["Kategoria 1", "Kategoria 2"],
  "image_path": "mva20d_ubv_3.png"
}

Përmbledhja e etapave kryesore të importit

  • regjistrimi i produktit tĂ« vet
  • pĂ«r lidhjen e produktit me ueb-faqen
  • atributet bazĂ« tĂ« produktit (EAV)
  • tĂ« dhĂ«nat e inventarit (sasia e produktit nĂ« depo)
  • media (imazhe)
  • lidhja me kategoritĂ« e kataloqeve

Regjistrimi i produktit

Informacioni bazë mbi produktin ndodhet 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 nevojshëm për krijimin e një regjistrimi në regjistrin e produkteve:

  • attribute_set_id
  • sku

shtesë:

  • type_id — nĂ«se nuk e specifikojmĂ«, atĂ«herĂ« do tĂ« pĂ«rdoret 'simple'

Për shkrimin direkt në bazë përdorim adapterin DB të Magento-s vetë:

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

Pasi produkti është regjistruar në catalog_product_entity ai bëhet i dukshëm në admin, në gridin e produkteve (Catalog / Products).

Magento 2: importi i produkteve direkt në bazën e të dhënave

Lidhja e produktit me ueb-faqen

Lidhja e produktit me ueb-faqen përcakton në cilat dyqane dhe në cilat vitrina produkti do të jetë i disponueshëm në front.

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: importi i produkteve direkt në bazën e të dhënave

Atributet bazë të produktit

Një produkt i sapo regjistruar nuk ka as emër, as përshkrim. Të gjitha këto bëhen përmes atributeve EAV. Ja lista e atributve bazë të produktit që nevojiten për të siguruar që produkti të shfaqet mjaft saktë në front:

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

Një atribut i veçantë shtohet kështu (detajet e marrjes së identifikatorit dhe tipit të atributit sipas kodit të tij janë lënë jashtë):

public function create($prodId, $attrCode, $attrValue)
{
    $attrId = /* merr ID-në e atributit sipas kodit të atributit */
    $attrType = /* merr tipin e atributit [datetime|decimal|int|text|varchar]) sipas kodit të atributit */
    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,
            /* vendos të gjitha atributet në pamjen e depozitës me id=0 (admin) */
            'store_id' => 0,
            'value' => $attrValue
        ];
        $conn->insert($table, $bind);
    }
}

Përmes kodit të atributit përcaktojmë ID-në e tij dhe tipin e të dhënave (datetime, decimal, int, text, varchar), pastaj në tabelën përkatëse shkruajmë të dhënat për pamjen administrative (store_id = 0).

Pasi t'i kemi shtuar atributet e mësipërme produktit, rezultati është ky skenar në admin:

Magento 2: importi i produkteve direkt në bazën e të dhënave

Të dhënat për inventar

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

  • cataloginventory_*: struktura e vjetĂ«r;
  • inventory_*: struktura e re (MSI — Multi Source Inventory);

Të dhënat e inventarit duhen shtuar në të dy strukturat, pasi struktura e re ende nuk është plotësisht e pavarur nga e vjetra (duket shumë se për default depon në strukturën e re është përfshirë tabela cataloginventory_stock_status si inventory_stock_1).

cataloginventory_

Kur zhvillohet Magneto 2.3 fillimisht kemi 2 regjistrime nĂ« store_website, qĂ« pĂ«rkon me dy faqe — administrimin dhe faqen kryesore tĂ« klientit:

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

Në tabelën cataloginventory_stock kemi vetëm një regjistrim:

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

Pra, në strukturën e vjetër kemi vetëm një «depo» (stock) dhe ajo është e lidhur me faqen administrative të website-it. Shtimi përmes adminit i burimeve të reja sources/stocks në MSI (strukturën e re) nuk çon në shfaqjen e regjistrimeve të reja në cataloginventory_stock.

Të dhënat e inventarit të produkteve në strukturën e vjetër fillimisht shkruhen në tabelat:

  • 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,
        /* ne përdorim vetëm një depo në strukturën 'cataloginventory' si parazgjedhje */
        'stock_id' => 1,
        'qty' => $qty,
        'is_qty_decimal' => $isQtyDecimal,
        'is_in_stock' => $isInStock,
        /* depoja parazgjedhëse është e lidhur me faqen admin (shih `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,
        /* ne përdorim vetëm një depo në strukturën 'cataloginventory' si parazgjedhje */
        'stock_id' => 1, 
        'qty' => $qty,
        'stock_status' => MagentoCatalogInventoryApiDataStockStatusInterface::STATUS_IN_STOCK,
        /* depoja parazgjedhëse është e lidhur me faqen admin (shih `cataloginventory_stock`) */
        'website_id' => 0 
    ];
    $conn->insert($table, $bind);
}

inventory_

Fillimisht struktura e re për ruajtjen e të dhënave të inventarit përmban 1 «burimi» (inventory_source):

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

dhe një «depo» (inventory_stock):

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

«Burimi» paraqet një depo fizike për produktet (regjistrimi përmban koordinatat fizike dhe adresën postare). «Depo» paraqet një bashkim logjik të disa «burimeve» (inventory_source_stock_link)

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

në nivelin e cilit ndodhet lidhja me kanalin e shënegjohur (inventory_stock_sales_channel)

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

Duke u bazuar nĂ« strukturĂ«n e tĂ« dhĂ«nave, parashikohen lloje tĂ« ndryshme kanalĂ«sh tĂ« shitjes, por pĂ«r parazgjedhjen pĂ«rdoret vetĂ«m lidhja «stock«-«website» (lidhja me web-faqen ndodh sipas kodit tĂ« web-faqes — bazĂ«).

NjĂ« «depo» mund tĂ« lidhet me disa «burime«, dhe njĂ« «burimi» — me disa «depo» (marrĂ«dhĂ«nie «shumĂ« me shumë»). PĂ«rjashtimet janĂ« default’ët «burimi» dhe «depo«. Ato nuk ribindĂ«n me entitete tĂ« tjera (njĂ« kufizim nĂ« nivelin e kodit — del njĂ« gabim «Can not save link related to Default Source or Default Stock«). MĂ« shumĂ« detaje rreth strukturĂ«s MSI nĂ« Magento 2 mund tĂ« lexohen nĂ« artikullin «Sistemi i menaxhimit tĂ« depot duke pĂ«rdorur CQRS dhe Event Sourcing. Projektimi«.

Do tĂ« pĂ«rdor konfigurimin e default dhe do tĂ« shtoj tĂ« gjitha informacionet e inventarit nĂ« burimin default, i cili Ă«shtĂ« aktivizuar nĂ« kanalin e shitjes, tĂ« lidhur me faqen e web-it me kodin bazĂ« (pĂ«rkon me pjesĂ«n klientore 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 në produkt në admin, duket kështu:

Magento 2: importi i produkteve direkt në bazën e të dhënave

Media

Kur shtoni manualisht imazhe në produkt përmes adminit, informacioni përkatës regjistrohet në tabelat e mëposhtme:

  • catalog_product_entity_media_gallery: regjistri i mediave (imazhe dhe video-fajla);
  • catalog_product_entity_media_gallery_value: lidhje e mediave me produktet dhe ekspozitat (lokalizimi);
  • catalog_product_entity_media_gallery_value_to_entity: lidhje e mediave vetĂ«m me produktet (ndoshta, pĂ«rmbajtja default e mediave pĂ«r produktin);
  • catalog_product_entity_varchar: kĂ«tu ruhen rolet, nĂ« tĂ« cilat pĂ«rdoret imazhi;

dhe vetĂ« imazhet ruhen nĂ« katalog ./pub/media/catalog/product/x/y/, ku x dhe y — shkronjat e para dhe tĂ« dyta tĂ« emrit tĂ« skedarit tĂ« imazhit. PĂ«r shembull, skedari image.png duhet tĂ« ruhet si ./pub/media/catalog/product/i/m/image.png, nĂ« mĂ«nyrĂ« qĂ« platforma tĂ« Mund ta pĂ«rdorĂ« si imazh kur pĂ«rshkruan produkte nga katalogu.

Regjistrojmë skedarin e publikuar në ./pub/media/catalog/product/ skedari mediatik (procesi i ngarkimit të skedarit në këtë artikull nuk diskutohet):

function createMediaGallery($imgPathPrefixed)
{
    $attrId = /* merr ID-në e atributit me kodin e atributit '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' ose 'video' */
        'media_type' => 'image',
        'disabled' => false
    ];
    $conn->insert($table, $bind);
    $result = $conn->lastInsertId($table);
    return $result;
}

Kur regjistrohet, skedarit të ri mediatik i jepet një identifikues.

Lidhim skedarin e regjistruar med produktin për vitrinën default:

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,
        /* përdor pamjen e dyqanit Admin si parazgjedhje */
        'store_id' => 0,
        'entity_id' => $prodId,
        'label' => null,
        /* ne kemi vetëm një imazh */
        'position' => 1,
        'disabled' => false
    ];
    $conn->insert($table, $bind);
}

Lidhim skedarin e regjistruar med produktin pa e lidhur me ndonjë dyqan. Nuk është e qartë se ku saktësisht përdoren këto të dhëna dhe pse nuk mund të referohemi në të dhënat e tabelës së mëparshme, por kjo tabelë ekziston dhe të dhënat regjistrohen aty kur shtohet një imazh në produkt. Prandaj, ja kështu.

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

Skedari mediatik mund të përdoret me role të ndryshme (në prindër dërgohet kodi i atributit të përkatës):

  • BazĂ« (image)
  • Imazhi i VogĂ«l (small_image)
  • Miniatura (thumbnail)
  • Imazhi i Swatch (swatch_image)

Lidhja e roleve me skedarin mediatik ndodh pikĂ«risht nĂ« catalog_product_entity_varchar. Kodi i lidhjes Ă«shtĂ« i ngjashĂ«m me kodin nĂ« seksionin “Atributet bazĂ« tĂ« produktit«.

Pas shtimit të imazhit në produkt në admin, duket kështu:

Magento 2: importi i produkteve direkt në bazën e të dhënave

Kategoritë

Tabelat kryesore, në të cilat ruhen të dhënat për kategoritë:

  • catalog_category_entity: regjistri i kategorive;
  • catalog_category_product: lidhja e produkteve dhe kategorive;
  • catalog_category_entity_*: vlerat EAV-aatributeve;

Fillimisht, nĂ« njĂ« aplikacion tĂ« zbrazĂ«t Magento, regjistri i kategorive pĂ«rmban 2 kategori (e kam shkurtuar emrin 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 gjithë katalogut Magento dhe nuk është e disponueshme as në admin as në front. Kategoria me id=2 (Default Category) është kategoria rrënjë për dyqanin kryesor të faqes kryesore (Main Website Store), e cila krijohet gjatë zbatimit të aplikacionit (shih. Admin / Stores / All Stores). Në fakt, vetë kategoria rrënjë e dyqanit në front gjithashtu nuk është e disponueshme, vetëm nënkategoritë e saj.

Duke qenë se tema e këtij artikulli megjithatë është importimi i të dhënave për produktet, nuk do ta përdor lidhjen e drejtpërdrejtë me bazën gjatë krijimit të kategorive, por do të përdor klasat që ofron vetë Magento (modelet dhe repozitoritë). Shkruajta drejtpërdrejt në bazë përdoret vetëm për të lidhur produktin e importuar me kategorinë (përputhja e kategorisë ndodh sipas emrit të saj, gjatë përputhjes nxirret id e kategorisë):

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 lidhjes sĂ« produktit me kategoritĂ« “Kategoria 1” dhe “Kategoria 2”, detajet e produktit nĂ« admin duken mĂ« pak kĂ«shtu:

Magento 2: importi i produkteve direkt në bazën e të dhënave

Veprimet e tjera

Pas përfundimit të importit të të dhënave, duhet të kryhen veprime të tjera:

  • indeksimi i tĂ« dhĂ«nave: thirrje nga konsola ./bin/magento indexer:reindex;
  • rregjenerimi i URL-ve pĂ«r produktet/kategoritĂ«: mund tĂ« pĂ«rdorĂ«sh zgjerimin “elgentos/regenerate-catalog-urls«

Produkte në admin pas përfundimit të veprimeve të tjera:

Magento 2: importi i produkteve direkt në bazën e të dhënave

dhe në front:

Magento 2: importi i produkteve direkt në bazën e të dhënave

Curriculum Vitae

E njĂ«jta grup produktesh (10 copa), si nĂ« artikullin e kaluar, importohet, sĂ« paku, me njĂ« rend mbrapa (1 sekondĂ« ndaj 10). PĂ«r njĂ« vlerĂ«sim mĂ« tĂ« saktĂ« tĂ« shpejtĂ«sisĂ« nevojiten mĂ« shumĂ« produkte — disa qindra, dhe mĂ« mirĂ« mijĂ«ra. MegjithatĂ«, edhe me kĂ«tĂ« madhĂ«si tĂ« vogĂ«l tĂ« tĂ« dhĂ«nave hyrĂ«se mund tĂ« arrijmĂ« nĂ« njĂ« pĂ«rfundim se pĂ«rdorimi i mjeteve tĂ« ofruara nga Magento (modelet dhe repozitoritĂ«) ndikon dukshĂ«m (theksoj — duke!) pĂ«rshpejtojnĂ« zhvillimin e funksionaliteteve tĂ« nevojshme, por gjithashtu (theksoj — duke!) ulin ndjeshĂ«m shbrendjen e tĂ« dhĂ«nave nĂ« bazĂ«n e tĂ« dhĂ«nave.

Si rezultat, uji doli të ishte i lagur dhe kjo nuk është ndonjë shpikje e re. Megjithatë, tani kam kodin për të eksperimentuar më tej dhe ndoshta për të bërë përfundime më interesante.

Burimi: habr.com

Bleni hostim tĂ« besueshĂ«m pĂ«r faqe me mbrojtje nga DDoS, serverĂ« VPS VDS đŸ”„ Bleni hostim tĂ« besueshĂ«m pĂ«r faqe me mbrojtje nga DDoS, serverĂ« VPS VDS | ProHoster