Manera fácil de agregar un conjunto de campos con campos al formulario de interfaz de usuario

Publicado: 2016-08-23

En este artículo, vamos a crear un módulo simple que agregará un conjunto de campos con campos en el formulario de interfaz de usuario de edición del producto. Además, crearemos un observador para interceptar estos datos durante el guardado del producto.

Primero, necesitamos crear un módulo Vendor_Product:

1. Cree un directorio aplicación/código/proveedor/producto
2. Cree un archivo de registro app/code/Vendor/Product/registration.php con el siguiente contenido:

 <?php
    \Magento\Framework\Component\ComponentRegistrar::registrar(
        \Magento\Framework\Component\ComponentRegistrar::MÓDULO,
        'Proveedor_Producto',
        __DIR__
    );
    ?>

Cree un archivo de compositor (si planea transferir el módulo) app/code/Vendor/Module/composer.json :

 {
        "nombre": "proveedor/módulo-producto",
        "descripción": "N/A",
        "tipo": "módulo magento2",
        "versión": "1.0.0",
        "licencia": [
            "OSL-3.0",
            "AFL-3.0"
        ],
        "carga automática": {
            "archivos": [
                "registro.php"
            ],
            "psr-4": {
                "Proveedor\\Producto\\": ""
            }
        }
    }

Ahora, cree el archivo XML principal app/code/Vendor/Product/etc/module.xml del módulo con la dependencia del módulo Magento_Catalog porque nuestra ventana modal se agregará a su formulario:

 <?xml versión="1.0"?>
    <config xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Module/etc/module.xsd">
        <nombre del módulo="Producto_proveedor" setup_version="1.0.0">
            <secuencia>
                <nombre del módulo="Magento_Catalog"/>
            </secuencia>
        </módulo>
    </config>

Habilite el módulo ingresando lo siguiente: módulo bin/magento: habilite Vendor_Product y configuración bin/magento: actualice en el directorio raíz de Magento.

Luego, agregue el contenido del módulo: los metadatos del formulario de interfaz de usuario y el tipo virtual para su adición.

Cree un archivo app/code/Vendor/Product/etc/adminhtml/di.xml. Vamos a colocar un modificador dentro:

 <?xml versión="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">
        <argumentos>
            <argumento nombre="modificadores" xsi:tipo="matriz">
                <item name="conjunto-de-campos-personalizado" xsi:type="matriz">
                    <item name="class" xsi:type="string">Vendor\Product\Ui\DataProvider\Product\Form\Modifier\CustomFieldset</item>
                    <elemento nombre="ordenar" xsi:tipo="número">10</elemento>
                </elemento>
            </argumento>
        </argumentos>
    </tipo virtual>
</config>

El modificador es responsable de la adición de datos y algunas manipulaciones con elementos y componentes de formularios de interfaz de usuario. Hay 2 métodos principales que provienen de la interfaz del modificador (siempre deben estar presentes):

 <?php
    /**
     * Derechos de autor 2016 Magento. Reservados todos los derechos.
     * Consulte COPYING.txt para conocer los detalles de la licencia.
     */
    espacio de nombres Magento\Ui\DataProvider\Modifier;
    
    /**
     * Interfaz de modificador de clase
     */
    interfaz ModificadorInterfaz
    {
        /**
         * matriz @param $datos
         * Matriz @return
         */
        función pública modificar datos (matriz $ datos);
    
        /**
         * matriz @param $meta
         * Matriz @return
         */
        función pública modificarMeta(matriz $meta);
    }
    ?>

Vamos a utilizar el método modifyMeta en este ejemplo. El método modifyData se explicará en el próximo artículo.

Ahora, cree el archivo modificador (app/code/Vendor/Product/Ui/DataProvider/Product/Form/Modifier/CustomFieldset.php) con un campo personalizado para la página de edición del producto y rellénelo con los campos:

 <?php
espacio de nombres Proveedor\Producto\Ui\Proveedor de datos\Producto\Formulario\Modificador;

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

clase CustomFieldset extiende AbstractModifier
{

    // Índices de componentes
    const CUSTOM_FIELDSET_INDEX = 'conjunto_campo_personalizado';
    const CUSTOM_FIELDSET_CONTENT = 'custom_fieldset_content';
    const CONTAINER_HEADER_NAME = 'custom_fieldset_content_header';

    // Nombres de los campos
    const FIELD_NAME_TEXT = 'ejemplo_texto_campo';
    const FIELD_NAME_SELECT = 'example_select_field';
    const FIELD_NAME_MULTISELECT = 'example_multiselect_field';

    /**
     * @var \Magento\Catalog\Model\Locator\LocatorInterface
     */
    localizador de $ protegido;

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

    /**
     * @var interfaz de URL
     */
    $urlBuilder protegido;

    /**
     * Matriz @var
     */
    protegido $ meta = [];

    /**
     * @param LocatorInterface $localizador
     * @param ArrayManager $arrayManager
     * @param UrlInterface $urlBuilder
     */
    función pública __construir(
        LocalizadorInterfaz $localizador,
        ArrayManager $arrayManager,
        UrlInterfaz $urlBuilder
    ) {
        $este->localizador = $localizador;
        $this->arrayManager = $arrayManager;
        $this->urlBuilder = $urlBuilder;
    }

    /**
     * Modificador de datos, no hace nada en nuestro ejemplo.
     *
     * matriz @param $datos
     * Matriz @return
     */
    función pública modificar datos (matriz $ datos)
    {
        devolver $datos;
    }

    /**
     * Modificador de metadatos: agrega nuestro conjunto de campos
     *
     * matriz @param $meta
     * Matriz @return
     */
    función pública modificarMeta(matriz $meta)
    {
        $esto->meta = $meta;
        $this->addCustomFieldset();

        devuelve $esto->meta;
    }

    /**
     * Combine los metadatos existentes con nuestros metadatos (¡no los sobrescriba!)
     *
     * @retorno nulo
     */
    función protegida addCustomFieldset()
    {
        $esto->meta = array_merge_recursive(
            $esto->meta,
            [
                estático::CUSTOM_FIELDSET_INDEX => $esto->getFieldsetConfig(),
            ]
        );
    }

    /**
     * Declarar nuestra configuración de campo
     *
     * Matriz @return
     */
    función protegida getFieldsetConfig()
    {
        devolver [
            'argumentos' => [
                'datos' => [
                    'config' => [
                        'etiqueta' => __('Título de conjunto de campos'),
                        'tipo de componente' => Fieldset::NOMBRE,
                        'dataScope' => static::DATA_SCOPE_PRODUCT, // guardar datos en los datos del producto
                        'proveedor' => estático::DATA_SCOPE_PRODUCT . '_fuente de datos',
                        'ns' => estático::FORM_NAME,
                        'plegable' => verdadero,
                        'ordenar' => 10,
                        'abierto' => verdadero,
                    ],
                ],
            ],
            'hijos' => [
                estático::CONTAINER_HEADER_NAME => $this->getHeaderContainerConfig(10),
                estático::FIELD_NAME_TEXT => $this->getTextFieldConfig(20),
                estático::FIELD_NAME_SELECT => $this->getSelectFieldConfig(30),
                estático::FIELD_NAME_MULTISELECT => $this->getMultiSelectFieldConfig(40),
            ],
        ];
    }

    /**
     * Obtener configuración para contenedor de encabezado
     *
     * @param int $OrdenOrdenar
     * Matriz @return
     */
    función protegida getHeaderContainerConfig($sortOrder)
    {
        devolver [
            'argumentos' => [
                'datos' => [
                    'config' => [
                        'etiqueta' => nulo,
                        'formElement' => Contenedor::NOMBRE,
                        'componentType' => Contenedor::NOMBRE,
                        'plantilla' => 'ui/formulario/componentes/complejo',
                        'OrdenOrdenar' => $OrdenOrdenar,
                        'contenido' => __('Puedes escribir cualquier texto aquí'),
                    ],
                ],
            ],
            'hijos' => [],
        ];
    }

    /**
     * Ejemplo de configuración de campo de texto
     *
     * @param $OrdenOrdenar
     * Matriz @return
     */
    función protegida getTextFieldConfig($sortOrder)
    {
        devolver [
            'argumentos' => [
                'datos' => [
                    'config' => [
                        'etiqueta' => __('Campo de texto de ejemplo'),
                        'formElement' => Campo::NOMBRE,
                        'tipo de componente' => Entrada::NOMBRE,
                        'dataScope' => estático::FIELD_NAME_TEXT,
                        'tipo de datos' => Número::NOMBRE,
                        'OrdenOrdenar' => $OrdenOrdenar,
                    ],
                ],
            ],
        ];
    }

    /**
     * Ejemplo de configuración de campo de selección
     *
     * @param $OrdenOrdenar
     * Matriz @return
     */
    función protegida getSelectFieldConfig($sortOrder)
    {
        devolver [
            'argumentos' => [
                'datos' => [
                    'config' => [
                        'etiqueta' => __('Seleccionar opciones'),
                        'tipo de componente' => Campo::NOMBRE,
                        'formElement' => Seleccionar::NOMBRE,
                        'dataScope' => estático::FIELD_NAME_SELECT,
                        'tipo de datos' => Texto::NOMBRE,
                        'OrdenOrdenar' => $OrdenOrdenar,
                        'opciones' => $this->_getOptions(),
                        'visible' => verdadero,
                        'deshabilitado' => falso,
                    ],
                ],
            ],
        ];
    }

    /**
     * Ejemplo de configuración de campo de selección múltiple
     *
     * @param $OrdenOrdenar
     * Matriz @return
     */
    función protegida getMultiSelectFieldConfig($sortOrder)
    {
        devolver [
            'argumentos' => [
                'datos' => [
                    'config' => [
                        'etiqueta' => __('Opciones Multiselección'),
                        'tipo de componente' => Campo::NOMBRE,
                        'formElement' => MultiSelect::NOMBRE,
                        'dataScope' => estático::FIELD_NAME_MULTISELECT,
                        'tipo de datos' => Texto::NOMBRE,
                        'OrdenOrdenar' => $OrdenOrdenar,
                        'opciones' => $this->_getOptions(),
                        'visible' => verdadero,
                        'deshabilitado' => falso,
                    ],
                ],
            ],
        ];
    }

    /**
     * Obtenga opciones de ejemplo como una matriz de opciones:
     * [
     * etiqueta => cadena,
     * valor => option_id
     * ]
     *
     * Matriz @return
     */
    función protegida _getOptions()
    {
        $opciones = [
            1 => [
                'etiqueta' => __('Opción 1'),
                'valor' => 1
            ],
            2 => [
                'etiqueta' => __('Opción 2'),
                'valor' => 2
            ],
            3 => [
                'etiqueta' => __('Opción 3'),
                'valor' => 3
            ],
        ];

        devolver $opciones;
    }
}
?>

En este ejemplo, debemos tomar los metadatos del formulario de interfaz de usuario existente y fusionarlos (¡no reescribirlos!) con nuestros nuevos datos:

 <?php
/**
 * Combine los metadatos existentes con nuestros metadatos (¡no los sobrescriba!)
 *
 * @retorno nulo
 */
función protegida addCustomFieldset()
{
    $esto->meta = array_merge_recursive(
        $esto->meta,
        [
            estático::CUSTOM_FIELDSET_INDEX => $esto->getFieldsetConfig(),
        ]
    );
}
?>

Cuando haya terminado, agregue el nuevo conjunto de campos al método getFieldsetConfig:

 <?php
/**
 * Declarar nuestra configuración de campo
 *
 * Matriz @return
 */
función protegida getFieldsetConfig()
{
    devolver [
        'argumentos' => [
            'datos' => [
                'config' => [
                    'etiqueta' => __('Título de conjunto de campos'),
                    'tipo de componente' => Fieldset::NOMBRE,
                    'dataScope' => static::DATA_SCOPE_PRODUCT, // guardar datos en los datos del producto
                    'proveedor' => estático::DATA_SCOPE_PRODUCT . '_fuente de datos',
                    'ns' => estático::FORM_NAME,
                    'plegable' => verdadero,
                    'ordenar' => 10,
                    'abierto' => verdadero,
                ],
            ],
        ],
        'hijos' => [
            estático::CONTAINER_HEADER_NAME => $this->getHeaderContainerConfig(10),
            estático::FIELD_NAME_TEXT => $this->getTextFieldConfig(20),
            estático::FIELD_NAME_SELECT => $this->getSelectFieldConfig(30),
            estático::FIELD_NAME_MULTISELECT => $this->getMultiSelectFieldConfig(40),
        ],
    ];
}
?>

Heredamos del modificador de formulario de interfaz de usuario del producto abstracto y usamos su espacio de nombres y datos como proveedor: 'provider' => static::DATA_SCOPE_PRODUCT . '_data_source' (donde DATA_SCOPE_PRODUCT es la línea 'data.product').

La opción componentType es una de las opciones principales y es responsable del tipo de componente. La opción plegable es responsable de contraer y expandir nuestro conjunto de campos. Y la opción abierta define si el conjunto de campos estará abierto por defecto durante el dibujo del formulario.

Luego, en consecuencia, agregamos un encabezado a nuestro conjunto de campos en el método getHeaderContainerConfig y 3 ejemplos de campos: texto, selección y selección múltiple. Sin embargo, nuestro producto y formulario no recibirán datos hasta que los agreguemos al método modifyData. Pero tenemos la capacidad de transmitir e interceptar los datos durante el guardado.

Veamos cómo queda el formulario:

El guardado de datos se lleva a cabo dentro del archivo del controlador del producto vendor/magento/module-catalog/Controller/Adminhtml/Product/Save.php en el método de ejecución principal. Si todo se ha hecho de la manera correcta, nuestros datos se mostrarán correctamente en los datos de entrada de este método:

Tenga en cuenta que si su producto no tiene esos atributos desde el principio, debe guardarlos manualmente. Puedes hacer esto en el observador.

Primero, declárelo en el archivo app/code/Vendor/Product/etc/adminhtml/events.xml (estamos usando el ámbito adminhtml porque el formulario no existe en el front-end):

 <?xml versión="1.0"?>
<config xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Event/etc/events.xsd">
    <nombre del evento="catalog_product_save_after">
        <observer name="save_example_data" instancia="Vendor\Product\Observer\ProductSaveAfter" />
    </evento>
</config>

Luego, crea la clase del observador que señalamos en el atributo de la instancia: app/code/Vendor/Product/Observer/ProductSaveAfter.php:

 <?php
espacio de nombres Proveedor\Producto\Observador;

use \Magento\Framework\Event\ObserverInterface;
use \Magento\Framework\Event\Observer como EventObserver;
use Proveedor\Producto\Ui\Proveedor de datos\Producto\Formulario\Modificador\CustomFieldset;

clase ProductSaveAfter implementa ObserverInterface
{

    /**
     * @param EventObserver $observador
     */
    función pública ejecutar (\Magento\Framework\Event\Observer $observer)
    {
        /** @var \Magento\Catálogo\Modelo\Producto $producto */
        $producto = $observador->getEvent()->getProduct();
        si (!$producto) {
            devolver;
        }

        $exampleTextField = $producto->getData(CustomFieldset::FIELD_NAME_TEXT);
        $exampleSelectField = $producto->getData(CustomFieldset::FIELD_NAME_SELECT);
        $ejemploMultiSelectField = $producto->getData(CustomFieldset::FIELD_NAME_MULTISELECT);

        // Manipular datos aquí
    }
}
?>

Los datos en el observador:

Ahora, puede llamar a su propio modelo desde el observador y guardar datos en él o modificarlo como desee.

¡Ten cuidado! Si el ahorro de su modelo está conectado con el ahorro del producto, entonces puede conducir a la recurrencia.