Mod ușoară de a adăuga un set de câmpuri cu câmpuri la formularul UI

Publicat: 2016-08-23

În acest articol, vom crea un modul simplu care va adăuga un set de câmpuri cu câmpuri în formularul UI de editare a produsului. De asemenea, vom crea un observator care să intercepteze aceste date în timpul salvării produsului.

Mai întâi, trebuie să creăm un modul Vendor_Product:

1. Creați un director aplicație/cod/furnizor/produs
2. Creați un fișier de înregistrare app/code/Vendor/Product/registration.php cu următorul conținut:

 <?php
    \Magento\Framework\Component\ComponentRegistrar::register(
        \Magento\Framework\Component\ComponentRegistrar::MODULE,
        „Vendor_Product”,
        __DIR__
    );
    ?>

Creați un fișier compozitor (dacă intenționați să transferați modulul) app/code/Vendor/Module/composer.json :

 {
        "nume": "furnizor/modul-produs",
        "descriere": "N/A",
        "type": "magento2-module",
        "versiunea": "1.0.0",
        "licență": [
            „OSL-3.0”,
            „AFL-3.0”
        ],
        „încărcare automată”: {
            „fișiere”: [
                "registration.php"
            ],
            „psr-4”: {
                „Vânzător\\Produs\\”: „”
            }
        }
    }

Acum, creați principalul fișier XML al modulului app/code/Vendor/Product/etc/module.xml cu dependența din modulul Magento_Catalog, deoarece fereastra noastră modală va fi adăugată la forma sa:

 <?xml version="1.0"?>
    <config xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Module/etc/module.xsd">
        <module name="Vendor_Product" setup_version="1.0.0">
            <secvență>
                <module name="Magento_Catalog"/>
            </sequence>
        </modul>
    </config>

Activați modulul introducând următoarele: bin/magento module:enable Vendor_Product și bin/magento setup:upgrade în directorul rădăcină Magento.

Apoi, adăugați conținutul modulului: metadatele formei UI și tipul virtual pentru adăugarea acestuia.

Creați un fișier app/code/Vendor/Product/etc/adminhtml/di.xml. Vom plasa un modificator în interior:

 <?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">
        <argumente>
            <argument name="modifiers" xsi:type="array">
                <item name="custom-fieldset" xsi:type="array">
                    <item name="class" xsi:type="string">Vendor\Product\Ui\DataProvider\Product\Form\Modifier\CustomFieldset</item>
                    <item name="sortOrder" xsi:type="number">10</item>
                </item>
            </argument>
        </argumente>
    </virtualType>
</config>

Modificatorul este responsabil pentru adăugarea datelor și unele manipulări cu elemente și componente de formular UI. Există 2 metode principale care provin din interfața modificatorului (ar trebui să fie întotdeauna prezente):

 <?php
    /**
     * Copyright 2016 Magento. Toate drepturile rezervate.
     * Consultați COPYING.txt pentru detalii despre licență.
     */
    spațiu de nume Magento\Ui\DataProvider\Modifier;
    
    /**
     * Interfață de modificare a clasei
     */
    Interfață ModifierInterfață
    {
        /**
         * @param array $date
         * @return matrice
         */
        funcția publică modifyData(matrice $date);
    
        /**
         * @param matrice $meta
         * @return matrice
         */
        funcția publică modifyMeta(array $meta);
    }
    ?>

Vom folosi metoda modifyMeta în acest exemplu. Metoda modifyData va fi explicată în articolul următor.

Acum, creați fișierul modificator (app/code/Vendor/Product/Ui/DataProvider/Product/Form/Modifier/CustomFieldset.php) cu un set de câmpuri personalizat pentru pagina de editare a produsului și completați-l cu câmpurile:

 <?php
spațiu de nume Vendor\Product\Ui\DataProvider\Product\Form\Modifier;

utilizați Magento\Catalog\Model\Locator\LocatorInterface;
utilizați Magento\Catalog\Ui\DataProvider\Product\Form\Modifier\AbstractModifier;
utilizați Magento\Framework\Stdlib\ArrayManager;
utilizați Magento\Framework\UrlInterface;
utilizați Magento\Ui\Component\Container;
utilizați Magento\Ui\Component\Form\Fieldset;
utilizați Magento\Ui\Component\Form\Element\DataType\Number;
utilizați Magento\Ui\Component\Form\Element\DataType\Text;
utilizați Magento\Ui\Component\Form\Element\Input;
utilizați Magento\Ui\Component\Form\Element\Select;
utilizați Magento\Ui\Component\Form\Element\MultiSelect;
utilizați Magento\Ui\Component\Form\Field;

clasa CustomFieldset extinde AbstractModifier
{

    // Indici de componente
    const CUSTOM_FIELDSET_INDEX = 'custom_fieldset';
    const CUSTOM_FIELDSET_CONTENT = 'custom_fieldset_content';
    const CONTAINER_HEADER_NAME = 'custom_fieldset_content_header';

    // Numele câmpurilor
    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 protejat;

    /**
     * @var ArrayManager
     */
    protejat $arrayManager;

    /**
     * @var UrlInterface
     */
    protejat $urlBuilder;

    /**
     * @var matrice
     */
    protejat $meta = [];

    /**
     * @param LocatorInterface $locator
     * @param ArrayManager $arrayManager
     * @param UrlInterface $urlBuilder
     */
    funcția publică __construct(
        LocatorInterface $locator,
        ArrayManager $arrayManager,
        UrlInterface $urlBuilder
    ) {
        $this->locator = $locator;
        $this->arrayManager = $arrayManager;
        $this->urlBuilder = $urlBuilder;
    }

    /**
     * Modificator de date, nu face nimic în exemplul nostru.
     *
     * @param array $date
     * @return matrice
     */
    funcția publică modifyData(matrice $date)
    {
        returnează $date;
    }

    /**
     * Modificator de metadate: adaugă setul de câmpuri al nostru
     *
     * @param matrice $meta
     * @return matrice
     */
    funcția publică modifyMeta(matrice $meta)
    {
        $this->meta = $meta;
        $this->addCustomFieldset();

        returnează $this->meta;
    }

    /**
     * Îmbinați metadatele existente cu metadatele noastre (nu le suprascrieți!)
     *
     * @return nul
     */
    funcția protejată addCustomFieldset()
    {
        $this->meta = array_merge_recursive(
            $this->meta,
            [
                static::CUSTOM_FIELDSET_INDEX => $this->getFieldsetConfig(),
            ]
        );
    }

    /**
     * Declarați configurația fieldset-ului nostru
     *
     * @return matrice
     */
    funcția protejată getFieldsetConfig()
    {
        întoarcere [
            'argumente' => [
                'date' => [
                    'config' => [
                        'label' => __('Titlul setului de câmpuri'),
                        'componentType' => Fieldset::NAME,
                        'dataScope' => static::DATA_SCOPE_PRODUCT, // salvează datele în datele produsului
                        'provider' => static::DATA_SCOPE_PRODUCT . '_sursă de date',
                        'ns' => static::FORM_NAME,
                        'colapsabil' => adevărat,
                        'sortOrder' => 10,
                        'deschis' => adevărat,
                    ],
                ],
            ],
            'copii' => [
                static::CONTAINER_HEADER_NAME => $this->getHeaderContainerConfig(10),
                static::FIELD_NAME_TEXT => $this->getTextFieldConfig(20),
                static::FIELD_NAME_SELECT => $this->getSelectFieldConfig(30),
                static::FIELD_NAME_MULTISELECT => $this->getMultiSelectFieldConfig(40),
            ],
        ];
    }

    /**
     * Obțineți configurația pentru containerul antet
     *
     * @param int $sortOrder
     * @return matrice
     */
    funcția protejată getHeaderContainerConfig($sortOrder)
    {
        întoarcere [
            'argumente' => [
                'date' => [
                    'config' => [
                        'label' => null,
                        'formElement' => Container::NAME,
                        'componentType' => Container::NAME,
                        'template' => 'ui/form/components/complex',
                        'sortOrder' => $sortOrder,
                        'content' => __('Puteți scrie orice text aici'),
                    ],
                ],
            ],
            „copii” => [],
        ];
    }

    /**
     * Exemplu de configurare a câmpului de text
     *
     * @param $sortOrder
     * @return matrice
     */
    funcția protejată getTextFieldConfig($sortOrder)
    {
        întoarcere [
            'argumente' => [
                'date' => [
                    'config' => [
                        'label' => __('Exemplu de câmp text'),
                        'formElement' => Câmp::NAME,
                        'componentType' => Intrare::NAME,
                        'dataScope' => static::FIELD_NAME_TEXT,
                        'dataType' => Number::NAME,
                        'sortOrder' => $sortOrder,
                    ],
                ],
            ],
        ];
    }

    /**
     * Exemplu de configurare a câmpului de selectare
     *
     * @param $sortOrder
     * @return matrice
     */
    funcția protejată getSelectFieldConfig($sortOrder)
    {
        întoarcere [
            'argumente' => [
                'date' => [
                    'config' => [
                        'label' => __('Opțiuni Selectați'),
                        'componentType' => Câmp::NAME,
                        'formElement' => Selectați::NAME,
                        'dataScope' => static::FIELD_NAME_SELECT,
                        'dataType' => Text::NAME,
                        'sortOrder' => $sortOrder,
                        'options' => $this->_getOptions(),
                        „vizibil” => adevărat,
                        'disabled' => fals,
                    ],
                ],
            ],
        ];
    }

    /**
     * Exemplu de configurare a câmpului cu selecție multiplă
     *
     * @param $sortOrder
     * @return matrice
     */
    funcția protejată getMultiSelectFieldConfig($sortOrder)
    {
        întoarcere [
            'argumente' => [
                'date' => [
                    'config' => [
                        'label' => __('Opțiuni Multiselect'),
                        'componentType' => Câmp::NAME,
                        'formElement' => MultiSelect::NAME,
                        'dataScope' => static::FIELD_NAME_MULTISELECT,
                        'dataType' => Text::NAME,
                        'sortOrder' => $sortOrder,
                        'options' => $this->_getOptions(),
                        „vizibil” => adevărat,
                        'disabled' => fals,
                    ],
                ],
            ],
        ];
    }

    /**
     * Obțineți exemple de opțiuni ca matrice de opțiuni:
     * [
     * etichetă => șir,
     * valoare => opțiune_id
     * ]
     *
     * @return matrice
     */
    funcția protejată _getOptions()
    {
        $opțiuni = [
            1 => [
                'label' => __('Opțiunea 1'),
                „valoare” => 1
            ],
            2 => [
                'label' => __('Opțiunea 2'),
                „valoare” => 2
            ],
            3 => [
                'label' => __('Opțiunea 3'),
                „valoare” => 3
            ],
        ];

        returnează $opțiuni;
    }
}
?>

În acest exemplu, trebuie să luăm metadatele existente ale formei UI și să le îmbinăm (nu să le rescriem!) cu noile noastre date:

 <?php
/**
 * Îmbinați metadatele existente cu metadatele noastre (nu le suprascrieți!)
 *
 * @return nul
 */
funcția protejată addCustomFieldset()
{
    $this->meta = array_merge_recursive(
        $this->meta,
        [
            static::CUSTOM_FIELDSET_INDEX => $this->getFieldsetConfig(),
        ]
    );
}
?>

Când ați terminat, adăugați noul set de câmpuri la metoda getFieldsetConfig:

 <?php
/**
 * Declarați configurația fieldset-ului nostru
 *
 * @return matrice
 */
funcția protejată getFieldsetConfig()
{
    întoarcere [
        'argumente' => [
            'date' => [
                'config' => [
                    'label' => __('Titlul setului de câmpuri'),
                    'componentType' => Fieldset::NAME,
                    'dataScope' => static::DATA_SCOPE_PRODUCT, // salvează datele în datele produsului
                    'provider' => static::DATA_SCOPE_PRODUCT . '_sursă de date',
                    'ns' => static::FORM_NAME,
                    'colapsabil' => adevărat,
                    'sortOrder' => 10,
                    'deschis' => adevărat,
                ],
            ],
        ],
        'copii' => [
            static::CONTAINER_HEADER_NAME => $this->getHeaderContainerConfig(10),
            static::FIELD_NAME_TEXT => $this->getTextFieldConfig(20),
            static::FIELD_NAME_SELECT => $this->getSelectFieldConfig(30),
            static::FIELD_NAME_MULTISELECT => $this->getMultiSelectFieldConfig(40),
        ],
    ];
}
?>

Moștenim de la modificatorul UI-form produs abstract și folosim spațiul de nume și datele acestuia ca furnizor: 'provider' => static::DATA_SCOPE_PRODUCT . „_data_source” (unde DATA_SCOPE_PRODUCT este linia „data.product”).

Opțiunea componentType este una dintre opțiunile principale și este responsabilă pentru tipul de componentă. Opțiunea pliabilă este responsabilă pentru restrângerea și extinderea setului nostru de câmpuri. Și opțiunea de deschidere definește dacă setul de câmpuri va fi deschis în mod implicit în timpul desenării formularului.

Apoi, în consecință, adăugăm un antet la setul nostru de câmpuri în metoda getHeaderContainerConfig și 3 exemple de câmpuri: text, select și multiselect. Cu toate acestea, produsul și formularul nostru nu vor primi date până când nu le vom adăuga la metoda modifyData. Dar avem capacitatea de a transmite și intercepta datele în timpul salvării.

Să vedem cum arată formularul:

Salvarea datelor are loc în fișierul controlerului de produs vendor/magento/module-catalog/Controller/Adminhtml/Product/Save.php în metoda principală de execuție. Dacă totul a fost făcut în mod corect, atunci datele noastre vor fi afișate corect în datele de intrare ale acestei metode:

Rețineți, dacă produsul dvs. nu are aceste atribute de la început, ar trebui să le salvați manual. Puteți face acest lucru în observator.

Mai întâi, declarați-l în fișierul app/code/Vendor/Product/etc/adminhtml/events.xml (folosim domeniul de aplicare adminhtml deoarece formularul nu există pe front-end):

 <?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="catalog_product_save_after">
        <observer name="save_example_data" instance="Vendor\Product\Observer\ProductSaveAfter" />
    </eveniment>
</config>

Apoi, creați clasa observatorului pe care am indicat-o în atributul instanței – app/code/Vendor/Product/Observer/ProductSaveAfter.php:

 <?php
spațiu de nume Vendor\Product\Observer;

utilizați \Magento\Framework\Event\ObserverInterface;
utilizați \Magento\Framework\Event\Observer ca EventObserver;
utilizați Vendor\Product\Ui\DataProvider\Product\Form\Modifier\CustomFieldset;

clasa ProductSaveAfter implementează ObserverInterface
{

    /**
     * @param EventObserver $observator
     */
    funcția publică execute(\Magento\Framework\Event\Observer $observator)
    {
        /** @var \Magento\Catalog\Model\Product $produs */
        $produs = $observator->getEvent()->getProduct();
        dacă (!$produs) {
            întoarcere;
        }

        $exampleTextField = $produs->getData(CustomFieldset::FIELD_NAME_TEXT);
        $exampleSelectField = $produs->getData(CustomFieldset::FIELD_NAME_SELECT);
        $exampleMultiSelectField = $produs->getData(CustomFieldset::FIELD_NAME_MULTISELECT);

        // Manipulați datele aici
    }
}
?>

Datele din observator:

Acum, puteți să vă apelați propriul model de la observator și să salvați datele în el sau să îl modificați după cum doriți.

Atenție! Dacă salvarea modelului dvs. este legată de salvarea produsului, atunci poate duce la recursivitate.