Magento 2: importera produkter direkt till databasen
В tidigare artikel Jag beskrev processen att importera produkter till Magento 2 på vanligt sätt - genom modeller och arkiv. Den vanliga metoden har en mycket låg databehandlingshastighet. Min bärbara dator producerade ungefär en produkt per sekund. I den här fortsättningen överväger jag ett alternativt sätt att importera en produkt - genom att gå direkt in i databasen, förbi de vanliga Magento 2-mekanismerna (modeller, fabriker, repositories). Sekvensen av steg för att importera produkter kan anpassas till alla programmeringsspråk som kan fungera med MySQL.
Villkor: Magento har färdig funktionalitet för dataimport och troligen kommer det att räcka för dig. Men om du behöver mer fullständig kontroll över importprocessen, inte begränsat till att förbereda en CSV-fil för det du har, välkommen till cat.
Koden som är resultatet av att skriva båda artiklarna kan ses i Magento-modulen "flancer32/mage2_ext_demo_import". Här är några begränsningar jag följde för att förenkla demomodulkoden:
Produkter skapas endast, inte uppdateras.
Ett lager
Endast kategorinamn importeras, utan deras struktur
Datastrukturer följer version 2.3
JSON för att importera en enskild 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"
}
Översikt över importens huvudstadier
registrering av själva produkten
koppling mellan produkt och webbplats
grundläggande produktattribut (EAV)
lagerdata (mängd produkt i lager)
media (bilder)
koppling till katalogkategorier
Produktregistrering
Grundläggande produktinformation finns 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`)
)
Den minsta information som krävs för att skapa en post i produktregistret är:
attribute_set_id
sku
ytterligare:
type_id — om vi inte anger det kommer 'enkel' att användas
För att skriva direkt till databasen använder jag Magentos DB-adapter:
Den nyregistrerade produkten har ännu inget namn eller beskrivning. Allt detta görs igenom EAV-attribut. Här är en lista över grundläggande produktattribut som behövs för att produkten ska visas korrekt på framsidan:
name
price
description
short_description
status
tax_class_id
url_key
visibility
Ett separat attribut läggs till en produkt som denna (detaljerna för att erhålla identifieraren och typen av attributet från dess kod utelämnas):
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);
}
}
Med hjälp av attributkoden bestämmer vi dess id och datatyp (datetime, decimal, int, text, varchar), skriv sedan data för det administrativa fönstret i lämplig tabell (store_id = 0).
Efter att ha lagt till ovanstående attribut till produkten får du denna bild i adminpanelen:
Inventeringsdata
Från och med version 2.3 i Magento finns det två parallella uppsättningar tabeller som tillhandahåller lagring av lagerinformation (produktkvantitet):
cataloginventory_*: gammal struktur;
inventory_*: ny struktur (MSI - Multi Source Inventory);
Du måste lägga till lagerdata till båda strukturerna, eftersom den nya strukturen är ännu inte helt oberoende av den gamla (det är mycket troligt att för default lager i den nya strukturen ett bord är inblandat cataloginventory_stock_status som inventory_stock_1).
kataloginventering_
När vi distribuerar Magneto 2.3 har vi initialt 2 poster i store_website, vilket motsvarar två webbplatser - administrativ och huvudklient:
Det vill säga, i vår gamla struktur finns det bara ett "lager" (stock) och den är länkad till den administrativa webbplatsen. Lägger till nya via adminpanelen sources/stocks i MSI (ny struktur) resulterar inte i nya poster i cataloginventory_stock.
Lagerdata om produkter i den gamla strukturen registreras initialt 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);
}
lager_
Inledningsvis innehåller den nya strukturen för lagring av lagerdata 1 "källa'(inventory_source):
«Källa» representerar den fysiska lagringen för produkter (posten innehåller fysiska koordinater och postadress). "lager"är en logisk förening av flera "källor" (inventory_source_stock_link)
på den nivå där kopplingen till försäljningskanalen sker (inventory_stock_sales_channel)
type |code|stock_id|
-------|----|--------|
website|base| 1|
Att döma av datastrukturen antas olika typer av försäljningskanaler, men som standard endast kopplingen "lager"-"webbplats"(länken till webbplatsen följer webbplatskoden - base).
Ett "lager"kan kopplas till flera"källor"och en "källa"- till flera"lager"(många-till-många relation). Undantagen är standard"källa"Och"lager". De är inte återlänkade till andra enheter (begränsning på kodnivå - felet "Det går inte att spara länk relaterad till standardkälla eller standardlager"). Mer information om MSI-strukturen i Magento 2 finns i artikeln "Lagerhanteringssystem med CQRS och Event Sourcing. Design".
Jag kommer att använda standardkonfigurationen och lägga till all inventeringsinformation till källan default, som är involverad i den försäljningskanal som är kopplad till webbplatsen med koden base (motsvarar framsidan av butiken - se store_website):
När du har lagt till lagerdata till produkten i adminpanelen får du den här bilden:
media
När du "manuellt" lägger till en bild till en produkt via adminpanelen, skrivs relevant information ned i följande tabeller:
catalog_product_entity_media_gallery: medieregister (bilder och videofiler);
catalog_product_entity_media_gallery_value: länka media till produkter och skyltfönster (lokalisering);
catalog_product_entity_media_gallery_value_to_entity: länkar endast media till produkter (förmodligen standardmedieinnehåll för produkten);
catalog_product_entity_varchar: De roller som bilden används i lagras här;
och själva bilderna sparas i katalogen ./pub/media/catalog/product/x/y/var x и y — första och andra bokstäverna i bildfilens namn. Till exempel fil image.png bör sparas som ./pub/media/catalog/product/i/m/image.png, så att plattformen kan använda den som en bild när man beskriver produkter från katalogen.
catalog_product_entity_media_gallery
Registrera inlagt i ./pub/media/catalog/product/ mediafil (processen för att placera själva filen diskuteras inte i den här artikeln):
Vi associerar den registrerade mediefilen med motsvarande produkt utan att vara bundna till något skyltfönster. Det är inte klart var exakt denna data används och varför det är omöjligt att komma åt data från föregående tabell, men denna tabell finns och data skrivs till den när en bild läggs till produkten. Så det är det.
En mediafil kan användas med olika roller (motsvarande attributkod anges inom parentes):
Bas(image)
Liten bild (small_image)
Miniatyr (thumbnail)
Swatch-bild (swatch_image)
Att länka roller till en mediefil är precis vad som händer i catalog_product_entity_varchar. Bindningskoden liknar koden i "Grundläggande produktegenskaper".
Efter att ha lagt till en bild till produkten i adminpanelen ser det ut så här:
kategori
Huvudtabeller som innehåller data per kategori:
catalog_category_entity: register över kategorier;
catalog_category_product: samband mellan produkter och kategorier;
catalog_category_entity_*: EAV-attributvärden;
Till en början, i en tom Magento-applikation, innehåller kategoriregistret 2 kategorier (jag förkortade kolumnnamnen: crt - created_at, upd - updated_at):
Kategorin med id=1 är roten till hela Magento-katalogen och är inte tillgänglig vare sig i adminpanelen eller på framsidan. Kategori med id=2 (standard~~POS=TRUNC Kategori) är rotkategorin för huvudsajtens huvudbutik (Huvudwebbbutik) skapas när applikationen distribueras (se. Admin / Butiker / Alla butiker). Dessutom är rotkategorin för själva butiken inte tillgänglig på framsidan, bara dess underkategorier.
Eftersom ämnet för den här artikeln fortfarande är att importera data om produkter, kommer jag inte att använda direkt inmatning i databasen när jag skapar kategorier, utan kommer att använda klasserna som tillhandahålls av Magento själv (modeller och repositories). Direktinmatning i databasen används endast för att associera den importerade produkten med en kategori (kategorin matchas av dess namn, och kategori-id hämtas under matchning):
Produkter i adminpanelen efter att ha utfört ytterligare åtgärder:
och längst fram:
Sammanfattning
Samma uppsättning produkter (10 stycken) som i föregående artikel importeras minst en storleksordning snabbare (1 sekund mot 10). För att mer exakt uppskatta hastigheten behöver du ett större antal produkter - flera hundra, eller ännu bättre tusentals. Men även med en så liten storlek på indata kan vi dra slutsatsen att användningen av verktygen från Magento (modeller och arkiv) är betydande (jag betonar - mycket!) påskynda utvecklingen av den nödvändiga funktionaliteten, men samtidigt avsevärt (jag betonar - mycket!) minska hastigheten med vilken data kommer in i databasen.
Som ett resultat visade det sig att vattnet var blött och detta är ingen avslöjande. Men nu har jag koden att leka med och kanske kommer till några mer intressanta slutsatser.