Magento 2: استيراد المنتجات مباشرة إلى قاعدة البيانات

في مقال سابق ، وصفت عملية استيراد المنتجات إلى Magento 2 بالطريقة المعتادة - من خلال النماذج والمستودعات. تتميز الطريقة المعتادة بسرعة منخفضة للغاية لمعالجة البيانات. حوالي منتج واحد في الثانية خرج على جهاز الكمبيوتر المحمول. في هذه المتابعة ، أفكر في طريقة بديلة لاستيراد منتج - عن طريق التسجيل المباشر في قاعدة البيانات ، وتجاوز الآليات القياسية لـ Magento 2 (النماذج والمصانع والمستودعات). يمكن تكييف تسلسل خطوات استيراد المنتجات مع أي لغة برمجة يمكن أن تعمل مع MySQL.


إخلاء المسئولية : لدى Magento وظيفة جاهزة لاستيراد البيانات ، وعلى الأرجح ، لديك ما يكفي منها. ومع ذلك ، إذا كنت بحاجة إلى مزيد من التحكم الكامل في عملية الاستيراد ، فلا تقتصر على إعداد ملف CSV لما هو عليه - مرحبًا بك في cat.


الصورة


يمكن الاطلاع على الكود الناتج عن كتابة كلا المادتين في وحدة flancer32 / mage2_ext_demo_import Magento. فيما يلي بعض القيود التي اتبعتها لتبسيط رمز وحدة العرض التوضيحي:


  • يتم إنشاء المنتجات فقط ، وليس تحديثها.
  • مستودع واحد
  • يتم استيراد أسماء الفئات فقط ، بدون هيكلها
  • هياكل البيانات تتوافق مع الإصدار 2.3

JSON لاستيراد منتج واحد:


{ "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" } 

نظرة عامة على خطوات الاستيراد الرئيسية


  • تسجيل المنتج
  • رابط المنتج والموقع
  • سمات المنتج الأساسية (EAV)
  • بيانات المخزون (كمية المنتج في المخزون)
  • الوسائط (صور)
  • رابط إلى فئات الكتالوج

تسجيل المنتج


معلومات المنتج الأساسية موجودة في 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`) ) 

الحد الأدنى من المعلومات اللازمة لإنشاء إدخال في سجل المنتج:


  • attribute_set_id
  • sku

إضافية:


  • type_id - إذا لم type_id ذلك ، فسيتم استخدام "بسيط"

للتسجيل المباشر في قاعدة البيانات ، يمكنني استخدام محول DB من Magento نفسه:


 function create($sku, $typeId, $attrSetId) { /** @var \Magento\Framework\App\ResourceConnection $this->resource */ /** @var \Magento\Framework\DB\Adapter\Pdo\Mysql $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; } 

بعد تسجيل منتج في catalog_product_entity يصبح مرئيًا في لوحة المسؤول ، في شبكة المنتج ( Catalog / Products ).


الصورة


ربط المنتج والموقع


تحدد علاقة المنتج بالموقع أي المتاجر وفي حالات العرض سيكون المنتج متاحًا في المقدمة.


 function linkToWebsite($prodId, $websiteId) { /** @var \Magento\Framework\App\ResourceConnection $this->resource */ /** @var \Magento\Framework\DB\Adapter\Pdo\Mysql $conn */ $conn = $this->resource->getConnection(); $table = $this->resource->getTableName('catalog_product_website'); $bind = [ 'product_id' => $prodId, 'website_id' => $websiteId ]; $conn->insert($table, $bind); } 

الصورة


سمات المنتج الأساسية


المنتج المسجل حديثًا ليس له اسم أو وصف حتى الآن. كل هذا يتم من خلال سمات EAV . فيما يلي قائمة بسمات المنتج الأساسية اللازمة لضمان عرض المنتج بشكل صحيح في المقدمة:


  • name
  • price
  • description
  • short_description
  • status
  • tax_class_id
  • url_key
  • visibility

تتم إضافة سمة منفصلة للمنتج مثل هذا (تم حذف تفاصيل الحصول على المعرف ونوع السمة بواسطة الكود الخاص به):


 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 \Magento\Framework\App\ResourceConnection $this->resource */ /** @var \Magento\Framework\DB\Adapter\Pdo\Mysql $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); } } 

باستخدام رمز السمة ، حدد المعرف ونوع البيانات (الوقت ، decimal ، int ، text ، varchar ) ، ثم في الجدول المقابل نكتب البيانات لواجهة المتجر الإدارية ( store_id = 0 ).


بعد إضافة السمات أعلاه إلى المنتج ، نحصل على هذه الصورة في لوحة الإدارة:


الصورة


بيانات المخزون


بدءًا من الإصدار 2.3 ، تحتوي Magento في وقت واحد على مجموعتين من الجداول التي توفر تخزين معلومات المخزون (كمية المنتج):


  • cataloginventory_* : الهيكل القديم ؛
  • inventory_* : بنية جديدة (MSI - جرد متعدد المصادر) ؛

تحتاج إلى إضافة بيانات المخزون لكلا الهياكل ، لأن البنية الجديدة ليست مستقلة تمامًا عن الهيكل القديم (يبدو أن جدول cataloginventory_stock_status كـ inventory_stock_1 للمستودع default في الهيكل الجديد).


كتالوج


عند نشر Magneto 2.3 ، لدينا مبدئيًا 2 إدخالات في store_website ، والتي تتوافق مع موقعين - الإداري والعميل الرئيسي:


 website_id|code |name |sort_order|default_group_id|is_default| ----------|-----|------------|----------|----------------|----------| 0|admin|Admin | 0| 0| 0| 1|base |Main Website| 0| 1| 1| 

في الجدول cataloginventory_stock ، لدينا إدخال واحد فقط:


 stock_id|website_id|stock_name| --------|----------|----------| 1| 0|Default | 

أي في هيكلنا القديم يوجد "مستودع" واحد فقط (مرتبط) وهو مرتبط بالموقع الإداري. لا تؤدي إضافة sources / stocks جديدة إلى MSI من خلال stocks المسؤول (بنية جديدة) إلى إدخالات جديدة في cataloginventory_stock .


تتم كتابة بيانات المخزون على المنتجات في الهيكل القديم في الجداول في البداية:


  • cataloginventory_stock_item
  • cataloginventory_stock_status

cataloginventory_stock_item


 function createOldItem($prodId, $qty) { $isQtyDecimal = (((int)$qty) != $qty); $isInStock = ($qty > 0); /** @var \Magento\Framework\App\ResourceConnection $this->resource */ /** @var \Magento\Framework\DB\Adapter\Pdo\Mysql $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 \Magento\Framework\App\ResourceConnection $this->resource */ /** @var \Magento\Framework\DB\Adapter\Pdo\Mysql $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' => \Magento\CatalogInventory\Api\Data\StockStatusInterface::STATUS_IN_STOCK, /* default stock is bound to admin website (see `cataloginventory_stock`) */ 'website_id' => 0 ]; $conn->insert($table, $bind); } 

جرد


في البداية ، يحتوي الهيكل الجديد لتخزين بيانات المخزون على 1 " مصدر " ( inventory_source ):


 source_code|name |enabled|description |latitude|longitude|country_id|...| -----------|--------------|-------|--------------|--------|---------|----------|...| default |Default Source| 1|Default Source|0.000000| 0.000000|US |...| 

و " مستودع " واحد ( inventory_stock ):


 stock_id|name | --------|-------------| 1|Default Stock| 

" المصدر " هو مخزن فعلي للمنتجات (يحتوي السجل على إحداثيات فعلية وعنوان بريدي). " المستودع " هو اتحاد منطقي للعديد من "المصادر" ( inventory_source_stock_link )


 link_id|stock_id|source_code|priority| -------|--------|-----------|--------| 1| 1|default | 1| 

في المستوى الذي يوجد به رابط لقناة المبيعات ( inventory_stock_sales_channel )


 type |code|stock_id| -------|----|--------| website|base| 1| 

بناءً على بنية البيانات ، يتم افتراض أنواع مختلفة من قنوات البيع ، ولكن افتراضيًا يتم استخدام اتصال " المخزون " - " موقع الويب " (يتم توفير الرابط إلى موقع الويب بواسطة base رمز موقع الويب).


يمكن ربط " مستودع " واحد بعدة " مصادر " ، ويمكن ربط " مصدر " واحد بعدة " مستودعات " (علاقة كثير إلى كثير). الاستثناءات هي default'ovye " المصدر " و " المستودع ". لا ترتبط بالكيانات الأخرى (التقييد على مستوى الكود - الخطأ " يتعذر حفظ الرابط المتعلق بالمصادر الافتراضية أو الأسهم الافتراضية "). يمكنك قراءة المزيد حول بنية MSI في Magento 2 في مقالة " نظام إدارة المستودعات باستخدام CQRS ومصادر الأحداث. التصميم ".


سأستخدم التكوين الافتراضي وأضيف جميع معلومات المخزون إلى المصدر default ، والذي يتم استخدامه في قناة المبيعات المرتبطة بموقع الويب base (يتوافق مع جزء العميل من المتجر - راجع store_website ):


 function createNewItem($sku, $qty) { /** @var \Magento\Framework\App\ResourceConnection $this->resource */ /** @var \Magento\Framework\DB\Adapter\Pdo\Mysql $conn */ $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); } 

بعد إضافة بيانات المخزون إلى المنتج في لوحة الإدارة ، نحصل على هذه الصورة:


الصورة


وسائل الإعلام


عند إضافة الصور يدويًا إلى المنتج من خلال لوحة الإدارة ، يتم تسجيل المعلومات ذات الصلة في الجداول التالية:


  • catalog_product_entity_media_gallery : سجل الوسائط (الصور وملفات الفيديو) ؛
  • catalog_product_entity_media_gallery_value : ربط الوسائط بالمنتجات وواجهات المتاجر (الترجمة) ؛
  • catalog_product_entity_media_gallery_value_to_entity : ربط الوسائط فقط مع المنتجات (من المفترض أن يكون محتوى الوسائط الافتراضي للمنتج) ؛
  • catalog_product_entity_varchar : الأدوار التي تستخدم الصورة يتم حفظها هنا ؛

ويتم حفظ الصور نفسها في الدليل ./pub/media/catalog/product/x/y/ ، حيث تمثل x و y الأحرف الأولى والثانية من اسم ملف الصورة. على سبيل المثال ، يجب حفظ ملف ./pub/media/catalog/product/i/m/image.png حتى يتمكن النظام الأساسي من استخدامه كصورة عند وصف المنتجات من الكتالوج.



نحن نسجل ملف الوسائط الموجود في ./pub/media/catalog/product/ (لا تعتبر عملية وضع الملف في هذه المقالة):


 function createMediaGallery($imgPathPrefixed) { $attrId = /* get attribute ID by attribute code 'media_gallery' */ /** @var \Magento\Framework\App\ResourceConnection $this->resource */ /** @var \Magento\Framework\DB\Adapter\Pdo\Mysql $conn */ $conn = $this->resource->getConnection(); $table = $this->resource->getTableName('catalog_product_entity_media_gallery'); $bind = [ 'attribute_id' => $attrId, 'value' => $imgPathPrefixed, /* 'image' or 'video' */ 'media_type' => 'image', 'disabled' => false ]; $conn->insert($table, $bind); $result = $conn->lastInsertId($table); return $result; } 

عند التسجيل ، يتم تعيين ملف وسائط جديد معرف.



نربط ملف الوسائط المسجلة بالمنتج المقابل للعرض الافتراضي:


 function createGalleryValue($mediaId, $prodId) { /** @var \Magento\Framework\App\ResourceConnection $this->resource */ /** @var \Magento\Framework\DB\Adapter\Pdo\Mysql $conn */ $conn = $this->resource->getConnection(); $table = $this->resource->getTableName('catalog_product_entity_media_gallery_value'); $bind = [ 'value_id' => $mediaId, /* use admin store view by default */ 'store_id' => 0, 'entity_id' => $prodId, 'label' => null, /* we have one only image */ 'position' => 1, 'disabled' => false ]; $conn->insert($table, $bind); } 


نحن نربط ملف الوسائط المسجل بالمنتج المقابل دون الرجوع إلى أي واجهة. ليس من الواضح أين يتم استخدام هذه البيانات بالضبط ولماذا يستحيل الوصول إلى بيانات الجدول السابق ، ولكن هذا الجدول موجود ويتم كتابة البيانات عند إضافة صورة إلى المنتج. لذلك ، مثل هذا.


 function createGalleryValueToEntity($mediaId, $prodId) { /** @var \Magento\Framework\App\ResourceConnection $this->resource */ /** @var \Magento\Framework\DB\Adapter\Pdo\Mysql $conn */ $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


يمكن استخدام ملف الوسائط بأدوار مختلفة (يشار إلى رمز السمة المقابلة بين قوسين):


  • قاعدة ( image )
  • صورة صغيرة (صورة صغيرة)
  • صورة مصغرة (صورة thumbnail )
  • حامل الصورة ( swatch_image )

يحدث ربط الأدوار بملف وسائط فقط في catalog_product_entity_varchar . يشبه رمز الربط الكود الموجود في قسم " سمات المنتج الأساسية ".


بعد إضافة الصورة إلى المنتج في لوحة المسؤول ، اتضح كما يلي:


الصورة


الفئات


الجداول الرئيسية التي تحتوي على بيانات حسب الفئة:


  • catalog_category_entity : سجل الفئات ؛
  • catalog_category_product : رابطة المنتجات والفئات ؛
  • catalog_category_entity_* : قيم سمات EAV ؛

في البداية ، في تطبيق Magento فارغ ، يحتوي سجل الفئات على فئتين (قمت باختصار أسماء الأعمدة: 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| 

الفئة ذات المعرف = 1 هي جذر دليل Magento بأكمله ولا تتوفر في لوحة الإدارة أو في المقدمة. الفئة ذات المعرف = 2 ( الفئة الافتراضية ) هي فئة الجذر للمتجر الرئيسي للموقع الرئيسي ( متجر الموقع الرئيسي ) الذي تم إنشاؤه عند نشر التطبيق (انظر المسؤول / المتاجر / جميع المتاجر ). علاوة على ذلك ، فإن فئة الجذر الخاصة بالمخزن في المقدمة غير متاحة أيضًا ، فقط فئاتها الفرعية.


نظرًا لأن موضوع هذه المقالة لا يزال يستورد بيانات المنتج ، فلن أستخدم التسجيل المباشر في قاعدة البيانات عند إنشاء الفئات ، لكنني سأستخدم الفئات التي توفرها Magento نفسها (النماذج والمستودعات). يستخدم التسجيل المباشر في قاعدة البيانات فقط لربط المنتج الذي تم استيراده بالفئة (يتم تعيين الفئة حسب اسمه ، ويتم استخراج معرف الفئة عند المطابقة):


 function create($prodId, $catId) { /** @var \Magento\Framework\App\ResourceConnection $this->resource */ /** @var \Magento\Framework\DB\Adapter\Pdo\Mysql $conn */ $conn = $this->resource->getConnection(); $table = $this->resource->getTableName('catalog_category_product'); $bind = [ 'category_id' => $catId, 'product_id' => $prodId, ]; $conn->insert($table, $bind); } 

بعد إضافة رابط المنتج إلى الفئتين "الفئة 1" و "الفئة 2" ، تبدو تفاصيل المنتج في لوحة المسؤول مثل هذا:


الصورة


إجراءات إضافية


بعد اكتمال عملية استيراد البيانات ، يلزمك تنفيذ الخطوات الإضافية التالية:


  • فهرسة البيانات: مكالمة في وحدة التحكم ./bin/magento indexer:reindex ؛
  • تجديد عنوان URL للمنتجات / الفئات: يمكنك استخدام الإضافة " elgentos / regenerate-catalog-urls "

المنتجات في لوحة المسؤول بعد الانتهاء من الخطوات الإضافية:


الصورة


وفي المقدمة:


الصورة


ملخص


يتم استيراد نفس مجموعة المنتجات (10 قطع) كما في المقالة السابقة بترتيب من حجمها على الأقل أسرع (ثانية واحدة مقابل 10). للحصول على تقدير أكثر دقة للسرعة ، تحتاج إلى عدد أكبر من المنتجات - عدة مئات ، ويفضل أن يكون الآلاف. ومع ذلك ، حتى مع وجود مثل هذه الكمية الصغيرة من بيانات المدخلات ، يمكن أن نستنتج أن استخدام الأدوات التي توفرها Magento (النماذج والمستودعات) بشكل كبير (التأكيد - بشكل كبير !) تسريع تطوير الوظيفة المطلوبة ، ولكن بشكل كبير (التأكيد - بشكل كبير !) تقليل سرعة الحصول على البيانات في قاعدة البيانات.


نتيجة لذلك ، تبين أن الماء رطب وهذا ليس الوحي. ومع ذلك ، لدي الآن رمز للعب عليه وربما استخلص استنتاجات أكثر إثارة للاهتمام.

Source: https://habr.com/ru/post/ar440262/


All Articles