Dalam artikel sebelumnya, saya menggambarkan proses mengimpor produk ke Magento 2 dengan cara yang biasa - melalui model dan repositori. Metode yang biasa dicirikan dengan kecepatan pemrosesan data yang sangat rendah. Sekitar satu produk per detik keluar di laptop saya. Dalam kelanjutan ini, saya mempertimbangkan cara alternatif untuk mengimpor produk - dengan merekam langsung ke database, melewati mekanisme standar Magento 2 (model, pabrik, repositori). Urutan langkah-langkah untuk mengimpor produk dapat disesuaikan dengan bahasa pemrograman apa pun yang dapat bekerja dengan MySQL.
Penafian : Magento memiliki fungsi siap pakai untuk mengimpor data dan, kemungkinan besar, Anda sudah cukup memilikinya. Namun, jika Anda memerlukan kontrol lebih lengkap atas proses impor, tidak terbatas pada menyiapkan file CSV seperti apa - selamat datang di cat.

Kode yang dihasilkan dari penulisan kedua artikel dapat dilihat di modul - Magenta flancer32 / mage2_ext_demo_import . Berikut adalah beberapa batasan yang saya ikuti untuk menyederhanakan kode modul demo:
- Produk hanya dibuat, tidak diperbarui.
- Satu gudang
- Hanya nama kategori yang diimpor, tanpa strukturnya
- Struktur data sesuai dengan versi 2.3
JSON untuk mengimpor satu produk:
{ "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" }
Ikhtisar langkah-langkah impor utama
- pendaftaran produk
- produk tautan dan situs web
- atribut produk dasar (EAV)
- data persediaan (jumlah produk dalam persediaan)
- media (gambar)
- tautan ke kategori katalog
Registrasi Produk
Informasi dasar produk ada di 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`) )
Informasi minimum yang diperlukan untuk membuat entri dalam registri produk:
tambahan:
type_id
- jika tidak type_id
, maka 'sederhana' akan digunakan
Untuk merekam langsung ke database, saya menggunakan adaptor DB Magento sendiri:
function create($sku, $typeId, $attrSetId) { $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; }
Setelah mendaftarkan produk di catalog_product_entity
itu menjadi terlihat di panel admin, di kisi produk ( Katalog / Produk ).

Tautkan produk dan situs web
Hubungan produk dengan situs menentukan di mana toko dan di mana etalase produk akan tersedia di bagian depan.
function linkToWebsite($prodId, $websiteId) { $conn = $this->resource->getConnection(); $table = $this->resource->getTableName('catalog_product_website'); $bind = [ 'product_id' => $prodId, 'website_id' => $websiteId ]; $conn->insert($table, $bind); }

Atribut produk dasar
Produk yang baru terdaftar belum memiliki nama atau deskripsi. Semua ini dilakukan melalui atribut EAV . Berikut adalah daftar atribut produk dasar yang diperlukan untuk memastikan bahwa produk ditampilkan dengan benar di depan:
name
price
description
short_description
status
tax_class_id
url_key
visibility
Atribut terpisah untuk produk ditambahkan seperti ini (rincian untuk mendapatkan pengidentifikasi dan tipe atribut dengan kode dihilangkan):
public function create($prodId, $attrCode, $attrValue) { $attrId = $attrType = if ($attrId) { $conn = $this->resource->getConnection(); $tblName = 'catalog_product_entity_' . $attrType; $table = $this->resource->getTableName($tblName); $bind = [ 'attribute_id' => $attrId, 'entity_id' => $prodId, 'store_id' => 0, 'value' => $attrValue ]; $conn->insert($table, $bind); } }
Dengan menggunakan kode atribut, tentukan id dan tipe datanya ( datetime
, decimal
, int
, text
, varchar
), lalu dalam tabel yang sesuai kita menulis data untuk etalase administratif ( store_id = 0
).
Setelah menambahkan atribut di atas ke produk, kami mendapatkan gambar ini di panel admin:

Data inventaris
Mulai dari versi 2.3, Magento secara bersamaan memiliki dua set tabel yang menyediakan penyimpanan informasi inventaris (jumlah produk):
cataloginventory_*
: struktur lama;inventory_*
: struktur baru (MSI - Multi Source Inventory);
Anda perlu menambahkan data inventaris ke kedua struktur, karena struktur baru belum sepenuhnya independen dari yang lama (sepertinya tabel cataloginventory_stock_status
sebagai inventory_stock_1
untuk gudang default
di struktur baru).
kataloginventory_
Ketika menggunakan Magneto 2.3, kami awalnya memiliki 2 entri di store_website
, yang sesuai dengan dua situs - administrasi dan klien utama:
website_id|code |name |sort_order|default_group_id|is_default| ----------|-----|------------|----------|----------------|----------| 0|admin|Admin | 0| 0| 0| 1|base |Main Website| 0| 1| 1|
Dalam tabel cataloginventory_stock
, kami hanya memiliki satu entri:
stock_id|website_id|stock_name| --------|----------|----------| 1| 0|Default |
Artinya, dalam struktur lama kami hanya ada satu "gudang" ( stock
) dan itu terkait dengan situs web administrasi. Menambahkan sources
/ stocks
ke MSI melalui stocks
admin (struktur baru) tidak mengarah ke entri baru di cataloginventory_stock
.
Data inventaris pada produk dalam struktur lama pada awalnya ditulis dalam tabel:
cataloginventory_stock_item
cataloginventory_stock_status
kataloginventory_stock_item
function createOldItem($prodId, $qty) { $isQtyDecimal = (((int)$qty) != $qty); $isInStock = ($qty > 0); $conn = $this->resource->getConnection(); $table = $this->resource->getTableName('cataloginventory_stock_item'); $bind = [ 'product_id' => $prodId, 'stock_id' => 1, 'qty' => $qty, 'is_qty_decimal' => $isQtyDecimal, 'is_in_stock' => $isInStock, 'website_id' => 0 ]; $conn->insert($table, $bind); }
kataloginventory_stock_status
function createOldStatus($prodId, $qty) { $isInStock = ($qty > 0); $conn = $this->resource->getConnection(); $table = $this->resource->getTableName('cataloginventory_stock_status'); $bind = [ 'product_id' => $prodId, 'stock_id' => 1, 'qty' => $qty, 'stock_status' => \Magento\CatalogInventory\Api\Data\StockStatusInterface::STATUS_IN_STOCK, 'website_id' => 0 ]; $conn->insert($table, $bind); }
inventaris_
Awalnya, struktur baru untuk menyimpan data inventaris berisi 1 " sumber " ( inventory_source
):
source_code|name |enabled|description |latitude|longitude|country_id|...| -----------|--------------|-------|--------------|--------|---------|----------|...| default |Default Source| 1|Default Source|0.000000| 0.000000|US |...|
dan satu " gudang " ( inventory_stock
):
stock_id|name | --------|-------------| 1|Default Stock|
" Sumber " adalah toko fisik untuk produk (catatan berisi koordinat fisik dan alamat surat). " Gudang " adalah gabungan logis dari beberapa "sumber" ( inventory_source_stock_link
)
link_id|stock_id|source_code|priority| -------|--------|-----------|--------| 1| 1|default | 1|
di tingkat yang ada tautan ke saluran penjualan ( inventory_stock_sales_channel
)
type |code|stock_id| -------|----|--------| website|base| 1|
Dilihat oleh struktur data, berbagai jenis saluran penjualan diasumsikan, tetapi secara default hanya koneksi " stok " - " situs web " yang digunakan (tautan ke situs web diberikan oleh base
kode situs web).
Satu " gudang " dapat diikat ke beberapa " sumber ", dan satu " sumber " dapat dihubungkan ke beberapa " gudang " (hubungan banyak-ke-banyak). Pengecualian adalah " sumber " dan " gudang " default'ovye. Mereka tidak mengikat ke entitas lain (pembatasan pada tingkat kode - kesalahan " Tidak dapat menyimpan tautan yang terkait dengan Sumber Default atau Stok Default " macet). Anda dapat membaca lebih lanjut tentang struktur MSI di Magento 2 di artikel " Sistem Manajemen Gudang Menggunakan CQRS dan Event Sourcing. Desain ".
Saya akan menggunakan konfigurasi default dan menambahkan semua informasi inventaris ke sumber default
, yang digunakan dalam saluran penjualan yang terkait dengan situs web dengan kode base
(sesuai dengan bagian klien dari toko - lihat store_website
):
function createNewItem($sku, $qty) { $conn = $this->resource->getConnection(); $table = $this->resource->getTableName('inventory_source_item'); $bind = [ 'source_code' => 'default', 'sku' => $sku, 'quantity' => $qty, 'status' => \Magento\InventoryApi\Api\Data\SourceItemInterface::STATUS_IN_STOCK ]; $conn->insert($table, $bind); }
Setelah menambahkan data inventaris ke produk di panel admin, kami mendapatkan gambar ini:

Ketika "secara manual" menambahkan gambar ke produk melalui panel admin, informasi yang relevan direkam dalam tabel berikut:
catalog_product_entity_media_gallery
: registry media (gambar dan file video);catalog_product_entity_media_gallery_value
: menautkan media dengan produk dan etalase (lokalisasi);catalog_product_entity_media_gallery_value_to_entity
: hanya mengikat media ke produk (mungkin konten media default untuk produk);catalog_product_entity_varchar
: peran yang menggunakan gambar disimpan di sini;
dan gambar itu sendiri disimpan dalam direktori ./pub/media/catalog/product/x/y/
, di mana x
dan y
adalah huruf pertama dan kedua dari nama file gambar. Misalnya, file image.png
harus disimpan sebagai ./pub/media/catalog/product/i/m/image.png
sehingga platform dapat menggunakannya sebagai gambar ketika menggambarkan produk dari katalog.
Kami mendaftarkan file media yang terletak di ./pub/media/catalog/product/
(proses menempatkan file dalam artikel ini tidak dipertimbangkan):
function createMediaGallery($imgPathPrefixed) { $attrId = $conn = $this->resource->getConnection(); $table = $this->resource->getTableName('catalog_product_entity_media_gallery'); $bind = [ 'attribute_id' => $attrId, 'value' => $imgPathPrefixed, 'media_type' => 'image', 'disabled' => false ]; $conn->insert($table, $bind); $result = $conn->lastInsertId($table); return $result; }
Saat mendaftar, file media baru diberikan pengenal.
Kami menautkan file media yang terdaftar dengan produk yang sesuai untuk showcase default:
function createGalleryValue($mediaId, $prodId) { $conn = $this->resource->getConnection(); $table = $this->resource->getTableName('catalog_product_entity_media_gallery_value'); $bind = [ 'value_id' => $mediaId, 'store_id' => 0, 'entity_id' => $prodId, 'label' => null, 'position' => 1, 'disabled' => false ]; $conn->insert($table, $bind); }
Kami mengaitkan file media yang terdaftar dengan produk yang sesuai tanpa merujuk ke etalase apa pun. Tidak jelas di mana tepatnya data ini digunakan dan mengapa tidak mungkin untuk mengakses data dari tabel sebelumnya, tetapi tabel ini ada dan data ditulis untuk itu ketika menambahkan gambar ke produk. Karenanya, seperti ini.
function createGalleryValueToEntity($mediaId, $prodId) { $conn = $this->resource->getConnection(); $table = $this->resource->getTableName('catalog_product_entity_media_gallery_value_to_entity'); $bind = [ 'value_id' => $mediaId, 'entity_id' => $prodId ]; $conn->insert($table, $bind); }
catalog_product_entity_varchar
File media dapat digunakan dengan peran yang berbeda (kode atribut yang sesuai ditunjukkan dalam tanda kurung):
- Base (
image
) - Gambar Kecil (
small_image
) - Gambar kecil (
thumbnail
) - Gambar Swatch (
swatch_image
)
Mengikat peran ke file media hanya terjadi di catalog_product_entity_varchar
. Kode pengikatan mirip dengan kode di bagian " Atribut Produk Dasar ".
Setelah menambahkan gambar ke produk di panel admin ternyata seperti ini:

Kategori
Tabel utama yang berisi data berdasarkan kategori:
catalog_category_entity
: daftar kategori;catalog_category_product
: asosiasi produk dan kategori;catalog_category_entity_*
: nilai atribut EAV;
Awalnya, dalam aplikasi Magento kosong, registri kategori berisi 2 kategori (Saya menyingkat nama kolom: crt
- created_at
, upd
- 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 dengan id = 1 adalah root dari seluruh direktori Magento dan tidak tersedia di panel admin atau di bagian depan. Kategori dengan id = 2 ( Kategori Default ) adalah kategori root untuk toko utama situs web utama ( Toko Situs Web Utama ) yang dibuat ketika aplikasi dikerahkan (lihat Admin / Toko / Semua Toko ). Selain itu, kategori paling dasar dari toko di bagian depan juga tidak tersedia, hanya subkategori.
Karena topik artikel ini masih mengimpor data produk, saya tidak akan menggunakan rekaman langsung dalam database saat membuat kategori, tapi saya akan menggunakan kelas yang disediakan oleh Magento sendiri (model dan repositori). Rekaman langsung ke database hanya digunakan untuk menghubungkan produk yang diimpor dengan kategori (kategori dipetakan berdasarkan namanya, id kategori diekstraksi saat pencocokan):
function create($prodId, $catId) { $conn = $this->resource->getConnection(); $table = $this->resource->getTableName('catalog_category_product'); $bind = [ 'category_id' => $catId, 'product_id' => $prodId, ]; $conn->insert($table, $bind); }
Setelah menambahkan tautan produk ke kategori "Kategori 1" dan "Kategori 2", detail produk di panel admin terlihat seperti ini:

Tindakan tambahan
Setelah impor data selesai, Anda perlu melakukan langkah-langkah tambahan berikut:
- pengindeksan data: panggilan di konsol
./bin/magento indexer:reindex
; - Regenerasi URL untuk produk / kategori: Anda dapat menggunakan ekstensi " elgentos / regenerate-catalog-url "
Produk di panel admin setelah menyelesaikan langkah-langkah tambahan:

dan di depan:

Ringkasan
Rangkaian produk yang sama (10 buah) seperti pada artikel sebelumnya diimpor setidaknya urutan besarnya lebih cepat (1 detik versus 10). Untuk perkiraan kecepatan yang lebih akurat, Anda membutuhkan lebih banyak produk - beberapa ratus, dan lebih disukai ribuan. Namun demikian, bahkan dengan sejumlah kecil data input, dapat disimpulkan bahwa penggunaan alat yang disediakan oleh Magento (model dan repositori) secara signifikan (menekankan - signifikan !) Mempercepat pengembangan fungsionalitas yang diperlukan, tetapi secara signifikan (menekankan - signifikan !) Mengurangi kecepatan data masuk ke database.
Alhasil, airnya menjadi basah dan ini bukan wahyu. Namun, saya sekarang memiliki kode untuk bermain dan mungkin menarik kesimpulan yang lebih menarik.