Łatwy sposób na dodanie zestawu pól z polami do formularza interfejsu użytkownika

Opublikowany: 2016-08-23

W tym artykule stworzymy prosty moduł, który doda zestaw pól z polami w formularzu UI edycji produktu. Ponadto stworzymy obserwatora, który przechwyci te dane podczas zapisywania produktu.

Najpierw musimy stworzyć moduł Vendor_Product:

1. Utwórz katalog app/code/Vendor/Product
2. Utwórz plik rejestracyjny app/code/Vendor/Product/registration.php o następującej zawartości:

 <?php
    \Magento\Framework\Component\ComponentRegistrar::register(
        \Magento\Framework\Component\ComponentRegistrar::MODULE,
        'Produkt_Dostawcy',
        __KATALOG__
    );
    ?>

Utwórz plik kompozytora (jeśli planujesz przenieść moduł) app/code/Vendor/Module/composer.json :

 {
        "name": "dostawca/moduł-produkt",
        "opis": "nie dotyczy",
        "typ": "magento2-moduł",
        "wersja": "1.0.0",
        "licencja": [
            "OSL-3.0",
            "AFL-3.0"
        ],
        "automatyczne ładowanie": {
            "akta": [
                "rejestracja.php"
            ],
            "psr-4": {
                "Dostawca\\Produkt\\": ""
            }
        }
    }

Teraz utwórz główny plik XML modułu app/code/Vendor/Product/etc/module.xml z zależnością z modułu Magento_Catalog, ponieważ nasze okno modalne zostanie dodane do jego formularza:

 <?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">
            <sekwencja>
                <nazwa modułu="Magento_Catalog"/>
            </sequence>
        </moduł>
    </config>

Włącz moduł, wpisując: bin/magento module:enable Vendor_Product i bin/magento setup:upgrade w głównym katalogu Magento.

Następnie dodaj zawartość modułu: metadane formularza interfejsu użytkownika i typ wirtualny do jego dodania.

Utwórz plik app/code/Vendor/Product/etc/adminhtml/di.xml. Umieścimy wewnątrz modyfikator:

 <?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">
        <argumenty>
            <argument name="modyfikatory" xsi:type="array">
                <item name="niestandardowy zestaw pól" xsi:type="array">
                    <item name="class" xsi:type="string">Dostawca\Produkt\Ui\DataProvider\Produkt\Form\Modifier\CustomFieldset</item>
                    <item name="sortOrder" xsi:type="number">10</item>
                </item>
            </argument>
        </arguments>
    </virtualType>
</config>

Modyfikator odpowiada za dodawanie danych oraz pewne manipulacje elementami i komponentami formularza UI. Istnieją 2 główne metody, które pochodzą z interfejsu modyfikatora (powinny zawsze być obecne):

 <?php
    /**
     * Prawa autorskie 2016 Magento. Wszelkie prawa zastrzeżone.
     * Zobacz COPYING.txt, aby uzyskać szczegółowe informacje o licencji.
     */
    przestrzeń nazw Magento\Ui\DataProvider\Modifier;
    
    /**
     * Interfejs modyfikatora klasy
     */
    Modyfikator interfejsuInterfejs
    {
        /**
         * @param array $data
         * @tablica powrotu
         */
        funkcja publiczna zmieńDane(tablica $dane);
    
        /**
         * @param array $meta
         * @tablica powrotu
         */
        funkcja publiczna zmodyfikujMeta(tablica $meta);
    }
    ?>

W tym przykładzie użyjemy metody modyfikacjiMeta. Metoda modyfikacjiData zostanie wyjaśniona w następnym artykule.

Teraz utwórz plik modyfikatora (app/code/Vendor/Product/Ui/DataProvider/Product/Form/Modifier/CustomFieldset.php) z niestandardowym zestawem pól dla strony edycji produktu i wypełnij go polami:

 <?php
przestrzeń nazw Dostawca\Produkt\Ui\DataProvider\Produkt\Form\Modyfikator;

użyj Magento\Catalog\Model\Locator\LocatorInterface;
użyj Magento\Catalog\Ui\DataProvider\Product\Form\Modifier\AbstractModifier;
użyj Magento\Framework\Stdlib\ArrayManager;
użyj Magento\Framework\UrlInterface;
użyj Magento\Ui\Komponent\Kontener;
użyj Magento\Ui\Component\Form\Fieldset;
użyj Magento\Ui\Component\Form\Element\DataType\Number;
użyj Magento\Ui\Component\Form\Element\DataType\Text;
użyj Magento\Ui\Komponent\Formularz\Element\Input;
użyj Magento\Ui\Komponent\Formularz\Element\Select;
użyj Magento\Ui\Komponent\Formularz\Element\MultiSelect;
użyj Magento\Ui\Komponent\Formularz\Pole;

klasa CustomFieldset rozszerza AbstractModifier
{

    // Indeksy składników
    const CUSTOM_FIELDSET_INDEX = 'niestandardowy_zestaw_pól';
    const CUSTOM_FIELDSET_CONTENT = 'custom_fieldset_content';
    const CONTAINER_HEADER_NAME = 'custom_fieldset_content_header';

    // Nazwy pól
    const FIELD_NAME_TEXT = 'przykładowe_pole_tekstowe';
    const FIELD_NAME_SELECT = 'example_select_field';
    const FIELD_NAME_MULTISELECT = 'example_multiselect_field';

    /**
     * @var \Magento\Catalog\Model\Locator\LocatorInterface
     */
    chroniony lokalizator;

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

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

    /**
     * @var array
     */
    chroniony $meta = [];

    /**
     * @param LocatorInterface $locator
     * @param ArrayManager $arrayManager
     * @param UrlInterface $urlBuilder
     */
    funkcja publiczna __konstrukcja(
        LocatorInterface $lokator,
        $arrayManager,
        UrlInterface $urlBuilder
    ) {
        $to->lokalizator = $lokalizator;
        $this->arrayManager = $arrayManager;
        $this->urlBuilder = $urlBuilder;
    }

    /**
     * Modyfikator danych, w naszym przykładzie nic nie robi.
     *
     * @param array $data
     * @tablica powrotu
     */
    funkcja publiczna zmieńDane(tablica $dane)
    {
        zwróć $dane;
    }

    /**
     * Modyfikator metadanych: dodaje nasz zestaw pól
     *
     * @param array $meta
     * @tablica powrotu
     */
    funkcja publiczna zmodyfikujMeta(tablica $meta)
    {
        $to->meta = $meta;
        $this->addCustomFieldset();

        zwróć $to->meta;
    }

    /**
     * Połącz istniejące metadane z naszymi metadanymi (nie nadpisuj ich!)
     *
     * @zwrot nieważny
     */
    funkcja chroniona addCustomFieldset()
    {
        $this->meta = array_merge_recursive(
            $this->meta,
            [
                static::CUSTOM_FIELDSET_INDEX => $this->getFieldsetConfig(),
            ]
        );
    }

    /**
     * Zadeklaruj naszą konfigurację zestawu pól
     *
     * @tablica powrotu
     */
    funkcja chroniona getFieldsetConfig()
    {
        zwrócić [
            'argumenty' => [
                'dane' => [
                    'konfiguracja' => [
                        'label' => __('Tytuł pola'),
                        'componentType' => Fieldset::NAME,
                        'dataScope' => static::DATA_SCOPE_PRODUCT, // zapisz dane w danych produktu
                        'provider' => static::DATA_SCOPE_PRODUCT . '_źródło danych',
                        'ns' => statyczny::FORM_NAME,
                        'składany' => prawda,
                        'porządek sortowania' => 10,
                        'otwarte' => prawda,
                    ],
                ],
            ],
            'dzieci' => [
                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),
            ],
        ];
    }

    /**
     * Pobierz konfigurację dla kontenera nagłówka
     *
     * @param int $sortOrder
     * @tablica powrotu
     */
    funkcja chroniona getHeaderContainerConfig($sortOrder)
    {
        zwrócić [
            'argumenty' => [
                'dane' => [
                    'konfiguracja' => [
                        'etykieta' => null,
                        'formElement' => Kontener::NAZWA,
                        'componentType' => Kontener::NAZWA,
                        'szablon' => 'ui/formularz/komponenty/kompleks',
                        'sortOrder' => $sortOrder,
                        'content' => __('Tu możesz wpisać dowolny tekst'),
                    ],
                ],
            ],
            'dzieci' => [],
        ];
    }

    /**
     * Przykładowa konfiguracja pola tekstowego
     *
     * @param $sortOrder
     * @tablica powrotu
     */
    funkcja chroniona getTextFieldConfig($sortOrder)
    {
        zwrócić [
            'argumenty' => [
                'dane' => [
                    'konfiguracja' => [
                        'label' => __('Przykładowe pole tekstowe'),
                        'formElement' => Pole::NAME,
                        'componentType' => Input::NAME,
                        'dataScope' => statyczny::FIELD_NAME_TEXT,
                        'dataType' => Numer::NAZWA,
                        'sortOrder' => $sortOrder,
                    ],
                ],
            ],
        ];
    }

    /**
     * Przykładowa konfiguracja pola wyboru
     *
     * @param $sortOrder
     * @tablica powrotu
     */
    funkcja chroniona getSelectFieldConfig($sortOrder)
    {
        zwrócić [
            'argumenty' => [
                'dane' => [
                    'konfiguracja' => [
                        'label' => __('Opcje Wybierz'),
                        'componentType' => Pole::NAZWA,
                        'formElement' => Wybierz::NAME,
                        'dataScope' => statyczny::FIELD_NAME_SELECT,
                        'dataType' => Tekst::NAZWA,
                        'sortOrder' => $sortOrder,
                        'opcje' => $this->_getOptions(),
                        'widoczny' => prawda,
                        'wyłączone' => fałsz,
                    ],
                ],
            ],
        ];
    }

    /**
     * Przykładowa konfiguracja pola wielokrotnego wyboru
     *
     * @param $sortOrder
     * @tablica powrotu
     */
    funkcja chroniona getMultiSelectFieldConfig($sortOrder)
    {
        zwrócić [
            'argumenty' => [
                'dane' => [
                    'konfiguracja' => [
                        'label' => __('Opcje wielokrotnego wyboru'),
                        'componentType' => Pole::NAZWA,
                        'formElement' => MultiSelect::NAME,
                        'dataScope' => statyczny::FIELD_NAME_MULTISELECT,
                        'dataType' => Tekst::NAZWA,
                        'sortOrder' => $sortOrder,
                        'opcje' => $this->_getOptions(),
                        'widoczny' => prawda,
                        'wyłączone' => fałsz,
                    ],
                ],
            ],
        ];
    }

    /**
     * Pobierz przykładowe opcje jako tablicę opcji:
     * [
     * etykieta => ciąg,
     * wartość => identyfikator_opcji
     * ]
     *
     * @tablica powrotu
     */
    funkcja chroniona _getOptions()
    {
        $opcje = [
            1 => [
                'etykieta' => __('Opcja 1'),
                'wartość' => 1
            ],
            2 => [
                'etykieta' => __('Opcja 2'),
                'wartość' => 2
            ],
            3 => [
                'etykieta' => __('Opcja 3'),
                'wartość' => 3
            ],
        ];

        zwróć $opcje;
    }
}
?>

W tym przykładzie musimy wziąć istniejące metadane formularza interfejsu użytkownika i połączyć je (nie przepisać!) z naszymi nowymi danymi:

 <?php
/**
 * Połącz istniejące metadane z naszymi metadanymi (nie nadpisuj ich!)
 *
 * @zwrot nieważny
 */
funkcja chroniona addCustomFieldset()
{
    $this->meta = array_merge_recursive(
        $this->meta,
        [
            static::CUSTOM_FIELDSET_INDEX => $this->getFieldsetConfig(),
        ]
    );
}
?>

Po zakończeniu dodaj nowy zestaw pól do metody getFieldsetConfig:

 <?php
/**
 * Zadeklaruj naszą konfigurację zestawu pól
 *
 * @tablica powrotu
 */
funkcja chroniona getFieldsetConfig()
{
    zwrócić [
        'argumenty' => [
            'dane' => [
                'konfiguracja' => [
                    'label' => __('Tytuł pola'),
                    'componentType' => Fieldset::NAME,
                    'dataScope' => static::DATA_SCOPE_PRODUCT, // zapisz dane w danych produktu
                    'provider' => static::DATA_SCOPE_PRODUCT . '_źródło danych',
                    'ns' => statyczny::FORM_NAME,
                    'składany' => prawda,
                    'porządek sortowania' => 10,
                    'otwarte' => prawda,
                ],
            ],
        ],
        'dzieci' => [
            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),
        ],
    ];
}
?>

Dziedziczymy po abstrakcyjnym modyfikatorze formularza interfejsu użytkownika produktu i używamy jego przestrzeni nazw i danych jako dostawcy: 'provider' => static::DATA_SCOPE_PRODUCT . „_data_source” (gdzie DATA_SCOPE_PRODUCT to wiersz „data.product”).

Opcja componentType jest jedną z głównych opcji i odpowiada za typ komponentu. Opcja collapsible odpowiada za zwijanie i rozwijanie naszego zestawu pól. A opcja open określa, czy zestaw pól będzie domyślnie otwarty podczas rysowania formularza.

Następnie konsekwentnie dodajemy nagłówek do naszego zestawu pól w metodzie getHeaderContainerConfig oraz 3 przykłady pól: text, select i multiselect. Jednak nasz produkt i formularz nie otrzymają danych, dopóki nie dodamy ich do metody modyfikacjiData. Ale mamy możliwość przesyłania i przechwytywania danych podczas zapisywania.

Zobaczmy jak wygląda formularz:

Zapisywanie danych odbywa się w pliku kontrolera produktu vendor/magento/module-catalog/Controller/Adminhtml/Product/Save.php w głównej metodzie wykonywania. Jeśli wszystko zostało zrobione we właściwy sposób, to nasze dane będą poprawnie wyświetlane w danych wejściowych tej metody:

Pamiętaj, że jeśli Twój produkt nie ma tych atrybutów od początku, powinieneś zapisać je ręcznie. Możesz to zrobić w obserwatorze.

Najpierw zadeklaruj go w pliku app/code/Vendor/Product/etc/adminhtml/events.xml (używamy zakresu adminhtml, ponieważ formularz nie istnieje na interfejsie):

 <?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="Dostawca\Produkt\Obserwator\ProduktZapiszPo" />
    </event>
</config>

Następnie stwórz klasę obserwatora, którą wskazaliśmy w atrybucie instancji – app/code/Vendor/Product/Observer/ProductSaveAfter.php:

 <?php
przestrzeń nazw Dostawca\Produkt\Obserwator;

użyj \Magento\Framework\Event\ObserverInterface;
użyj \Magento\Framework\Event\Observer jako EventObserver;
użyj Vendor\Product\Ui\DataProvider\Product\Form\Modifier\CustomFieldset;

klasa ProduktZapiszPo wdrożeniu ObserverInterface
{

    /**
     * @param EventObserver $observer
     */
    wykonanie funkcji publicznej (\Magento\Framework\Event\Observer $observer)
    {
        /** @var \Magento\Katalog\Model\Produkt $produkt */
        $product = $observer->getEvent()->getProduct();
        jeśli (!$produkt) {
            zwrócić;
        }

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

        // Manipuluj danymi tutaj
    }
}
?>

Dane w obserwatorze:

Teraz możesz wywołać własny model z obserwatora i zapisać w nim dane lub zmodyfikować go według własnego uznania.

Bądź ostrożny! Jeśli zapisanie Twojego modelu jest połączone z zapisywaniem produktu, może to prowadzić do rekursji.