В anterioară articol Am descris procesul de import de produse în Magento 2 în modul obișnuit - prin modele și depozite. Metoda obișnuită are o viteză foarte mică de procesare a datelor. Laptopul meu producea aproximativ un produs pe secundă. În această continuare, consider o modalitate alternativă de a importa un produs - prin intrare directă în baza de date, ocolind mecanismele standard Magento 2 (modele, fabrici, depozite). Secvența de pași pentru importul produselor poate fi adaptată oricărui limbaj de programare care poate funcționa cu MySQL.
Declinare a responsabilităţii: Magento are o funcționalitate gata făcută pentru import de date și, cel mai probabil, îți va fi suficient. Cu toate acestea, dacă aveți nevoie de un control mai complet asupra procesului de import, fără a se limita la pregătirea unui fișier CSV pentru ceea ce aveți, bine ați venit la cat.
Codul rezultat din scrierea ambelor articole poate fi vizualizat in modulul Magento "flancer32/mage2_ext_demo_import". Iată câteva restricții pe care le-am urmat pentru a simplifica codul modulului demonstrativ:
Produsele sunt doar create, nu actualizate.
Un singur depozit
Sunt importate doar numele de categorii, fără structura lor
Structurile de date sunt conforme cu versiunea 2.3
JSON pentru importarea unui singur produs:
{
"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"
}
Prezentare generală a principalelor etape ale importului
înregistrarea produsului în sine
conexiune între produs și site-ul web
atributele de bază ale produsului (EAV)
date de inventar (cantitatea de produs în stoc)
media (imagini)
legătura cu categoriile de catalog
Inregistrarea produsului
Informațiile de bază despre produs pot fi găsite î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`)
)
Informațiile minime necesare pentru a crea o intrare în registrul produsului sunt:
attribute_set_id
sku
adiţional:
type_id — dacă nu o specificăm, atunci se va folosi „simple”.
Pentru a scrie direct în baza de date, folosesc adaptorul DB al Magento însuși:
Produsul nou înregistrat nu are încă un nume sau descriere. Toate acestea se fac prin Atributele EAV. Iată o listă cu atributele de bază ale produsului care sunt necesare pentru ca produsul să fie afișat corect pe față:
name
price
description
short_description
status
tax_class_id
url_key
visibility
Un atribut separat este adăugat unui produs ca acesta (detaliile obținerii identificatorului și tipului atributului din codul său sunt omise):
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);
}
}
Folosind codul de atribut, determinăm id-ul și tipul de date (datetime, decimal, int, text, varchar), apoi scrieți datele pentru fereastra administrativă în tabelul corespunzător (store_id = 0).
După adăugarea atributelor de mai sus la produs, obțineți această imagine în panoul de administrare:
Date de inventar
Începând cu versiunea 2.3 în Magento, există două seturi paralele de tabele care oferă stocarea informațiilor despre inventar (cantitatea de produs):
cataloginventory_*: structura veche;
inventory_*: structura noua (MSI - Multi Source Inventory);
Trebuie să adăugați date de inventar la ambele structuri, deoarece noua structură nu este încă complet independentă de cea veche (este foarte probabil ca pt default depozit în noua structură este implicată o masă cataloginventory_stock_status la fel de inventory_stock_1).
cataloginventory_
Când implementăm Magneto 2.3, avem inițial 2 intrări store_website, care corespunde a două site-uri - administrativ și client principal:
Adică, în vechea noastră structură există un singur „depozit” (stock) și este legat de site-ul administrativ. Adăugarea unor noi prin panoul de administrare sources/stocks în MSI (nouă structură) nu are ca rezultat noi intrări în cataloginventory_stock.
Datele de inventar despre produsele din vechea structură sunt inițial înregistrate în tabele:
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);
}
inventar_
Inițial, noua structură pentru stocarea datelor de inventar conține 1 "sursă'(inventory_source):
«Sursă» reprezintă depozitul fizic pentru produse (înregistrarea conține coordonatele fizice și adresa de corespondență). "Depozit„este o uniune logică a mai multor „surse” (inventory_source_stock_link)
la nivelul la care are loc conexiunea la canalul de vânzare (inventory_stock_sales_channel)
type |code|stock_id|
-------|----|--------|
website|base| 1|
Judecând după structura datelor, se presupun diverse tipuri de canale de vânzare, dar implicit doar conexiunea „stoc"-""(linkul către site urmează codul site-ului - base).
Unu "depozit"poate fi legat de mai multe"surse"și unul "sursă"-la mai multe"depozite„(relație multi-la-mulți). Excepțiile sunt implicite "sursă"Și"depozit". Ele nu sunt reconectate cu alte entități (limitare la nivel de cod - eroarea „Nu se poate salva linkul legat de Sursa implicită sau Stocul implicit"). Mai multe detalii despre structura MSI din Magento 2 pot fi găsite în articolul „Sistem de management al depozitelor folosind CQRS și Event Sourcing. Proiecta“.
Voi folosi configurația implicită și voi adăuga toate informațiile de inventar la sursă default, care este implicat în canalul de vânzare asociat site-ului cu codul base (corespunde cu partea din față a magazinului - vezi store_website):
După ce adăugați date de inventar la produs în panoul de administrare, obțineți această imagine:
Mass-media
Când adăugați „manual” o imagine la un produs prin panoul de administrare, informațiile relevante sunt notate în următoarele tabele:
catalog_product_entity_media_gallery: registru media (imagini si fisiere video);
catalog_product_entity_media_gallery_value: legarea mass-media la produse și vitrine (localizare);
catalog_product_entity_media_gallery_value_to_entity: conectarea media la produse numai (presumabil conținut media implicit pentru produs);
catalog_product_entity_varchar: Rolurile în care este folosită imaginea sunt stocate aici;
iar imaginile în sine sunt salvate în director ./pub/media/catalog/product/x/y/Unde x и y — prima și a doua literă ale numelui fișierului imagine. De exemplu, fișier image.png ar trebui salvat ca ./pub/media/catalog/product/i/m/image.png, astfel încât platforma să o poată folosi ca imagine atunci când descrie produsele din catalog.
catalog_product_entity_media_gallery
Înregistrare postat în ./pub/media/catalog/product/ fișier media (procesul de plasare a fișierului în sine nu este discutat în acest articol):
Asociem fișierul media înregistrat cu produsul corespunzător fără a fi legați de vreo vitrină. Nu este clar unde se folosesc exact aceste date și de ce este imposibil să accesezi datele din tabelul anterior, dar acest tabel există și datele sunt scrise în el când se adaugă o poză la produs. Deci asta este.
Un fișier media poate fi utilizat cu diferite roluri (codul de atribut corespunzător este indicat în paranteze):
Baza (image)
Imagine mică (small_image)
Miniatură (thumbnail)
Eșantion imagine (swatch_image)
Conectarea rolurilor la un fișier media este exact ceea ce se întâmplă în catalog_product_entity_varchar. Codul obligatoriu este similar cu codul din „Atributele de bază ale produsului“.
După adăugarea unei imagini la produs în panoul de administrare, arată astfel:
Categorie
Tabelele principale care conțin date pe categorii:
catalog_category_entity: registrul categoriilor;
catalog_category_product: legatura intre produse si categorii;
Categoria cu id=1 este rădăcina întregului catalog Magento și nu este disponibilă nici în panoul de administrare, nici pe prima pagină. Categorie cu id=2 (Implicit Categorie) este categoria rădăcină pentru magazinul principal al site-ului principal (Magazinul principal de site-uri web) creat atunci când aplicația este implementată (vezi. Administrator / Magazine / Toate magazinele). Mai mult decât atât, categoria rădăcină a magazinului în sine nu este disponibilă nici în față, ci doar subcategoriile sale.
Deoarece subiectul acestui articol este încă importul de date despre produse, nu voi folosi intrarea directă în baza de date atunci când creez categorii, ci voi folosi clasele oferite de Magento însuși (modele și depozitele). Intrarea directă în baza de date este utilizată numai pentru a asocia produsul importat cu o categorie (categoria este potrivită după numele acesteia, iar id-ul categoriei este preluat în timpul potrivirii):
Produse din panoul de administrare după efectuarea unor acțiuni suplimentare:
si in fata:
Rezumat
Același set de produse (10 bucăți) ca în articolul precedent este importat cu cel puțin un ordin de mărime mai rapid (1 secundă față de 10). Pentru a estima mai precis viteza, aveți nevoie de un număr mai mare de produse - câteva sute, sau mai bine zis mii. Cu toate acestea, chiar și cu o dimensiune atât de mică a datelor de intrare, putem concluziona că utilizarea instrumentelor furnizate de Magento (modele și depozite) este semnificativă (subliniez - mult!) accelerează dezvoltarea funcționalității necesare, dar în același timp semnificativ (subliniez - mult!) reduceți viteza cu care datele intră în baza de date.
Drept urmare, apa s-a dovedit a fi umedă și aceasta nu este o revelație. Cu toate acestea, acum am codul cu care să mă joc și poate ajung la niște concluzii mai interesante.