Magento 2: importeer producten rechtstreeks in de database
В vorige artikel Ik beschreef het proces van het importeren van producten in Magento 2 op de gebruikelijke manier - via modellen en repositories. De gebruikelijke methode heeft een zeer lage gegevensverwerkingssnelheid. Mijn laptop produceerde ongeveer één product per seconde. In dit vervolg overweeg ik een alternatieve manier om een product te importeren - door directe toegang tot de database, waarbij de standaard Magento 2-mechanismen (modellen, fabrieken, repositories) worden omzeild. De volgorde van stappen om producten te importeren kan worden aangepast aan elke programmeertaal die met MySQL kan werken.
Disclaimer: Magento heeft kant-en-klare functionaliteit voor gegevens importeren en hoogstwaarschijnlijk zal het genoeg voor je zijn. Als u echter meer volledige controle over het importproces nodig heeft, en niet beperkt bent tot het voorbereiden van een CSV-bestand voor wat u heeft, dan bent u van harte welkom bij cat.
De code die voortkomt uit het schrijven van beide artikelen kunt u bekijken in de Magento module"lancer32/mage2_ext_demo_import". Hier zijn enkele beperkingen die ik heb gevolgd om de demomodulecode te vereenvoudigen:
Producten worden alleen gemaakt, niet bijgewerkt.
Eén magazijn
Alleen categorienamen worden geïmporteerd, zonder hun structuur
Datastructuren voldoen aan versie 2.3
JSON voor het importeren van één product:
{
"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"
}
Overzicht van de belangrijkste fasen van import
registratie van het product zelf
verbinding tussen product en website
basisproductkenmerken (EAV)
voorraadgegevens (hoeveelheid product op voorraad)
media (foto's)
verbinding met cataloguscategorieën
Product registratie
Basisproductinformatie vindt u in 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`)
)
De minimale informatie die vereist is om een vermelding in het productregister te maken, is:
attribute_set_id
sku
aanvullend:
type_id — als we het niet specificeren, wordt 'eenvoudig' gebruikt
Om rechtstreeks naar de database te schrijven gebruik ik de DB-adapter van Magento zelf:
Het nieuw geregistreerde product heeft nog geen naam of beschrijving. Dit alles gebeurt via EAV-attributen. Hier is een lijst met basisproductkenmerken die nodig zijn om ervoor te zorgen dat het product correct op de voorkant wordt weergegeven:
name
price
description
short_description
status
tax_class_id
url_key
visibility
Aan een product als dit wordt een afzonderlijk attribuut toegevoegd (de details voor het verkrijgen van de identificatie en het type van het attribuut uit de code zijn weggelaten):
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);
}
}
Met behulp van de attribuutcode bepalen we de ID en het gegevenstype (datetime, decimal, int, text, varchar), schrijf vervolgens de gegevens voor het administratieve venster in de juiste tabel (store_id = 0).
Nadat u de bovenstaande kenmerken aan het product heeft toegevoegd, krijgt u deze afbeelding in het beheerderspaneel:
Voorraadgegevens
Vanaf versie 2.3 in Magento zijn er twee parallelle sets tabellen die de opslag van voorraadinformatie (producthoeveelheid) mogelijk maken:
cataloginventory_*: oude structuur;
inventory_*: nieuwe structuur (MSI - Multi Source Inventory);
U moet inventarisgegevens aan beide structuren toevoegen, omdat de nieuwe structuur is nog niet volledig onafhankelijk van de oude (het is zeer waarschijnlijk dat default magazijn in de nieuwe structuur is een tafel betrokken cataloginventory_stock_status als inventory_stock_1).
catalogusinventaris_
Bij het inzetten van Magneto 2.3 hebben we in eerste instantie 2 vermeldingen in store_website, wat overeenkomt met twee sites: administratief en hoofdclient:
Dat wil zeggen, in onze oude structuur is er maar één ‘magazijn’ (stock) en is gekoppeld aan de administratieve website. Nieuwe toevoegen via het beheerderspaneel sources/stocks in MSI (nieuwe structuur) resulteert niet in nieuwe vermeldingen in cataloginventory_stock.
Voorraadgegevens over producten in de oude structuur worden in eerste instantie vastgelegd in tabellen:
cataloginventory_stock_item
cataloginventory_stock_status
catalogusinventaris_voorraad_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);
}
catalogusinventaris_voorraad_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);
}
inventaris_
Aanvankelijk bevat de nieuwe structuur voor het opslaan van inventarisgegevens 1 "bron"(inventory_source):
«Bron» vertegenwoordigt de fysieke opslag voor producten (het record bevat fysieke coördinaten en postadres). "Magazijn"is een logische vereniging van verschillende" bronnen "(inventory_source_stock_link)
op het niveau waarop de aansluiting op het verkoopkanaal plaatsvindt (inventory_stock_sales_channel)
type |code|stock_id|
-------|----|--------|
website|base| 1|
Afgaande op de datastructuur wordt uitgegaan van verschillende soorten verkoopkanalen, maar standaard wordt alleen de verbinding “voorraad"-"van de"(de link naar de website volgt de websitecode - base).
Een "magazijn"kan aan meerdere gekoppeld worden"bronnen"en een "bron" - aan verschillende "magazijnen"(veel-op-veel-relatie). De uitzonderingen zijn standaard "bron"En"magazijn". Ze zijn niet opnieuw gekoppeld aan andere entiteiten (beperking op codeniveau - de fout “Kan link met betrekking tot standaardbron of standaardvoorraad niet opslaan"). Meer details over de MSI-structuur in Magento 2 vindt u in het artikel “Magazijnbeheersysteem met behulp van CQRS en Event Sourcing. Ontwerp".
Ik gebruik de standaardconfiguratie en voeg alle inventarisinformatie toe aan de bron default, die betrokken is bij het verkoopkanaal dat is gekoppeld aan de website met de code base (komt overeen met de voorkant van de winkel - zie store_website):
Nadat u voorraadgegevens aan het product heeft toegevoegd in het beheerdersdashboard, krijgt u deze afbeelding:
media
Wanneer u via het admin-paneel “handmatig” een afbeelding aan een product toevoegt, wordt de relevante informatie in de volgende tabellen opgeschreven:
catalog_product_entity_media_gallery: mediaregister (afbeeldingen en videobestanden);
catalog_product_entity_media_gallery_value: media koppelen aan producten en showcases (lokalisatie);
catalog_product_entity_media_gallery_value_to_entity: media alleen aan producten koppelen (vermoedelijk standaardmedia-inhoud voor het product);
catalog_product_entity_varchar: De rollen waarin de afbeelding wordt gebruikt, worden hier opgeslagen;
en de afbeeldingen zelf worden in de map opgeslagen ./pub/media/catalog/product/x/y/Waar x и y — de eerste en tweede letter van de naam van het beeldbestand. Bestand bijvoorbeeld image.png moet worden opgeslagen als ./pub/media/catalog/product/i/m/image.png, zodat het platform het als afbeelding kan gebruiken bij het beschrijven van producten uit de catalogus.
catalogus_product_entiteit_media_galerij
Register geplaatst in ./pub/media/catalog/product/ mediabestand (het proces van het plaatsen van het bestand zelf wordt in dit artikel niet besproken):
Wij koppelen het geregistreerde mediabestand aan het overeenkomstige product, zonder dat wij aan een etalage gebonden zijn. Het is niet duidelijk waar deze gegevens precies worden gebruikt en waarom het onmogelijk is om toegang te krijgen tot de gegevens uit de vorige tabel, maar deze tabel bestaat en de gegevens worden ernaartoe geschreven wanneer een afbeelding aan het product wordt toegevoegd. Dus dat is het.
Een mediabestand kan met verschillende rollen worden gebruikt (de bijbehorende attribuutcode wordt tussen haakjes aangegeven):
Basis (image)
Kleine afbeelding (small_image)
Miniatuur (thumbnail)
Voorbeeldafbeelding (swatch_image)
Het koppelen van rollen aan een mediabestand is precies wat er gebeurt in catalog_product_entity_varchar. De bindende code is vergelijkbaar met de code in de "Basisproductkenmerken".
Na het toevoegen van een afbeelding aan het product in het admin-paneel ziet het er als volgt uit:
categorie
Hoofdtabellen met gegevens per categorie:
catalog_category_entity: register van categorieën;
catalog_category_product: verbinding tussen producten en categorieën;
catalog_category_entity_*: EAV-attribuutwaarden;
In eerste instantie bevat het categorieregister in een lege Magento-applicatie 2 categorieën (ik heb de kolomnamen ingekort: crt - created_at, upd - updated_at):
De categorie met id=1 is de root van de gehele Magento-catalogus en is niet beschikbaar in het beheerdersdashboard of op de voorpagina. Categorie met id=2 (standaard Categorie) is de hoofdcategorie voor de hoofdwinkel van de hoofdsite (Hoofdwebsitewinkel) gemaakt wanneer de applicatie wordt geïmplementeerd (zie. Beheerder / Winkels / Alle winkels). Bovendien is de hoofdcategorie van de winkel zelf ook niet aan de voorkant beschikbaar, alleen de subcategorieën.
Omdat het onderwerp van dit artikel nog steeds het importeren van gegevens over producten is, zal ik bij het maken van categorieën geen directe invoer in de database gebruiken, maar de klassen gebruiken die door Magento zelf worden aangeboden (modellen en repositories). Directe invoer in de database wordt alleen gebruikt om het geïmporteerde product aan een categorie te koppelen (de categorie wordt gekoppeld aan de naam en de categorie-ID wordt opgehaald tijdens het matchen):
Na het toevoegen van een productlink aan de categorieën “Categorie 1” en “Categorie 2”, zien de productdetails in het beheerderspaneel er ongeveer zo uit:
Aanvullende acties
Zodra de gegevensimport is voltooid, moet u de volgende aanvullende stappen uitvoeren:
gegevensindexering: roep de console in ./bin/magento indexer:reindex;
Producten in het beheerdersdashboard na het uitvoeren van aanvullende acties:
en aan de voorkant:
Beknopt
Dezelfde set producten (10 stuks) als in het vorige artikel wordt minimaal een orde van grootte sneller geïmporteerd (1 seconde versus 10). Om de snelheid nauwkeuriger te schatten, hebt u een groter aantal producten nodig: enkele honderden, of beter nog duizenden. Maar zelfs met zo’n kleine omvang van de invoergegevens kunnen we concluderen dat het gebruik van de tools van Magento (modellen en repositories) aanzienlijk is (ik benadruk: veel!) de ontwikkeling van de vereiste functionaliteit versnellen, maar tegelijkertijd aanzienlijk (ik benadruk - veel!) verminder de snelheid waarmee gegevens in de database terechtkomen.
Hierdoor bleek het water nat te zijn en dit is geen openbaring. Nu heb ik echter de code om mee te spelen en kom ik misschien tot enkele interessantere conclusies.