NĂ« UnĂ« pĂ«rshkrova procesin e importit tĂ« produkteve nĂ« Magento 2 nĂ« mĂ«nyrĂ«n e zakonshme â pĂ«rmes modeleve dhe repozitorĂ«ve. MĂ«nyra e zakonshme ka njĂ« shpejtĂ«si tĂ« pĂ«rpunimit tĂ« tĂ« dhĂ«nave qĂ« Ă«shtĂ« mjaft e ulĂ«t. NĂ« laptopin tim dilte rreth njĂ« produkt nĂ« sekondĂ«. NĂ« kĂ«tĂ« vazhdim, shqyrtoj njĂ« mĂ«nyrĂ« alternative tĂ« importit tĂ« produkteve â duke shkruar direkt nĂ« bazĂ«n e tĂ« dhĂ«nave, duke anashkaluar mekanizmat standardĂ« tĂ« Magento 2 (modelet, fabrikat, repozitorĂ«t). Seqvenca e hapave qĂ« sigurojnĂ« importin e produkteve mund tĂ« adaptohet pĂ«r çdo gjuhĂ« programimi qĂ« Ă«shtĂ« e aftĂ« tĂ« punojĂ« me MySQL.
Kufizimi: Në Magento ka funksionalitet të gatshëm për dhe me siguri do t'ju mjaftojë. Megjithatë, nëse ju nevojitet më shumë kontroll mbi procesin e importit, që nuk kufizohet në përgatitjen e një skedari CSV për atë që është, ju mirëpresim nën kat.

Kodi, që u krijua si rezultat i të shkruarit të të dyja artikujve, mund të shihet në modulit Magento "". Këtu janë disa kufizime që unë kam ndjekur për të thjeshtuar kodin e modulit demo:
- Produkti vetëm krijohet, nuk përditësohet.
- Një depo
- Importohen vetëm emrat e kategorive, pa strukturën e tyre
- Strukturat e të dhënave i përkasin versionit 2.3
JSON për importimin e një produkti të veçantë:
{
"sku": "MVA20D-UBV-3",
"name": "Mbyllës për plombimin VA47-29 IEK",
"desc": "Sigurimi i aksesit në pajisje ...",
"desc_short": "Mbyllësi për plombimin 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 etapa kryesore të importit
- regjistrimi i vetë produktit
- lidhja e produktit me web-in
- atributet bazë të produktit (EAV)
- të dhënat e inventarit (sasia e produktit në depo)
- mediat (imazhet)
- lidhja me kategoritë e katalologut
Regjistrimi i produktit
Informacioni bazë për 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 minimalisht i nevojshëm për krijimin e një regjistri produktesh:
attribute_set_idsku
shtesë:
type_idâ nĂ«se nuk e caktuam, do tĂ« pĂ«rdoret 'simple'
Për regjistrimin e drejtpërdrejtë në bazë përdor DB-adapterin e Magento-s:
function create($sku, $typeId, $attrSetId)
{
\/** @var MagentoFrameworkAppResourceConnection $this->resource *\/\n \/** @var MagentoFrameworkDBAdapterPdoMysql $conn *\/\n $conn = $this->resource->getConnection();\n $table = $this->resource->getTableName('catalog_product_entity');\n $bind = [\n 'sku' => $sku,\n 'type_id' => $typeId,\n 'attribute_set_id' => $attrSetId\n ];\n $conn->insert($table, $bind);\n $result = $conn->lastInsertId($table);\n return $result;\n}Pas regjistrimit të produktit në catalog_product_entity ai bëhet i dukshëm në administratë, në gridin e produkteve (Catalog / Products).

Lidhja e produktit me web-faqen
Lidhja e produktit me faqen definon në cilat dyqane dhe në cilat vitrina produkti do të jetë i aksesueshëm në front.
function linkToWebsite($prodId, $websiteId)
{
\/** @var MagentoFrameworkAppResourceConnection $this->resource *\/\n \/** @var MagentoFrameworkDBAdapterPdoMysql $conn *\/\n $conn = $this->resource->getConnection();\n $table = $this->resource->getTableName('catalog_product_website');\n $bind = [\n 'product_id' => $prodId,\n 'website_id' => $websiteId\n ];\n $conn->insert($table, $bind);\n}
Atributet bazë të produktit
Një produkt i saporegistruar ende nuk ka as emër dhe as përshkrim. Të gjitha këto bëhen nëpërmjet . Ja lista e atributve bazë të produktit, të cilat janë të nevojshme për të siguruar që prodotti të paraqitet mjaft saktë në front:
emripricedescriptionshort_descriptionstatustax_class_idurl_keyvisibility
Një atribut i veçantë për produktin shtohet kështu (detajet për marrë identifikatorin dhe tipin e 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 *\/\n $attrType = \/\* merr tipin e atributit [datetime|decimal|int|text|varchar] sipas kodit të atributit *\/\n if ($attrId) {\n \/** @var MagentoFrameworkAppResourceConnection $this->resource *\/\n \/** @var MagentoFrameworkDBAdapterPdoMysql $conn *\/\n $conn = $this->resource->getConnection();\n $tblName = 'catalog_product_entity_' . $attrType;\n $table = $this->resource->getTableName($tblName);\n $bind = [\n 'attribute_id' => $attrId,\n 'entity_id' => $prodId,\n \/\* vendos të gjitha atributet në pamjen e dyqanit të parazgjedhur me id=0 (administratë) *\/\n 'store_id' => 0,\n 'value' => $attrValue\n ];\n $conn->insert($table, $bind);\n }\n}Përmes kodit të atributit, përcaktojmë ID-në dhe tipin e të dhënave (datetime, decimal, int, text, varchar), pastaj në tabelen përkatëse shkruajmë të dhënat për vitrinën administrative (store_id = 0).
Pas shtimit të atributeve të përmendura të produktit, pamja në administratë duket kështu:

Të dhënat e inventarit
Nga versioni 2.3, Magento ka dy grupe tabelash që funksionojnë paralelisht për ruajtjen e informacionit të inventarit (sasia e produktit):
cataloginventory_*: struktura e vjetĂ«r;inventory_*: struktura e re (MSI â Multi Source Inventory);
Duhet të shtoni të dhëna inventari në të dy struktura, pasi struktura e re ende nuk është plotësisht e pavarur nga e vjetra (duket se për default depon në strukturën e re është përdorur tabela cataloginventory_stock_status si inventory_stock_1).
cataloginventory_
GjatĂ« implementimit tĂ« Magneto 2.3, fillimisht kemi 2 regjistrime nĂ« store_website, qĂ« pĂ«rkon me dy faqe â administratĂ«n dhe atĂ« 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 |D.m.th., në strukturën e vjetër kemi vetëm një «depo» (stock) dhe ajo është lidhur me faqen administruese. Shtimi i burimeve të reja sources/stocks në MSI (strukturën e re) nuk sjell krijimin e regjistrimeve të reja në cataloginventory_stock.
Të dhënat e inventarit për produktet në strukturën e vjetër inicialisht shkruhen në tabelat:
cataloginventory_stock_itemcataloginventory_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);
}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 |...|and one «magazina» (inventory_stock):
stock_id|name |
--------|-------------|
1|Default Stock|«Burimi» represents a physical storage for products (the record contains physical coordinates and postal address). «Magazina» represents a logical grouping of several «sources» (inventory_source_stock_link)
link_id|stock_id|source_code|priority|
-------|--------|-----------|--------|
1| 1|default | 1|at which the binding to the sales channel occurs (inventory_stock_sales_channel)
type |code|stock_id|
-------|----|--------|
website|base| 1|Judging by the data structure, various types of sales channels are assumed, but by default, only the connection «stock«-«website» (the link to the website goes by the website code â base).
One «magazina» can be linked to multiple «sources«, while one «burimi» can be linked to multiple «magazina» (the relationship is «many-to-many»). Exceptions are the default «burimi» dhe "magazina«. They cannot be re-linked to other entities (a code-level restriction â it throws an error «Can not save link related to Default Source or Default Stock«). More details about the MSI structure in Magento 2 can be found in the article ««.
I will use the default configuration and add all inventory information to the source default, which is involved in the sales channel related to the website with the code base (corresponds to the client side of the store â see. 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);
}After adding inventory data to the product in the admin panel, it looks like this:

Media
When adding images to a product manually through the admin panel, the corresponding information is recorded in the following tables:
catalog_product_entity_media_gallery: media registry (images and video files);catalog_product_entity_media_gallery_value: linking media to products and storefronts (localization);catalog_product_entity_media_gallery_value_to_entity: linking media only to products (presumably default media content for the product);catalog_product_entity_varchar: këtu ruajnë rolet ku përdoret imazhi;
ndĂ«rsa vetĂ« imazhet ruhen nĂ« katalog .\/pub\/media\/catalog\/product\/x\/y\/index x dhe y â shkronjat e para dhe tĂ« dyta tĂ« emrit tĂ« skedarit me imazhin. PĂ«r shembull, skedari image.png duhet tĂ« ruhet si ./pub/media/catalog/product/i/m/image.png, nĂ« mĂ«nyrĂ« qĂ« platforma ta pĂ«rdorĂ« si imazh nĂ« pĂ«rshkrimin e produkteve nga katalogu.
catalog_product_entity_media_gallery
Regjistrojmë skedarin mediatik në .\/pub\/media\/catalog\/product\/ skedari mediatik (procesi i vendosjes së skedarit në këtë artikull nuk shqyrtohet):
function createMediaGallery($imgPathPrefixed)
{
$attrId = /* merr id-në e atributit sipas kodit të 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, një skedari të ri media i jepet një identifikues.
catalog_product_entity_media_gallery_value
Lidhim skedarin mediatik të regjistruar me produktin për pasqyrë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 administrues si default */
'store_id' => 0,
'entity_id' => $prodId,
'label' => null,
/* ne kemi vetëm një imazh */
'position' => 1,
'disabled' => false
];
$conn->insert($table, $bind);
}catalog_product_entity_media_gallery_value_to_entity
Lidhim skedarin mediatik të regjistruar me produktin pa lidhje me ndonjë pasqyrë. Nuk është e qartë se ku përdoren këto të dhëna dhe pse nuk mund të referohemi te të dhënat e tabelës së mëparshme, por kjo tabelë ekziston dhe të dhënat regjistrohen në të kur shtohet një imazh në produkt. Prandaj, ashtu.
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ë kllapa është kodi i atributit përkatës):
- Base (
image) - Small Image (
small_image) - Thumbnail (
thumbnail) - Swatch Image (
swatch_image)
Lidhja e roleve me skedarin mediatik ndodh në catalog_product_entity_varchar. Kodi i lidhjes është ngjashëm me kodin në seksionin «Atributet bazë të produktit«.
Pas pastrimit të një imazhi në produktin në panelin e administratorit, duket kështu:

Kategoritë
Tabelat kryesore që përmbajnë të dhëna për kategoritë:
catalog_category_entity: regjistri i kategorive;catalog_category_product: lidhja midis produkteve dhe kategorive;catalog_category_entity_*: vlerat e atributeve EAV;
Fillimisht, nĂ« njĂ« aplikacion Magento tĂ« zbrazĂ«t, regjistri i kategorive pĂ«rmban 2 kategori (unĂ« shkurtoj 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 gjithë katalogut Magento dhe nuk është e aksesueshme as në panelin e administratorit, as në front. Kategoria me id=2 (Default Category) është kategoria rrënjë për dyqanin kryesor të sitit kryesor (Main Website Store), e krijuar gjatë shpërndarjes së aplikacionit (shih. Admin / Stores / All Stores). Për më tepër, vetë kategoria rrënjë e dyqanit në front gjithashtu nuk është e aksesueshme, vetëm nënkategoritë e saj.
Duke qenë se subjekti i këtij artikulli është importi i të dhënave për produktet, nuk do ta përdor regjistrimin e drejtpërdrejtë në bazë gjatë krijimit të kategorive, por do të përdor klasat e ofruara nga vetë Magento (modelet dhe depozitë). Regjistrimi i 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 shtimit të lidhjes së produktit me kategoritë "Kategoria 1" dhe "Kategoria 2", detajet e produktit në panelin e administratorit duken kështu:

Veprime shtesë
Pas përfundimit të importit të të dhënave, duhet të kryhen veprime të tjera:
- indeksimi i të dhënave: thirrja në konsolë
./bin/magento indexer:reindex; - rregjenerimi i URL-ve për produktet/kategoritë: mund të përdoret zgjatja "«
Produkte në panelin e administratorit pas kryerjes së veprimeve shtesë:

dhe në front:

CV
I njĂ«jtĂ« grup produktesh (10 copĂ«), siç ishte nĂ« artikullin e kaluar, importohet sĂ« paku njĂ« rend tĂ«rĂ« mĂ« shpejt (1 sekondĂ« kundrejt 10). PĂ«r njĂ« vlerĂ«sim mĂ« tĂ« saktĂ« tĂ« shpejtĂ«sisĂ« nevojiten mĂ« shumĂ« produkte â disa qindra, e mĂ« mirĂ« shumĂ« mijĂ«ra. MegjithatĂ«, madje edhe me kaq njĂ« numĂ«r tĂ« vogĂ«l tĂ« tĂ« dhĂ«nave hyrĂ«se, mund tĂ« arrihet nĂ« pĂ«rfundimin qĂ« pĂ«rdorimi i mjeteve tĂ« ofruara nga Magento (modelet dhe depozitat) ndihmon ndjeshĂ«m (theksoj â ndjeshĂ«m!) pĂ«r tĂ« pĂ«rshpejtuar zhvillimin e funksionalitetit tĂ« kĂ«rkuar, por njĂ«kohĂ«sisht ndihmojnĂ« ndjeshĂ«m (theksoj â ndjeshĂ«m!) nĂ« zvogĂ«limin e shpejtĂ«sisĂ« sĂ« futjes sĂ« tĂ« dhĂ«nave nĂ« bazĂ«.
Si përfundim, uji doli të ishte i lagësht dhe kjo nuk është ndonjë shpikje. Megjithatë, tani kam kodin për të vazhduar dhe ndoshta për të arritur përfundime më interesante.
Burimi: habr.com
