طريقة سهلة لإضافة مجموعة الحقول مع الحقول إلى نموذج واجهة المستخدم

نشرت: 2016-08-23

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

أولاً ، نحتاج إلى إنشاء وحدة Vendor_Product:

1. قم بإنشاء تطبيق دليل / كود / بائع / منتج
2. أنشئ تطبيق / كود / بائع / منتج / تسجيل ملف تسجيل بالمحتوى التالي:

 <؟ php
    \ Magento \ Framework \ Component \ ComponentRegistrar :: تسجيل (
        \ Magento \ Framework \ مكون \ ComponentRegistrar :: MODULE ،
        "Vendor_Product"،
        __DIR__
    ) ؛
    ؟>

قم بإنشاء ملف composer (إذا كنت تخطط لنقل الوحدة) app / code / Vendor / Module / composer.json:

 {
        "الاسم": "البائع / منتج الوحدة" ،
        "الوصف": "N / A"،
        "النوع": "magento2-module" ،
        "الإصدار": "1.0.0"،
        "رخصة": [
            "OSL-3.0" ،
            "AFL-3.0"
        ] ،
        "تحميل تلقائى": {
            "الملفات": [
                "registration.php"
            ] ،
            "psr-4": {
                "المورّد \\ المنتج \\": ""
            }
        }
    }

الآن ، قم بإنشاء ملف XML الرئيسي للوحدة app / code / Vendor / Product / etc / module.xml بالتبعية من الوحدة النمطية Magento_Catalog لأن نافذة النموذج الخاصة بنا ستُضاف إلى شكلها:

 <؟ xml version = "1.0"؟>
    <config xmlns: xsi = "https://www.w3.org/2001/XMLSchema-instance" xsi: noNamespaceSchemaLocation = "urn: magento: framework: Module / etc / module.xsd">
        <اسم الوحدة النمطية = "Vendor_Product" setup_version = "1.0.0">
            <تسلسل>
                <اسم الوحدة النمطية = "Magento_Catalog" />
            </sequence>
        </module>
    </config>

قم بتمكين الوحدة عن طريق إدخال ما يلي: bin / magento module: قم بتمكين إعداد Vendor_Product و bin / magento: الترقية في دليل Magento الجذر.

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

قم بإنشاء ملف app / code / Vendor / Product / etc / adminhtml / di.xml. سنقوم بوضع مُعدِّل في الداخل:

 <؟ xml version = "1.0"؟>
<config xmlns: xsi = "https://www.w3.org/2001/XMLSchema-instance" xsi: noNamespaceSchemaLocation = "urn: magento: framework: ObjectManager / etc / config.xsd">
    <virtualType name = "Magento \ Catalog \ Ui \ DataProvider \ Product \ Form \ Modifier \ Pool">
        <الحجج>
            <اسم الوسيطة = "المعدلات" xsi: type = "array">
                <item name = "custom-fieldset" xsi: type = "array">
                    <item name = "class" xsi: type = "string"> المورّد \ المنتج \ Ui \ DataProvider \ Product \ Form \ Modifier \ CustomFieldset </item>
                    <item name = "sortOrder" xsi: type = "number"> 10 </item>
                </item>
            </argument>
        </ الحجج>
    </virtualType>
</config>

يعد المُعدِّل مسؤولاً عن إضافة البيانات وبعض التلاعب بالعناصر ومكونات شكل واجهة المستخدم. هناك طريقتان رئيسيتان تم الحصول عليهما من واجهة المُعدِّل (يجب أن تكون موجودة دائمًا):

 <؟ php
    / **
     * حقوق الطبع والنشر 2016 Magento. كل الحقوق محفوظة.
     * راجع COPYING.txt للحصول على تفاصيل الترخيص.
     * /
    مساحة الاسم Magento \ Ui \ DataProvider \ Modifier ؛
    
    / **
     * واجهة معدّل الفئة
     * /
    معدل الواجهة
    {
        / **
         *param array $ data
         *return مجموعة
         * /
        تعديل بيانات الوظيفة العامة (مجموعة البيانات $) ؛
    
        / **
         *param array $ meta
         *return مجموعة
         * /
        تعديل الوظيفة العامة (المصفوفة $ ميتا) ؛
    }
    ؟>

سنستخدم طريقة editMeta في هذا المثال. سيتم شرح طريقة editData في المقالة التالية.

الآن ، قم بإنشاء ملف التعديل (app / code / Vendor / Product / Ui / DataProvider / Product / Form / Modifier / CustomFieldset.php) بمجموعة حقول مخصصة لصفحة تحرير المنتج واملأها بالحقول:

 <؟ php
مورد مساحة الاسم \ المنتج \ Ui \ DataProvider \ Product \ Form \ Modifier ؛

استخدم Magento \ Catalog \ Model \ Locator \ LocatorInterface؛
استخدم Magento \ Catalog \ Ui \ DataProvider \ Product \ Form \ Modifier \ AbstractModifier ؛
استخدم Magento \ Framework \ Stdlib \ ArrayManager ؛
استخدام Magento \ Framework \ UrlInterface ؛
استخدام Magento \ Ui \ Component \ Container ؛
استخدام Magento \ Ui \ Component \ Form \ Fieldset ؛
استخدم Magento \ Ui \ Component \ Form \ Element \ DataType \ Number ؛
استخدم Magento \ Ui \ Component \ Form \ Element \ DataType \ Text ؛
استخدم Magento \ Ui \ Component \ Form \ Element \ Input ؛
استخدم Magento \ Ui \ Component \ Form \ Element \ Select ؛
استخدم Magento \ Ui \ Component \ Form \ Element \ MultiSelect ؛
استخدام Magento \ Ui \ Component \ Form \ Field ؛

تقوم فئة CustomFieldset بتوسيع AbstractModifier
{

    // فهارس المكونات
    const CUSTOM_FIELDSET_INDEX = 'custom_fieldset' ،
    const CUSTOM_FIELDSET_CONTENT = 'custom_fieldset_content' ،
    CONTAINER_HEADER_NAME = "custom_fieldset_content_header" ،

    // أسماء الحقول
    const FIELD_NAME_TEXT = 'example_text_field' ،
    const FIELD_NAME_SELECT = 'example_select_field' ،
    const FIELD_NAME_MULTISELECT = 'example_multiselect_field' ،

    / **
     *var \ Magento \ Catalog \ Model \ Locator \ LocatorInterface
     * /
    محمي $ locator؛

    / **
     * فار ArrayManager
     * /
    arrayManager $ المحمي؛

    / **
     *var UrlInterface
     * /
    محمية urlBuilder $؛

    / **
     * @ مجموعة فار
     * /
    محمية $ meta = []؛

    / **
     *param LocatorInterface $ locator
     *param ArrayManager $ arrayManager
     *param UrlInterface $ urlBuilder
     * /
    الوظيفة العامة __construct (
        LocatorInterface $ locator ،
        ArrayManager $ arrayManager ،
        UrlInterface $ urlBuilder
    ) {
        $ this-> locator = $ locator؛
        $ this-> arrayManager = $ arrayManager ؛
        $ this-> urlBuilder = $ urlBuilder؛
    }

    / **
     * معدّل البيانات ، لا يفعل شيئًا في مثالنا.
     *
     *param array $ data
     *return مجموعة
     * /
    تعديل بيانات الوظيفة العامة (مجموعة بيانات $)
    {
        إرجاع البيانات $؛
    }

    / **
     * معدل البيانات الوصفية: يضيف مجموعة الحقول الخاصة بنا
     *
     *param array $ meta
     *return مجموعة
     * /
    تعديل الوظيفة العامة ميتا (مجموعة ميتا $)
    {
        $ this-> meta = $ meta؛
        $ this-> addCustomFieldset ()؛

        إرجاع $ this-> meta؛
    }

    / **
     * دمج البيانات الوصفية الموجودة مع البيانات الوصفية الخاصة بنا (لا تقم بالكتابة فوقها!)
     *
     *return الفراغ
     * /
    وظيفة محمية addCustomFieldset ()
    {
        $ this-> meta = array_merge_recursive (
            $ this-> meta،
            [
                ثابت :: CUSTOM_FIELDSET_INDEX => $ this-> getFieldsetConfig () ،
            ]
        ) ؛
    }

    / **
     * نعلن لنا fieldset config
     *
     *return مجموعة
     * /
    وظيفة محمية getFieldsetConfig ()
    {
        إرجاع [
            "الحجج" => [
                "البيانات" => [
                    'التكوين' => [
                        'label' => __ ('Fieldset Title') ،
                        'componentType' => Fieldset :: NAME،
                        'dataScope' => ثابت :: DATA_SCOPE_PRODUCT ، // حفظ البيانات في بيانات المنتج
                        'Provider' => ثابت :: DATA_SCOPE_PRODUCT. '_مصدر البيانات'،
                        'ns' => ثابت :: FORM_NAME ،
                        'قابل للطي' => صحيح ،
                        "sortOrder" => 10 ،
                        'فتح' => صحيح ،
                    ] ،
                ] ،
            ] ،
            "الأطفال" => [
                ثابت :: CONTAINER_HEADER_NAME => $ this-> getHeaderContainerConfig (10) ،
                ثابت :: FIELD_NAME_TEXT => $ this-> getTextFieldConfig (20) ،
                ثابت :: FIELD_NAME_SELECT => $ this-> getSelectFieldConfig (30) ،
                ثابت :: FIELD_NAME_MULTISELECT => $ this-> getMultiSelectFieldConfig (40) ،
            ] ،
        ] ؛
    }

    / **
     * احصل على التكوين لحاوية الرأس
     *
     *param int $ sortOrder
     *return مجموعة
     * /
    وظيفة محمية getHeaderContainerConfig ($ sortOrder)
    {
        إرجاع [
            "الحجج" => [
                "البيانات" => [
                    'التكوين' => [
                        'التسمية' => خالية ،
                        'formElement' => الحاوية :: NAME ،
                        'componentType' => الحاوية :: NAME ،
                        'template' => 'ui / form / Components / complex' ،
                        'sortOrder' => sortOrder $ ،
                        'content' => __ ('يمكنك كتابة أي نص هنا') ،
                    ] ،
                ] ،
            ] ،
            "الأطفال" => [] ،
        ] ؛
    }

    / **
     * مثال حقل نص التكوين
     *
     *param $ sortOrder
     *return مجموعة
     * /
    وظيفة محمية getTextFieldConfig ($ sortOrder)
    {
        إرجاع [
            "الحجج" => [
                "البيانات" => [
                    'التكوين' => [
                        'label' => __ ('مثال لحقل نصي') ،
                        'formElement' => الحقل :: الاسم ،
                        'componentType' => الإدخال :: NAME ،
                        'dataScope' => ثابت :: FIELD_NAME_TEXT ،
                        'dataType' => الرقم :: NAME ،
                        'sortOrder' => sortOrder $ ،
                    ] ،
                ] ،
            ] ،
        ] ؛
    }

    / **
     * مثال حدد حقل التكوين
     *
     *param $ sortOrder
     *return مجموعة
     * /
    وظيفة محمية getSelectFieldConfig ($ sortOrder)
    {
        إرجاع [
            "الحجج" => [
                "البيانات" => [
                    'التكوين' => [
                        "تسمية" => __ ("تحديد الخيارات") ،
                        'componentType' => الحقل :: NAME ،
                        'formElement' => حدد :: NAME ،
                        'dataScope' => ثابت :: FIELD_NAME_SELECT ،
                        'dataType' => نص :: NAME ،
                        'sortOrder' => sortOrder $ ،
                        "الخيارات" => $ this -> _ getOptions () ،
                        'مرئي' => صحيح ،
                        'معطل' => خطأ ،
                    ] ،
                ] ،
            ] ،
        ] ؛
    }

    / **
     * مثال على تكوين حقل متعدد التحديد
     *
     *param $ sortOrder
     *return مجموعة
     * /
    وظيفة محمية getMultiSelectFieldConfig ($ sortOrder)
    {
        إرجاع [
            "الحجج" => [
                "البيانات" => [
                    'التكوين' => [
                        "تسمية" => __ ("خيارات متعددة التحديد") ،
                        'componentType' => الحقل :: NAME ،
                        'formElement' => تحديد متعدد :: NAME ،
                        'dataScope' => ثابت :: FIELD_NAME_MULTISELECT ،
                        'dataType' => نص :: NAME ،
                        'sortOrder' => sortOrder $ ،
                        "الخيارات" => $ this -> _ getOptions () ،
                        'مرئي' => صحيح ،
                        'معطل' => خطأ ،
                    ] ،
                ] ،
            ] ،
        ] ؛
    }

    / **
     * احصل على أمثلة على الخيارات كمصفوفة خيارات:
     * [
     * التسمية => سلسلة ،
     * القيمة => option_id
     *]
     *
     *return مجموعة
     * /
    وظيفة محمية _getOptions ()
    {
        خيارات دولار = [
            1 => [
                "التسمية" => __ ("الخيار 1") ،
                "القيمة" => 1
            ] ،
            2 => [
                "التسمية" => __ ("الخيار 2") ،
                "القيمة" => 2
            ] ،
            3 => [
                "التسمية" => __ ("الخيار 3") ،
                "القيمة" => 3
            ] ،
        ] ؛

        عودة $ الخيارات؛
    }
}
؟>

في هذا المثال ، نحتاج إلى أخذ البيانات الوصفية الموجودة في شكل واجهة المستخدم ودمجها (وليس إعادة كتابتها!) مع بياناتنا الجديدة:

 <؟ php
/ **
 * دمج البيانات الوصفية الموجودة مع البيانات الوصفية الخاصة بنا (لا تقم بالكتابة فوقها!)
 *
 *return الفراغ
 * /
وظيفة محمية addCustomFieldset ()
{
    $ this-> meta = array_merge_recursive (
        $ this-> meta،
        [
            ثابت :: CUSTOM_FIELDSET_INDEX => $ this-> getFieldsetConfig () ،
        ]
    ) ؛
}
؟>

عند الانتهاء ، أضف مجموعة الحقول الجديدة إلى طريقة getFieldsetConfig:

 <؟ php
/ **
 * نعلن لنا fieldset config
 *
 *return مجموعة
 * /
وظيفة محمية getFieldsetConfig ()
{
    إرجاع [
        "الحجج" => [
            "البيانات" => [
                'التكوين' => [
                    'label' => __ ('Fieldset Title') ،
                    'componentType' => Fieldset :: NAME،
                    'dataScope' => ثابت :: DATA_SCOPE_PRODUCT ، // حفظ البيانات في بيانات المنتج
                    'Provider' => ثابت :: DATA_SCOPE_PRODUCT. '_مصدر البيانات'،
                    'ns' => ثابت :: FORM_NAME ،
                    'قابل للطي' => صحيح ،
                    "sortOrder" => 10 ،
                    'فتح' => صحيح ،
                ] ،
            ] ،
        ] ،
        "الأطفال" => [
            ثابت :: CONTAINER_HEADER_NAME => $ this-> getHeaderContainerConfig (10) ،
            ثابت :: FIELD_NAME_TEXT => $ this-> getTextFieldConfig (20) ،
            ثابت :: FIELD_NAME_SELECT => $ this-> getSelectFieldConfig (30) ،
            ثابت :: FIELD_NAME_MULTISELECT => $ this-> getMultiSelectFieldConfig (40) ،
        ] ،
    ] ؛
}
؟>

نحن نرث من مُعدِّل نموذج واجهة المستخدم للمنتج المجرد ونستخدم مساحة الاسم والبيانات الخاصة به كمزود: 'Provider' => static :: DATA_SCOPE_PRODUCT. "_data_source" (حيث DATA_SCOPE_PRODUCT هو سطر "data.product").

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

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

دعونا نرى كيف يبدو النموذج:

يتم حفظ البيانات داخل بائع ملف وحدة التحكم في المنتج / magento / module -atalog / Controller / Adminhtml / Product / Save.php في طريقة التنفيذ الرئيسية. إذا تم كل شيء بالطريقة الصحيحة ، فسيتم عرض بياناتنا بشكل صحيح في بيانات الإدخال لهذه الطريقة:

لاحظ أنه إذا لم يكن منتجك يحتوي على هذه السمات من البداية ، فيجب عليك حفظها يدويًا. يمكنك القيام بذلك في المراقب.

أولاً ، قم بالإعلان عنه في ملف app / code / Vendor / Product / etc / adminhtml / events.xml (نحن نستخدم نطاق adminhtml لأن النموذج غير موجود في الواجهة الأمامية):

 <؟ xml version = "1.0"؟>
<config xmlns: xsi = "https://www.w3.org/2001/XMLSchema-instance" xsi: noNamespaceSchemaLocation = "urn: magento: framework: Event / etc / events.xsd">
    <event name = "atalog_product_save_after ">
        <Observer name = "save_example_data" مثيل = "Vendor \ Product \ Observer \ ProductSaveAfter" />
    </event>
</config>

بعد ذلك ، أنشئ فئة المراقب التي أشرنا إليها في سمة المثيل - app / code / Vendor / Product / Observer / ProductSaveAfter.php:

 <؟ php
مساحة الاسم البائع \ المنتج \ المراقب ؛

استخدم \ Magento \ Framework \ Event \ ObserverInterface ؛
استخدم \ Magento \ Framework \ Event \ Observer كـ EventObserver ؛
استخدام Vendor \ Product \ Ui \ DataProvider \ Product \ Form \ Modifier \ CustomFieldset ؛

فئة ProductSaveAfter تنفذ ObserverInterface
{

    / **
     *param EventObserver $ Observer
     * /
    تنفيذ الوظيفة العامة (\ Magento \ Framework \ Event \ Observer $ Observer)
    {
        / **var \ Magento \ Catalog \ Model \ Product $ product * /
        $ product = $ Observer-> getEvent () -> getProduct () ؛
        إذا (! $ product) {
            إرجاع؛
        }

        $ exampleTextField = $ product-> getData (CustomFieldset :: FIELD_NAME_TEXT) ؛
        $ exampleSelectField = $ product-> getData (CustomFieldset :: FIELD_NAME_SELECT) ؛
        $ exampleMultiSelectField = $ product-> getData (CustomFieldset :: FIELD_NAME_MULTISELECT) ؛

        // التلاعب بالبيانات هنا
    }
}
؟>

البيانات الموجودة في المراقب:

الآن ، يمكنك استدعاء النموذج الخاص بك من المراقب وحفظ البيانات فيه أو تعديله كما يحلو لك.

كن حذرا! إذا كان حفظ النموذج الخاص بك متصلاً بحفظ المنتج ، فقد يؤدي ذلك إلى التكرار.