Magento 2: importer produkter direkte inn i databasen
В forrige artikkel Jeg beskrev prosessen med å importere produkter til Magento 2 på vanlig måte – gjennom modeller og repositories. Den vanlige metoden har svært lav databehandlingshastighet. Den bærbare datamaskinen min produserte omtrent ett produkt per sekund. I denne fortsettelsen vurderer jeg en alternativ måte å importere et produkt på - ved å gå direkte inn i databasen, omgå standard Magento 2-mekanismer (modeller, fabrikker, depoter). Sekvensen av trinn for å importere produkter kan tilpasses et hvilket som helst programmeringsspråk som kan fungere med MySQL.
Ansvarsfraskrivelse: Magento har ferdig funksjonalitet for dataimport og mest sannsynlig vil det være nok for deg. Men hvis du trenger mer fullstendig kontroll over importprosessen, ikke begrenset til å forberede en CSV-fil for det du har, velkommen til cat.
Koden som er et resultat av å skrive begge artiklene kan sees i Magento-modulen "flancer32/mage2_ext_demo_import". Her er noen begrensninger jeg fulgte for å forenkle demomodulkoden:
Produkter opprettes kun, ikke oppdatert.
Ett lager
Bare kategorinavn importeres, uten struktur
Datastrukturer er i samsvar med versjon 2.3
JSON for import av ett enkelt produkt:
{
"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"
}
Oversikt over hovedstadiene av import
registrering av selve produktet
forbindelse mellom produkt og nettside
grunnleggende produktattributter (EAV)
lagerdata (antall produkt på lager)
media (bilder)
forbindelse med katalogkategorier
Produkt registrering
Grunnleggende produktinformasjon finner du i 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`)
)
Minimumsinformasjonen som kreves for å opprette en oppføring i produktregisteret er:
attribute_set_id
sku
ytterligere:
type_id - hvis vi ikke spesifiserer det, vil 'enkel' bli brukt
For å skrive direkte til databasen bruker jeg DB-adapteren til Magento selv:
Det nyregistrerte produktet har ennå ikke navn eller beskrivelse. Alt dette er gjort gjennom EAV-attributter. Her er en liste over grunnleggende produktattributter som er nødvendige for at produktet skal vises riktig på forsiden:
name
price
description
short_description
status
tax_class_id
url_key
visibility
Et eget attributt legges til et produkt som dette (detaljene for å få identifikatoren og typen av attributtet fra koden er utelatt):
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);
}
}
Ved å bruke attributtkoden bestemmer vi dens id og datatype (datetime, decimal, int, text, varchar), skriv deretter dataene for det administrative vinduet inn i den aktuelle tabellen (store_id = 0).
Etter å ha lagt til attributtene ovenfor til produktet, får du dette bildet i administrasjonspanelet:
Inventardata
Fra og med versjon 2.3 i Magento er det to parallelle sett med tabeller som gir lagring av lagerinformasjon (produktmengde):
cataloginventory_*: gammel struktur;
inventory_*: ny struktur (MSI - Multi Source Inventory);
Du må legge til inventardata til begge strukturene, fordi den nye strukturen er ennå ikke helt uavhengig av den gamle (det er svært sannsynlig at for default lager i den nye strukturen et bord er involvert cataloginventory_stock_status som inventory_stock_1).
katalogbeholdning_
Når vi distribuerer Magneto 2.3, har vi i utgangspunktet 2 oppføringer store_website, som tilsvarer to nettsteder - administrativ og hovedklient:
Det vil si at i vår gamle struktur er det bare ett "lager" (stock) og den er koblet til det administrative nettstedet. Legger til nye gjennom administrasjonspanelet sources/stocks i MSI (ny struktur) resulterer ikke i nye oppføringer i cataloginventory_stock.
Lagerdata om produkter i den gamle strukturen blir først registrert i tabeller:
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_
I utgangspunktet inneholder den nye strukturen for lagring av lagerdata 1 "kilde"(inventory_source):
«Kilde» representerer den fysiske lagringen for produkter (posten inneholder fysiske koordinater og postadresse). "Lager"er en logisk forening av flere "kilder" (inventory_source_stock_link)
på nivået der koblingen til salgskanalen skjer (inventory_stock_sales_channel)
type |code|stock_id|
-------|----|--------|
website|base| 1|
Ut fra datastrukturen å dømme, antas det ulike typer salgskanaler, men som standard bare tilkoblingen "lager"-"nettsted"(lenken til nettstedet følger nettstedskoden - base).
En "lager"kan knyttes til flere"til kilder"og en "kilde"- til flere"varehus"(mange-til-mange forhold). Unntakene er standard "kilde"Og"lager". De er ikke koblet til andre enheter (begrensning på kodenivå - feilen "Kan ikke lagre koblingen relatert til standardkilde eller standardlager"). Flere detaljer om MSI-strukturen i Magento 2 finner du i artikkelen "Lagerstyringssystem som bruker CQRS og Event Sourcing. Design".
Jeg vil bruke standardkonfigurasjonen og legge til all inventarinformasjon til kilden default, som er involvert i salgskanalen knyttet til nettstedet med koden base (tilsvarer forsiden av butikken - se store_website):
Etter å ha lagt til lagerdata til produktet i administrasjonspanelet, får du dette bildet:
media
Når du "manuelt" legger til et bilde til et produkt gjennom administrasjonspanelet, skrives den relevante informasjonen ned i følgende tabeller:
catalog_product_entity_media_gallery: medieregister (bilder og videofiler);
catalog_product_entity_media_gallery_value: koble media til produkter og utstillingsvinduer (lokalisering);
catalog_product_entity_media_gallery_value_to_entity: kun koble media til produkter (antagelig standard medieinnhold for produktet);
catalog_product_entity_varchar: Rollene som bildet brukes i lagres her;
og selve bildene lagres i katalogen ./pub/media/catalog/product/x/y/Der x и y — den første og andre bokstaven i bildefilnavnet. For eksempel fil image.png skal lagres som ./pub/media/catalog/product/i/m/image.png, slik at plattformen kan bruke den som et bilde når den skal beskrive produkter fra katalogen.
catalog_product_entity_media_galleri
Registrering lagt inn ./pub/media/catalog/product/ mediefil (prosessen med å plassere selve filen er ikke omtalt i denne artikkelen):
Vi knytter den registrerte mediefilen til det tilsvarende produktet uten å være knyttet til noen butikkfront. Det er ikke klart hvor nøyaktig disse dataene brukes og hvorfor det er umulig å få tilgang til dataene fra forrige tabell, men denne tabellen eksisterer og dataene skrives til den når et bilde legges til produktet. Så det er det.
En mediefil kan brukes med forskjellige roller (den tilsvarende attributtkoden er angitt i parentes):
Utgangspunkt (image)
Lite bilde (small_image)
Miniatyrbilde (thumbnail)
Swatch-bilde (swatch_image)
Å koble roller til en mediefil er akkurat det som skjer i catalog_product_entity_varchar. Bindingskoden ligner på koden i "Grunnleggende produktegenskaper".
Etter å ha lagt til et bilde til produktet i administrasjonspanelet ser det slik ut:
kategori
Hovedtabeller som inneholder data etter kategori:
catalog_category_entity: register over kategorier;
catalog_category_product: sammenheng mellom produkter og kategorier;
catalog_category_entity_*: EAV-attributtverdier;
Til å begynne med, i en tom Magento-applikasjon, inneholder kategoriregisteret 2 kategorier (jeg forkortet kolonnenavnene: crt - created_at, upd - updated_at):
Kategorien med id=1 er roten til hele Magento-katalogen og er ikke tilgjengelig verken i administrasjonspanelet eller på forsiden. Kategori med id=2 (standard kategori) er rotkategorien for hovednettstedets hovedbutikk (Hovednettstedsbutikk) opprettet når applikasjonen er distribuert (se. Admin / Butikker / Alle butikker). Dessuten er rotkategorien til selve butikken heller ikke tilgjengelig foran, bare underkategoriene.
Siden emnet for denne artikkelen fortsatt er import av data på produkter, vil jeg ikke bruke direkte oppføring i databasen når jeg oppretter kategorier, men vil bruke klassene levert av Magento selv (modeller og repositories). Direkte oppføring i databasen brukes bare for å knytte det importerte produktet til en kategori (kategorien samsvarer med navnet, og kategori-ID-en hentes under matching):
Produkter i administrasjonspanelet etter å ha utført ytterligere handlinger:
og foran:
Oppsummering
Det samme settet med produkter (10 stykker) som i forrige artikkel importeres minst en størrelsesorden raskere (1 sekund mot 10). For å estimere hastigheten mer nøyaktig, trenger du et større antall produkter - flere hundre, eller enda bedre tusenvis. Men selv med en så liten størrelse på inndata, kan vi konkludere med at bruken av verktøyene levert av Magento (modeller og depoter) er betydelig (jeg understreker - mye!) fremskynde utviklingen av den nødvendige funksjonaliteten, men samtidig betydelig (jeg understreker - mye!) redusere hastigheten som data kommer inn i databasen med.
Som et resultat viste vannet seg å være vått, og dette er ikke en åpenbaring. Men nå har jeg koden å leke med og kanskje komme til noen mer interessante konklusjoner.