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

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

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

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

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

  • يتم إنشاء المنتجات فقط، ولا يتم تحديثها.
  • مستودع واحد
  • يتم استيراد أسماء الفئات فقط، بدون بنيتها
  • تتوافق هياكل البيانات مع الإصدار 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 - إذا لم يتم تحديده، فسيتم استخدام "بسيط".

للكتابة المباشرة إلى قاعدة البيانات، أستخدم محول قاعدة البيانات الخاص بـ Magento نفسه:

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;
}

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

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

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

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

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);
}

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

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

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

  • 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 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);
    }
}

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

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

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

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

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

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

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

جرد الكتالوج _

عند نشر Magneto 2.3، لدينا في البداية إدخالان 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   |

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

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

  • cataloginventory_stock_item
  • cataloginventory_stock_status

كتالوج مخزون_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);
}

كتالوج مخزون_المخزون_حالة

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);
}

جرد_

في البداية، يحتوي الهيكل الجديد لتخزين بيانات المخزون على 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).

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

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

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);
}

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

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

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

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

  • 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 - الحرف الأول والثاني من اسم الملف مع الصورة. على سبيل المثال الملف image.png يجب حفظها باسم ./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 MagentoFrameworkAppResourceConnection $this->resource */
    /** @var MagentoFrameworkDBAdapterPdoMysql $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 MagentoFrameworkAppResourceConnection $this->resource */
    /** @var MagentoFrameworkDBAdapterPdoMysql $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 MagentoFrameworkAppResourceConnection $this->resource */
    /** @var MagentoFrameworkDBAdapterPdoMysql $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)
  • صورة صغيرة (small_image)
  • ظفري (thumbnail)
  • صورة سواتش(swatch_image)

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

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

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

Категории

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

  • 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 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);
}

بعد إضافة ارتباط المنتج بالفئتين "الفئة 1" و"الفئة 2"، تبدو تفاصيل المنتج في لوحة الإدارة كما يلي:

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

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

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

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

المنتجات في لوحة الإدارة بعد تنفيذ خطوات إضافية:

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

وفي المقدمة:

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

ملخص

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

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

المصدر: www.habr.com