Magento 2: uvoz proizvoda direktno u bazu podataka
В prethodni članak Proces uvoza proizvoda u Magento 2 opisao sam na uobičajen način - kroz modele i repozitorije. Uobičajena metoda ima vrlo nisku brzinu obrade podataka. Moj laptop je proizvodio otprilike jedan proizvod u sekundi. U ovom nastavku razmatram alternativni način uvoza proizvoda - direktnim ulaskom u bazu podataka, zaobilazeći standardne Magento 2 mehanizme (modeli, fabrike, repozitorijumi). Redoslijed koraka za uvoz proizvoda može se prilagoditi bilo kojem programskom jeziku koji može raditi sa MySQL.
odricanje: Magento ima gotovu funkcionalnost za uvoz podataka i najvjerovatnije će vam to biti dovoljno. Međutim, ako vam je potrebna potpunija kontrola nad procesom uvoza, ne ograničena na pripremu CSV datoteke za ono što imate, dobrodošli u cat.
Kod nastao pisanjem oba članka može se vidjeti u Magento modulu "flancer32/mage2_ext_demo_import". Evo nekih ograničenja koja sam slijedio kako bih pojednostavio kod demo modula:
Proizvodi se samo kreiraju, ne ažuriraju.
Jedno skladište
Uvoze se samo nazivi kategorija, bez njihove strukture
Strukture podataka su u skladu sa verzijom 2.3
JSON za uvoz jednog proizvoda:
{
"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"
}
Pregled glavnih faza uvoza
registracija samog proizvoda
vezu između proizvoda i web stranice
osnovni atributi proizvoda (EAV)
podaci o zalihama (količina proizvoda na zalihama)
mediji (slike)
povezanost sa kataloškim kategorijama
Registracija proizvoda
Osnovne informacije o proizvodu možete pronaći u 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`)
)
Minimalne informacije potrebne za kreiranje unosa u registar proizvoda su:
attribute_set_id
sku
dodatno:
type_id — ako to ne navedemo, tada će se koristiti 'jednostavno'
Da pišem direktno u bazu podataka, koristim DB adapter samog Magenta:
Novoregistrirani proizvod još nema naziv ni opis. Sve se to radi kroz EAV atributi. Evo liste osnovnih atributa proizvoda koji su potrebni da bi proizvod bio ispravno prikazan na prednjoj strani:
name
price
description
short_description
status
tax_class_id
url_key
visibility
Zaseban atribut se dodaje proizvodu kao što je ovaj (detalji o dobijanju identifikatora i tipa atributa iz njegovog koda su izostavljeni):
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);
}
}
Koristeći kod atributa, određujemo njegov id i tip podataka (datetime, decimal, int, text, varchar), zatim upišite podatke za administrativni prozor u odgovarajuću tabelu (store_id = 0).
Nakon što proizvodu dodate gore navedene atribute, u admin panelu ćete dobiti ovu sliku:
Podaci o zalihama
Počevši od verzije 2.3 u Magentu, postoje dva paralelna skupa tabela koje omogućavaju skladištenje informacija o zalihama (količina proizvoda):
cataloginventory_*: stara struktura;
inventory_*: nova struktura (MSI - Multi Source Inventory);
Potrebno je dodati podatke o zalihama u obje strukture, jer nova struktura još nije potpuno nezavisna od stare (vrlo je vjerovatno da će za default magacin u novoj strukturi uključen je sto cataloginventory_stock_status kao inventory_stock_1).
kataloški inventar_
Kada implementiramo Magneto 2.3 u početku imamo 2 unosa store_website, što odgovara dvije lokacije - administrativnom i glavnom klijentu:
Odnosno, u našoj staroj strukturi postoji samo jedno „skladište“ (stock) i povezan je sa administrativnom web lokacijom. Dodavanje novih preko admin panela sources/stocks u MSI (nova struktura) ne rezultira novim unosima u cataloginventory_stock.
Podaci o zalihama proizvoda u staroj strukturi inicijalno se evidentiraju u tabelama:
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_
U početku, nova struktura za pohranjivanje podataka o zalihama sadrži 1 "izvor"(inventory_source):
«Izvor» predstavlja fizičko skladište za proizvode (zapis sadrži fizičke koordinate i poštansku adresu). "Skladište"je logičan spoj nekoliko "izvora" (inventory_source_stock_link)
na nivou na kojem dolazi do povezivanja sa prodajnim kanalom (inventory_stock_sales_channel)
type |code|stock_id|
-------|----|--------|
website|base| 1|
Sudeći po strukturi podataka, pretpostavljaju se različiti tipovi prodajnih kanala, ali standardno samo veza “zaliha"-"sajt"(link do web stranice prati kôd web stranice - base).
jedan "skladište"može se povezati na nekoliko"izvori"i jedan"izvor" - na nekoliko "skladišta"(odnos mnogo-prema-više). Izuzeci su zadani "izvor"I"skladište". Nisu ponovo povezani sa drugim entitetima (ograničenje na nivou koda - greška “Nije moguće sačuvati vezu koja se odnosi na zadani izvor ili zadanu zalihu"). Više detalja o MSI strukturi u Magento 2 možete pronaći u članku “Sistem upravljanja skladištem koristeći CQRS i Event Sourcing. Dizajn".
Koristit ću zadanu konfiguraciju i dodati sve informacije o inventaru izvoru default, koji je uključen u prodajni kanal povezan s web-mjestom s kodom base (odgovara prednjem kraju prodavnice - vidi store_website):
Nakon dodavanja podataka o zalihama proizvodu u admin panelu, dobijate ovu sliku:
Mediji
Prilikom “ručnog” dodavanja slike proizvodu preko admin panela, relevantne informacije su zapisane u sljedećim tabelama:
catalog_product_entity_media_gallery: registar medija (slike i video fajlovi);
catalog_product_entity_media_gallery_value: povezivanje medija sa proizvodima i izlozima (lokalizacija);
catalog_product_entity_media_gallery_value_to_entity: povezivanje medija samo sa proizvodima (vjerovatno zadani medijski sadržaj za proizvod);
catalog_product_entity_varchar: Ovdje se pohranjuju uloge u kojima se slika koristi;
a same slike se spremaju u direktorij ./pub/media/catalog/product/x/y/gde x и y — prvo i drugo slovo naziva datoteke slike. Na primjer, fajl image.png treba sačuvati kao ./pub/media/catalog/product/i/m/image.png, tako da ga platforma može koristiti kao sliku pri opisivanju proizvoda iz kataloga.
catalog_product_entity_media_gallery
Registracija objavljena u ./pub/media/catalog/product/ medijski fajl (proces postavljanja samog fajla nije razmatran u ovom članku):
Mi povezujemo registrovanu medijsku datoteku sa odgovarajućim proizvodom bez vezivanja za bilo koji izlog. Nije jasno gdje se tačno ti podaci koriste i zašto je nemoguće pristupiti podacima iz prethodne tabele, ali ova tabela postoji i podaci se u nju upisuju kada se slika doda u proizvod. To je to.
Medijska datoteka se može koristiti s različitim ulogama (odgovarajući kod atributa je naveden u zagradama):
baza(image)
mala slika (small_image)
Sličica (thumbnail)
Uzorak slike (swatch_image)
Povezivanje uloga sa medijskim fajlom je upravo ono što se dešava u njemu catalog_product_entity_varchar. Vezivni kod je sličan kodu u "Osnovni atributi proizvoda".
Nakon dodavanja slike proizvodu u admin panel to izgleda ovako:
Kategorije
Glavne tabele koje sadrže podatke po kategorijama:
catalog_category_entity: registar kategorija;
catalog_category_product: povezanost proizvoda i kategorija;
catalog_category_entity_*: EAV vrijednosti atributa;
U početku, u praznoj Magento aplikaciji, registar kategorija sadrži 2 kategorije (skratio sam nazive kolona: crt - created_at, upd - updated_at):
Kategorija s id=1 je korijen cijelog Magento kataloga i nije dostupna ni u admin panelu ni na naslovnoj stranici. Kategorija sa id=2 (Zadana kategorija) je osnovna kategorija za glavnu trgovinu glavne stranice (Glavna web stranica prodavnica) kreiran kada se aplikacija implementira (pogledajte. Admin / Prodavnice / Sve prodavnice). Štaviše, osnovna kategorija same prodavnice takođe nije dostupna na prednjoj strani, već samo njene potkategorije.
Budući da je tema ovog članka još uvijek uvoz podataka o proizvodima, neću koristiti direktan ulazak u bazu podataka prilikom kreiranja kategorija, već ću koristiti klase koje pruža sam Magento (modeli i spremišta). Direktan ulazak u bazu podataka koristi se samo za povezivanje uvezenog proizvoda sa kategorijom (kategorija se poklapa sa njenim imenom, a id kategorije se preuzima tokom uparivanja):
Proizvodi u admin panelu nakon izvođenja dodatnih radnji:
i na prednjoj strani:
Rezime
Isti set proizvoda (10 komada) kao u prethodnom članku uvozi se barem red veličine brže (1 sekunda naspram 10). Da biste preciznije procijenili brzinu, potreban vam je veći broj proizvoda - nekoliko stotina, ili još bolje hiljade. Međutim, čak i uz tako malu veličinu ulaznih podataka, možemo zaključiti da je upotreba alata koje pruža Magento (modeli i repozitoriji) značajna (naglašavam - mnogo!) ubrzavaju razvoj potrebne funkcionalnosti, ali u isto vrijeme značajno (naglašavam - mnogo!) smanjiti brzinu kojom podaci ulaze u bazu podataka.
Kao rezultat toga, voda se pokazala mokrom i to nije otkriće. Međutim, sada imam kod za igru i možda ću doći do nekih zanimljivijih zaključaka.