I Jag har beskrivit processen för produktimport i Magento 2 pĂ„ det vanliga sĂ€ttet â via modeller och repositarier. Den vanliga metoden har en ganska lĂ„g databehandlingshastighet. PĂ„ min bĂ€rbara dator var det ungefĂ€r en produkt per sekund. I den hĂ€r fortsĂ€ttningen kommer jag att titta pĂ„ ett alternativt sĂ€tt att importera produkter â genom direktinskrivning i databasen, helt utan standardmekanismerna i Magento 2 (modeller, fabriker, repositarier). Följden av steg som möjliggör produktimport kan anpassas till vilket programmeringssprĂ„k som helst som kan arbeta med MySQL.
Ansvarsfriskrivning: I Magento finns det en fĂ€rdig funktion för och du kommer förmodligen att ha tillrĂ€ckligt med det. Men om du behöver mer full kontroll över importprocessen, utan begrĂ€nsningar kopplade till förbereda en CSV-fil för vad som finns â vĂ€lkommen ner.

Koden som skapades som resultat av att skriva de tvÄ artiklarna kan ses i Magento-modulen "". HÀr Àr nÄgra begrÀnsningar som jag följde för att förenkla koden för demomodulen:
- Produkter skapas endast, inte uppdateras.
- En lagerplats
- Endast kategori namn importeras, utan deras struktur
- Datastrukturerna motsvarar version 2.3
JSON för import av enskild produkt:
{
"sku": "MVA20D-UBV-3",
"name": "TÀtningspropp för försegling VA47-29 IEK",
"desc": "Ger tillgÄng till enheter ...",
"desc_short": "TÀtningsproppen för försegling VA47-29 IEK Àr avsedd för ...",
"price": 5.00,
"qty": 25,
"categories": ["Kategori 1", "Kategori 2"],
"image_path": "mva20d_ubv_3.png"
}Ăversikt över huvudsakliga steg vid import
- registrering av sjÀlva produkten
- koppling mellan produkten och webbplatsen
- grundlÀggande produktattribut (EAV)
- lagerdata (antal produkter i lager)
- media (bilder)
- kopplingar till katalogkategorier
Registrering av produkt
GrundlÀggande information om produkten finns i catalog_product_entity:
SKAPA TABELL `catalog_product_entity` (
`entity_id` int(10) unsigned NOT NULL AUTO_INCREMENT KOMMENTAR 'Entity Id',
`attribute_set_id` smallint(5) unsigned NOT NULL STANDARD '0' KOMMENTAR 'AttributuppsÀttning ID',
`type_id` varchar(32) NOT NULL STANDARD 'simple' KOMMENTAR 'Typ ID',
`sku` varchar(64) STANDARD NULL KOMMENTAR 'SKU',
`has_options` smallint(6) NOT NULL STANDARD '0' KOMMENTAR 'Har alternativ',
`required_options` smallint(5) unsigned NOT NULL STANDARD '0' KOMMENTAR 'Obligatoriska alternativ',
`created_at` timestamp NOT NULL STANDARD CURRENT_TIMESTAMP KOMMENTAR 'Skapelsestid',
`updated_at` timestamp NOT NULL STANDARD CURRENT_TIMESTAMP VID UPPDATERING CURRENT_TIMESTAMP KOMMENTAR 'Uppdateringstid',
PRIMARY KEY (`entity_id`),
KEY `CATALOG_PRODUCT_ENTITY_ATTRIBUTE_SET_ID` (`attribute_set_id`),
KEY `CATALOG_PRODUCT_ENTITY_SKU` (`sku`)
)Minimalt nödvÀndig information för att skapa en post i produktregistret:
attributset_idsku
extra:
typ_idâ om vi inte anger det, kommer 'simple' att anvĂ€ndas
För direktinspelning till databasen anvÀnder jag Magento:s DB-adapter:
function create($sku, $typeId, $attrSetId)
{
\/** @var MagentoFrameworkAppResourceConnection $this->resource *\/
\/** @var MagentoFrameworkDBAdapterPdoMysql $conn *\/
$conn = $this->resource->getConnection();
$table = $this->resource->getTableName('catalog_product_entity');
$bind = [
'sku' => $sku,
'type_id' => $typeId,
'attribute_set_id' => $attrSetId
];
$conn->insert($table, $bind);
$result = $conn->lastInsertId($table);
return $result;
}Efter registrering av produkten i catalog_product_entity blir den synlig i adminpanelen, i produktgridden (Katalog / Produkter).

Produktens koppling till webbplatsen
Produktens koppling till webbplatsen bestÀmmer i vilka butiker och pÄ vilka fönster produkten kommer att vara tillgÀnglig pÄ fronten.
function linkToWebsite($prodId, $websiteId)
{
\/** @var MagentoFrameworkAppResourceConnection $this->resource *\/
\/** @var MagentoFrameworkDBAdapterPdoMysql $conn *\/
$conn = $this->resource->getConnection();
$table = $this->resource->getTableName('catalog_product_website');
$bind = [
'product_id' => $prodId,
'website_id' => $websiteId
];
$conn->insert($table, $bind);
}
GrundlÀggande produktattribut
En nyligen registrerad produkt har Ànnu inget namn eller beskrivning. Detta görs via . HÀr Àr en lista över grundlÀggande produktattribut som behövs för att produkten ska visas korrekt pÄ fronten:
namepricedescriptionkort_beskrivningstatusskatteklass_idurl_nyckelsynlighet
Ett separat attribut lÀggs till produkten sÄ hÀr (detaljer om att hÀmta ID och typ av attribut via dess kod Àr utelÀmnade):
public function create($prodId, $attrCode, $attrValue)
{
$attrId = \/** hÀmta attribut-ID med attributkod *\/
$attrType = \/** hÀmta attributtyp [datetime|decimal|int|text|varchar] med attributkod *\/
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,
\/** sÀtt alla attribut till standardbutiksvisning med id=0 (admin) *\/
'store_id' => 0,
'value' => $attrValue
];
$conn->insert($table, $bind);
}
}Genom attributkoden bestÀmmer vi dess id och datatyp (datetime, decimal, int, text, varchar), sedan skriver vi data till motsvarande tabell för den administrativa butiken (store_id = 0).
Efter att ha lagt till de ovan nÀmnda attributen till produkten ser vi en sÄdan bild i adminpanelen:

Lagerdata
FrÄn och med version 2.3 i Magento finns tvÄ uppsÀttningar tabeller parallellt som lagrar lagerinformation (produkternas mÀngd):
kataloglager_*: gammal struktur;lager_*: ny struktur (MSI â Multi Source Inventory);
Inventardata mÄste lÀggas till i bÄda strukturerna eftersom den nya strukturen Ànnu inte Àr helt oberoende av den gamla (det verkar mycket troligt att för default lagret i den nya strukturen anvÀnds tabellen cataloginventory_stock_status som inventory_stock_1).
cataloginventory_
Vid utplacering av Magneto 2.3 har vi initialt 2 poster i store_website, vilket motsvarar tvĂ„ webbplatser â en administrativ och en huvudkundsida:
website_id|code |name |sort_order|default_group_id|is_default|
----------|-----|------------|----------|----------------|----------|
0|admin|Admin | 0| 0| 0|
1|base |Huvudwebbsite| 0| 1| 1|I tabellen cataloginventory_stock har vi bara en post:
stock_id|website_id|stock_name|
--------|----------|----------|
1| 0|Standard |Det vill sÀga, vi har i den gamla strukturen endast ett "lager" (stock) och det Àr kopplat till den administrativa webbplatsen. TillÀgg via adminpanelen av nya utgÄngar/stocks i MSI (den nya strukturen) resulterar inte i nya poster i cataloginventory_stock.
Inventardata om produkter i den gamla strukturen skrivs initialt in i tabellerna:
cataloginventory_stock_itemcataloginventory_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,
/* vi anvÀnder bara en stock i 'cataloginventory' strukturen som standard */
'stock_id' => 1,
'qty' => $qty,
'is_qty_decimal' => $isQtyDecimal,
'is_in_stock' => $isInStock,
/* standardlagret Àr kopplat till admin webbplats (se `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,
/* vi anvÀnder bara en stock i 'cataloginventory' strukturen som standard */
'stock_id' => 1,
'qty' => $qty,
'stock_status' => MagentoCatalogInventoryApiDataStockStatusInterface::STATUS_IN_STOCK,
/* standardlagret Àr kopplat till admin webbplats (se `cataloginventory_stock`) */
'website_id' => 0
];
$conn->insert($table, $bind);
}inventory_
Den nya strukturen för lagring av inventardata innehÄller initialt 1 "ClickHouse-Ninja/Proton» (inventory_source):
source_code|name |enabled|description |latitude|longitude|country_id|...|
-----------|--------------|-------|--------------|--------|---------|----------|...|
default |Standard KÀlla| 1|Standard KÀlla|0.000000| 0.000000|SE |...|och en "lager» (inventory_stock):
stock_id|name |
--------|-------------|
1|Standard Lager|«KÀlla» Àr ett fysiskt lager för produkter (posten innehÄller fysiska koordinater och en postadress). «Lager» Àr en logisk sammanslagning av flera «kÀllor» (inventory_source_stock_link)
link_id|stock_id|source_code|priority|
-------|--------|-----------|--------|
1| 1|default | 1|pÄ vilken nivÄ som bindningen till försÀljningskanalen sker (inventory_stock_sales_channel)
type |code|stock_id|
-------|----|--------|
website|base| 1|UtifrĂ„n datans struktur förutses det olika typer av försĂ€ljningskanaler, men som standard anvĂ€nds endast kopplingen «stock«-«website» (lĂ€nken till webbplatsen gĂ„r genom webbplatsens kod â base).
En «lager» kan bindas till flera «kĂ€llor«, och en «ClickHouse-Ninja/Proton» â till flera «lager» (förhĂ„llandet «mĂ„nga till mĂ„nga»). Undantag utgör de default-kĂ€llor «ClickHouse-Ninja/Proton" och "lager«. De ombindas inte till andra enheter (en begrĂ€nsning pĂ„ kodnivĂ„ â ett fel uppstĂ„r: «Kan inte spara lĂ€nk kopplad till standardkĂ€lla eller standardlager «). Mer information om MSI-strukturen i Magento 2 kan lĂ€sas i artikeln «Lagarsystem med anvĂ€ndning av CQRS och Event Sourcing. Design«.
, som anvĂ€nds i försĂ€ljningskanalen kopplad till webbplatsen med koden default(motsvarar kunddelen av butiken â se. base function createNewItem($sku, $qty) { \/** @var MagentoFrameworkAppResourceConnection $this->resource *\/ \/** @var MagentoFrameworkDBAdapterPdoMysql $conn *\/ $conn = $this->resource->getConnection(); $table = $this->resource->getTableName('inventory_source_item'); $bind = [ 'source_code' => 'default', 'sku' => $sku, 'quantity' => $qty, 'status' => MagentoInventoryApiApiDataSourceItemInterface::STATUS_IN_STOCK ]; $conn->insert($table, $bind); } store_website):
Efter att ha lagt till lagerdata till produkten i adminpanelen fÄr man en sÄdan bild:Vid «manuell» tillÀggning av bilder till produkten via adminpanelen skrivs den motsvarande informationen i följande tabeller:

Som regel skiljer sig mediastöd för produkten för kunden i butiken (e-handel) frÄn mediastödet för samma produkt för anstÀllda i det interna redovisningssystemet (ERP). I det första fallet Àr det önskvÀrt att visa "produkten frontal", i det andra fallet rÀcker det med att ge en allmÀn översikt över produkten. Trots detta Àr överföringen av Ätminstone den primÀra bilden av produkten ganska vanlig
catalog_product_entity_media_gallery
: medieregister (bilder och videofiler);catalog_product_entity_media_gallery_value: koppling av media till produkter och butiker (lokalisering);catalog_product_entity_media_gallery_value_to_entity: koppling av media endast till produkter (troligen, standard mediainnehÄll för produkten);: hÀr lagras roller dÀr bilden anvÀnds;catalog_product_entity_varcharoch sjÀlva bilderna lagras i katalogen
.\/pub\/media\/catalog\/product\/x\/y\/ â de första och andra bokstĂ€verna av filnamnet pĂ„ bilden. Till exempel, filen, dĂ€r x och y ska sparas som image.png ĐŽĐŸĐ»Đ¶Đ”Đœ бŃŃŃ ŃĐŸŃ
ŃĐ°ĐœŃĐœ ĐșаĐș ./pub/media/catalog/product/i/m/image.png, sĂ„ att plattformen kan anvĂ€nda den som ett bildalternativ vid beskrivning av produkter i katalogen.
: medieregister (bilder och videofiler);
Registrerar den som Àr placerad i .\/pub\/media\/catalog\/product\/ mediafil (sjÀlva processen för att placera filen i denna artikel beaktas inte):
function createMediaGallery($imgPathPrefixed)
{
$attrId = \/* hÀmta attribut-ID genom attributkod 'media_gallery' *\/\n \/** @var MagentoFrameworkAppResourceConnection $this->resource *\/\n \/** @var MagentoFrameworkDBAdapterPdoMysql $conn *\/\n $conn = $this->resource->getConnection();\n $table = $this->resource->getTableName('catalog_product_entity_media_gallery');\n $bind = [\n 'attribute_id' => $attrId,\n 'value' => $imgPathPrefixed,\n \/* 'image' eller 'video' *\/\n 'media_type' => 'image',\n 'disabled' => false\n ];\n $conn->insert($table, $bind);\n $result = $conn->lastInsertId($table);\n return $result;\n}Vid registreringen fÄr den nya mediafilen ett identifieringsnummer.
: koppling av media till produkter och butiker (lokalisering);
Kopplar den registrerade mediafilen med den motsvarande produkten för standardbutiken:
function createGalleryValue($mediaId, $prodId)
{
\/** @var MagentoFrameworkAppResourceConnection $this->resource *\/\n \/** @var MagentoFrameworkDBAdapterPdoMysql $conn *\/\n $conn = $this->resource->getConnection();\n $table = $this->resource->getTableName('catalog_product_entity_media_gallery_value');\n $bind = [\n 'value_id' => $mediaId,\n \/* anvÀnd adminbutiksvy som standard *\/\n 'store_id' => 0,\n 'entity_id' => $prodId,\n 'label' => null,\n \/* vi har bara en bild *\/\n 'position' => 1,\n 'disabled' => false\n ];\n $conn->insert($table, $bind);\n}: koppling av media endast till produkter (troligen, standard mediainnehÄll för produkten);
Kopplar den registrerade mediafilen med den motsvarande produkten utan bindning till nÄgon butik. Det Àr oklart var dessa data anvÀnds och varför man inte kan referera till data frÄn den föregÄende tabellen, men den hÀr tabellen finns och data skrivs in i den nÀr en bild lÀggs till produkten. SÄ hÀr Àr det.
function createGalleryValueToEntity($mediaId, $prodId)
{
\/** @var MagentoFrameworkAppResourceConnection $this->resource *\/\n \/** @var MagentoFrameworkDBAdapterPdoMysql $conn *\/\n $conn = $this->resource->getConnection();\n $table = $this->resource->getTableName('catalog_product_entity_media_gallery_value_to_entity');\n $bind = [\n 'value_id' => $mediaId,\n 'entity_id' => $prodId\n ];\n $conn->insert($table, $bind);\n}catalog_product_entity_varchar
Mediafilen kan anvÀndas med olika roller (koden för motsvarande attribut anges inom parentes):
- Bas (
bild) - Liten bild (
thumbnail) - Thumbnail (
swatch_image) - Swatch-bild (
Av nÄgon anledning kopplas media endast efter att produkten har sparats prelimÀrt och hÀmtats frÄn repot pÄ nytt. Och man mÄste ange attributet)
Rollbindningarna för mediafilen sker just i catalog_product_entity_varchar. Koden för bindningen Àr liknande koden i avsnittet «GrundlÀggande produktattribut«.
Efter att ha lagt till en bild till produkten i adminpanelen ser det ut sÄ hÀr:

Kategorier
De huvudsakliga tabellerna som innehÄller kategoridata:
catalog_category_entity: register över kategorier;catalog_category_product: koppling mellan produkter och kategorier;catalog_category_entity_*: vÀrden för EAV-attribut;
Inledningsvis, i en tom Magento-applikation i kategoriens register finns det 2 kategorier (jag har förkortat kolumntitlarna: crt â created_at, uppdatering â updated_at):
entity_id|attribute_set_id|parent_id|crt|upd|path|position|level|children_count|
---------|----------------|---------|---|---|----|--------|-----|--------------|
1| 3| 0|...|...|1 | 0| 0| 1|
2| 3| 1|...|...|1\/2 | 1| 1| 0|Kategori med id=1 Àr roten till hela Magento-katalogen och Àr inte tillgÀnglig varken i adminpanel eller pÄ fronten. Kategori med id=2 (Standardkategori) Àr rotkategorin för huvudbutiken pÄ huvudwebbplatsen (Main Website Store), som skapas vid distributionen av applikationen (se. Admin / Stores / All Stores). Observera att den rotkategorin för butiken ocksÄ Àr otillgÀnglig pÄ fronten, endast dess underkategorier Àr tillgÀngliga.
Eftersom temat för denna artikel ÀndÄ Àr import av produktdata, kommer jag inte att anvÀnda direkt skrivning till databasen vid skapandet av kategorier, utan jag kommer att anvÀnda klasserna som tillhandahÄlls av Magento (modeller och repository). Direkt skrivning till databasen anvÀnds endast för att koppla den importerade produkten med kategorin (kopplingen av kategorin görs baserat pÄ dess namn, id för kategorin hÀmtas vid kopplingen):
function create($prodId, $catId)
{
\/** @var MagentoFrameworkAppResourceConnection $this->resource *\/
\/** @var MagentoFrameworkDBAdapterPdoMysql $conn *\/
$conn = $this->resource->getConnection();
$table = $this->resource->getTableName('catalog_category_product');
$bind = [
'category_id' => $catId,
'product_id' => $prodId,
];
$conn->insert($table, $bind);
}Efter att ha lagt till kopplingen av produkten med kategorierna "Kategori 1" och "Kategori 2" ser produktens detaljer i adminpanelen ungefÀr ut sÄ hÀr:

Ytterligare ÄtgÀrder
Efter att importen av data har slutförts mÄste följande ytterligare ÄtgÀrder vidtas:
- indexering av data: anrop i terminalen
.\/bin\/magento indexer:reindex; - Ätergenerering av URL:er för produkter\/kategorier: kan anvÀnda tillÀgget "«
Produkter i adminpanelen efter att ytterligare ÄtgÀrder har utförts:

och pÄ fronten:

Sammanfattning
Det samma setet av produkter (10 stycken), som i den föregĂ„ende artikeln, importeras Ă„tminstone en ordning snabbare (1 sekund mot 10). För en mer exakt bedömning av hastigheten behövs fler produkter â flera hundra, helst tusentals. ĂndĂ„, Ă€ven med en sĂ„dan liten storlek pĂ„ indatadatan kan man dra slutsatsen att anvĂ€ndningen av verktygen som tillhandahĂ„lls av Magento (modeller och repository) pĂ„tagligt (jag understryker â pĂ„tagligt!) snabbar utvecklingen av den nödvĂ€ndiga funktionaliteten, men samtidigt (jag betonar â pĂ„tagligt!) sĂ€nker hastigheten för datainmatning i databasen.
Resultatet var att vatten var blött och det Ă€r ingen nyhet. ĂndĂ„ har jag nu koden för att experimentera vidare och kanske göra mer intressanta slutsatser.
KĂ€lla: habr.com
