Magento 2: importuokite produktus tiesiai į duomenų bazę
В ankstesnis straipsnis Produktų importavimo į Magento 2 procesą aprašiau įprastu būdu – per modelius ir saugyklas. Įprastas metodas turi labai mažą duomenų apdorojimo greitį. Mano nešiojamas kompiuteris gamino maždaug vieną produktą per sekundę. Šiame tęsinyje svarstau alternatyvų būdą importuoti produktą – tiesioginiu įvedimu į duomenų bazę, apeinant standartinius Magento 2 mechanizmus (modelius, gamyklas, saugyklas). Produktų importavimo veiksmų seka gali būti pritaikyta bet kuriai programavimo kalbai, kuri gali veikti su MySQL.
Atsakomybės neigimas: Magento turi paruoštas funkcijas duomenų importas ir, greičiausiai, tau to užteks. Tačiau, jei jums reikia išsamesnės importo proceso kontrolės, neapsiribojant CSV failo paruošimu tam, ką turite, sveiki atvykę į cat.
Kodą, gautą parašius abu straipsnius, galite peržiūrėti Magento modulyje "flancer32/mage2_ext_demo_import“. Štai keletas apribojimų, kurių laikiausi norėdamas supaprastinti demonstracinio modulio kodą:
Produktai tik kuriami, o ne atnaujinami.
Vienas sandėlis
Importuojami tik kategorijų pavadinimai be jų struktūros
Duomenų struktūros atitinka 2.3 versiją
JSON vienam produktui importuoti:
{
"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"
}
Pagrindinių importo etapų apžvalga
paties gaminio registracija
ryšys tarp produkto ir svetainės
pagrindinės produkto savybės (EAV)
atsargų duomenys (produkto kiekis sandėlyje)
žiniasklaida (nuotraukos)
ryšys su katalogo kategorijomis
Produkto registracija
Pagrindinę informaciją apie gaminį galite rasti 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`)
)
Minimali informacija, reikalinga norint sukurti įrašą produktų registre, yra:
attribute_set_id
sku
papildomas:
type_id — jei nenurodysime, bus naudojamas „paprastas“.
Norėdami rašyti tiesiai į duomenų bazę, naudoju paties Magento DB adapterį:
Naujai registruotas produktas dar neturi pavadinimo ar aprašymo. Visa tai daroma per EAV atributika. Čia pateikiamas pagrindinių produkto atributų, reikalingų, kad produktas būtų tinkamai rodomas priekinėje pusėje, sąrašas:
name
price
description
short_description
status
tax_class_id
url_key
visibility
Prie tokio produkto pridedamas atskiras atributas (išsami informacija apie identifikatoriaus gavimą ir atributo tipą iš jo kodo praleista):
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);
}
}
Naudodami atributo kodą nustatome jo ID ir duomenų tipą (datetime, decimal, int, text, varchar), tada įrašykite administracinio lango duomenis į atitinkamą lentelę (store_id = 0).
Pridėję aukščiau nurodytus atributus prie produkto, administratoriaus skydelyje gausite šią nuotrauką:
Inventorizacijos duomenys
Pradedant nuo 2.3 versijos Magento, yra du lygiagrečiai lentelių rinkiniai, kuriuose saugoma atsargų informacija (produkto kiekis):
cataloginventory_*: sena konstrukcija;
inventory_*: nauja struktūra (MSI – Multi Source Inventory);
Turite pridėti atsargų duomenis prie abiejų struktūrų, nes nauja struktūra dar nėra visiškai nepriklausoma nuo senosios (labai tikėtina, kad už default sandėlyje naujoje struktūroje yra įtrauktas stalas cataloginventory_stock_status kaip inventory_stock_1).
katalogo inventorius_
Diegdami Magneto 2.3 iš pradžių turime 2 įrašus store_website, kuri atitinka dvi svetaines – administracinę ir pagrindinę klientą:
Tai yra, mūsų senoje struktūroje yra tik vienas „sandėlis“ (stock) ir ji yra susijusi su administracine svetaine. Naujų įtraukimas per administratoriaus skydelį sources/stocks MSI (nauja struktūra) nesukelia naujų įrašų cataloginventory_stock.
Atsargų duomenys apie senosios struktūros produktus iš pradžių įrašomi į lenteles:
cataloginventory_stock_item
cataloginventory_stock_status
Katalogo inventoriaus_atsargos_prekė
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);
}
katalogo inventoriaus_atsargos_būsena
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);
}
inventorius_
Iš pradžių naujoje atsargų duomenų saugojimo struktūroje yra 1 "šaltinis"(inventory_source):
«šaltinis» reiškia fizinę produktų saugyklą (įraše yra fizinės koordinatės ir pašto adresas). “Sandėlis"yra logiška kelių "šaltinių" sąjunga (inventory_source_stock_link)
lygiu, kuriame atsiranda prisijungimas prie pardavimo kanalo (inventory_stock_sales_channel)
type |code|stock_id|
-------|----|--------|
website|base| 1|
Sprendžiant iš duomenų struktūros, daroma prielaida, kad yra įvairių tipų pardavimo kanalai, tačiau pagal nutylėjimą tik ryšys “akcijos„-“Interneto svetainė"(nuoroda į svetainę yra po svetainės kodu - base).
vienas"sandėlis"gali būti susietas su keliais"šaltiniai"ir vienas "šaltinis"- keliems"sandėliai(santykis „daugelis su daugeliu“). Išimtys yra numatytosios "šaltinis"Ir"sandėlis“. Jie nėra iš naujo susieti su kitais objektais (ribojimas kodo lygiu - klaida “Nepavyko išsaugoti nuorodos, susijusios su numatytuoju šaltiniu arba numatytosiomis atsargomis“). Daugiau informacijos apie MSI struktūrą Magento 2 rasite straipsnyje "Sandėlio valdymo sistema naudojant CQRS ir Event Sourcing. Dizainas"
Naudosiu numatytąją konfigūraciją ir visą informaciją apie atsargas įtrauksiu į šaltinį default, kuris dalyvauja pardavimo kanale, susietame su kodu su svetaine base (atitinka parduotuvės priekinę dalį – žr store_website):
Pridėję atsargų duomenis prie produkto administratoriaus skydelyje, gausite šį paveikslėlį:
Žiniasklaida
Kai „rankiniu būdu“ pridedate vaizdą prie gaminio per administratoriaus skydelį, atitinkama informacija užrašoma šiose lentelėse:
catalog_product_entity_media_gallery: medijos registras (vaizdai ir vaizdo failai);
catalog_product_entity_media_gallery_value: žiniasklaidos susiejimas su produktais ir vitrinomis (lokalizacija);
catalog_product_entity_media_gallery_value_to_entity: medijos susiejimas tik su produktais (turbūt numatytasis produkto medijos turinys);
catalog_product_entity_varchar: čia saugomi vaidmenys, kuriuose naudojamas vaizdas;
o patys vaizdai išsaugomi kataloge ./pub/media/catalog/product/x/y/Kur x и y — pirmoji ir antroji vaizdo failo pavadinimo raidės. Pavyzdžiui, failas image.png turėtų būti išsaugotas kaip ./pub/media/catalog/product/i/m/image.png, kad platforma galėtų naudoti jį kaip vaizdą aprašant produktus iš katalogo.
catalog_product_entity_media_gallery
Registracija paskelbta ./pub/media/catalog/product/ medijos failą (pats failo įdėjimo procesas šiame straipsnyje neaptariamas):
Mes susiejame registruotą medijos failą su atitinkamu produktu nesusiedami su jokiu parduotuvės filialu. Neaišku, kur tiksliai šie duomenys naudojami ir kodėl neįmanoma prieiti prie ankstesnės lentelės duomenų, tačiau ši lentelė egzistuoja ir į ją įrašomi duomenys, kai prie gaminio pridedamas paveikslėlis. Taigi viskas.
Medijos failas gali būti naudojamas su skirtingais vaidmenimis (skliausteliuose nurodytas atitinkamas atributo kodas):
Bazė(image)
Mažas vaizdas (small_image)
Miniatiūra (thumbnail)
Swatch vaizdas (swatch_image)
Vaidmenų susiejimas su medijos failu yra būtent tai, kas vyksta catalog_product_entity_varchar. Įrišimo kodas yra panašus į kodą „Pagrindinės produkto savybės"
Pridėjus vaizdą prie produkto administratoriaus skydelyje, jis atrodo taip:
Категории
Pagrindinės lentelės su duomenimis pagal kategorijas:
catalog_category_entity: kategorijų registras;
catalog_category_product: ryšys tarp produktų ir kategorijų;
catalog_category_entity_*: EAV atributų reikšmės;
Iš pradžių tuščioje „Magento“ programoje kategorijų registre yra 2 kategorijos (stulpelių pavadinimus sutrumpinau: crt - created_at, upd - updated_at):
Kategorija su id=1 yra viso Magento katalogo šaknis ir nepasiekiama nei administratoriaus skydelyje, nei pirmajame puslapyje. Kategorija su id=2 (Numatytoji kategorija) yra pagrindinės svetainės pagrindinės parduotuvės šakninė kategorija (Pagrindinė internetinė parduotuvė), sukurtas diegiant programą (žr. Administratorius / Parduotuvės / Visos parduotuvės). Be to, pačios parduotuvės šakninės kategorijos priekyje taip pat nėra, tik jos subkategorijos.
Kadangi šio straipsnio tema vis dar yra duomenų apie gaminius importavimas, tai kurdamas kategorijas nenaudosiu tiesioginio įėjimo į duomenų bazę, o naudosiu paties Magento pateiktas klases (modelius ir saugyklas). Tiesioginis įėjimas į duomenų bazę naudojamas tik susieti importuotą prekę su kategorija (kategorija suderinama pagal jos pavadinimą, o derinimo metu gaunamas kategorijos ID):
Produktai administratoriaus skydelyje atlikus papildomus veiksmus:
ir priekyje:
Santrauka
Tas pats gaminių rinkinys (10 vnt.), kaip ir ankstesniame straipsnyje, importuojamas bent dydžiu greičiau (1 sekundė, palyginti su 10). Norint tiksliau įvertinti greitį, reikia didesnio gaminių kiekio – kelių šimtų, o dar geriau tūkstančių. Tačiau net ir turėdami tokį mažą įvesties duomenų dydį galime daryti išvadą, kad Magento teikiamų įrankių (modelių ir saugyklų) naudojimas yra reikšmingas (pabrėžiu - daug!) paspartinti reikiamo funkcionalumo kūrimą, bet tuo pačiu žymiai (pabrėžiu - daug!) sumažinkite duomenų patekimo į duomenų bazę greitį.
Dėl to vanduo pasirodė šlapias ir tai nėra apreiškimas. Tačiau dabar turiu kodą, su kuriuo galiu žaisti, ir galbūt padarysiu įdomesnių išvadų.