La solución anterior no es completamente correcta. Está agregando un campo como elemento html "desnudo" y un formulario de producto es un formulario de interfaz de usuario con sus propias peculiaridades. Una clase especial ( vendor/magento/module-ui/view/base/web/js/form/form.js
) es responsable de la recopilación de campos y su validación cuando se envía un formulario. Además, esta clase debe omitir los campos que no están relacionados con este formulario de IU o que no son additional fields
similares a todos sus campos. Debe usar los siguientes nombres para asegurarse de que su campo se enviará al controlador:
Pero esto no es completamente correcto porque la solución correcta es no desviarse de los estándares de uso de formularios de IU y utilizar sus elementos y componentes nativos. En este caso, no debe preocuparse por tal cosa porque todo se procesará automáticamente.
Puede verificar el método principal para almacenar los datos de los formularios de la IU para comprender el proceso:
Como puede ver en este código, no se envía un formulario html con todos sus campos. Sin embargo, this.source
y this.additionalFields
se envían pero su elemento no está incluido en él porque se declara incorrectamente.
Aquí está el ejemplo sobre cómo agregar un conjunto de campos desde nuestro blog. Puede leer el artículo completo, utilizando el siguiente enlace:
Agregue el contenido: los metadatos de forma de interfaz de usuario y el tipo virtual para su adición.
Crea un archivo app/code/Vendor/Product/etc/adminhtml/di.xml
. Vamos a colocar un modificador dentro:
<?xml version="1.0"?>
<config xmlns:xsi="http://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">
<arguments>
<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>
</arguments>
</virtualType>
</config>
Ahora, cree el archivo modificador ( app/code/Vendor/Product/Ui/DataProvider/Product/Form/Modifier/CustomFieldset.php
) con un conjunto de campos personalizado para la página de edición del producto y complételo con los campos:
<?php
namespace Vendor\Product\Ui\DataProvider\Product\Form\Modifier;
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;
class CustomFieldset extends AbstractModifier
{
// Components indexes
const CUSTOM_FIELDSET_INDEX = 'custom_fieldset';
const CUSTOM_FIELDSET_CONTENT = 'custom_fieldset_content';
const CONTAINER_HEADER_NAME = 'custom_fieldset_content_header';
// Fields names
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
*/
protected $locator;
/**
* @var ArrayManager
*/
protected $arrayManager;
/**
* @var UrlInterface
*/
protected $urlBuilder;
/**
* @var array
*/
protected $meta = [];
/**
* @param LocatorInterface $locator
* @param ArrayManager $arrayManager
* @param UrlInterface $urlBuilder
*/
public function __construct(
LocatorInterface $locator,
ArrayManager $arrayManager,
UrlInterface $urlBuilder
) {
$this->locator = $locator;
$this->arrayManager = $arrayManager;
$this->urlBuilder = $urlBuilder;
}
/**
* Data modifier, does nothing in our example.
*
* @param array $data
* @return array
*/
public function modifyData(array $data)
{
return $data;
}
/**
* Meta-data modifier: adds ours fieldset
*
* @param array $meta
* @return array
*/
public function modifyMeta(array $meta)
{
$this->meta = $meta;
$this->addCustomFieldset();
return $this->meta;
}
/**
* Merge existing meta-data with our meta-data (do not overwrite it!)
*
* @return void
*/
protected function addCustomFieldset()
{
$this->meta = array_merge_recursive(
$this->meta,
[
static::CUSTOM_FIELDSET_INDEX => $this->getFieldsetConfig(),
]
);
}
/**
* Declare ours fieldset config
*
* @return array
*/
protected function getFieldsetConfig()
{
return [
'arguments' => [
'data' => [
'config' => [
'label' => __('Fieldset Title'),
'componentType' => Fieldset::NAME,
'dataScope' => static::DATA_SCOPE_PRODUCT, // save data in the product data
'provider' => static::DATA_SCOPE_PRODUCT . '_data_source',
'ns' => static::FORM_NAME,
'collapsible' => true,
'sortOrder' => 10,
'opened' => true,
],
],
],
'children' => [
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),
],
];
}
/**
* Get config for header container
*
* @param int $sortOrder
* @return array
*/
protected function getHeaderContainerConfig($sortOrder)
{
return [
'arguments' => [
'data' => [
'config' => [
'label' => null,
'formElement' => Container::NAME,
'componentType' => Container::NAME,
'template' => 'ui/form/components/complex',
'sortOrder' => $sortOrder,
'content' => __('You can write any text here'),
],
],
],
'children' => [],
];
}
/**
* Example text field config
*
* @param $sortOrder
* @return array
*/
protected function getTextFieldConfig($sortOrder)
{
return [
'arguments' => [
'data' => [
'config' => [
'label' => __('Example Text Field'),
'formElement' => Field::NAME,
'componentType' => Input::NAME,
'dataScope' => static::FIELD_NAME_TEXT,
'dataType' => Number::NAME,
'sortOrder' => $sortOrder,
],
],
],
];
}
/**
* Example select field config
*
* @param $sortOrder
* @return array
*/
protected function getSelectFieldConfig($sortOrder)
{
return [
'arguments' => [
'data' => [
'config' => [
'label' => __('Options Select'),
'componentType' => Field::NAME,
'formElement' => Select::NAME,
'dataScope' => static::FIELD_NAME_SELECT,
'dataType' => Text::NAME,
'sortOrder' => $sortOrder,
'options' => $this->_getOptions(),
'visible' => true,
'disabled' => false,
],
],
],
];
}
/**
* Example multi-select field config
*
* @param $sortOrder
* @return array
*/
protected function getMultiSelectFieldConfig($sortOrder)
{
return [
'arguments' => [
'data' => [
'config' => [
'label' => __('Options Multiselect'),
'componentType' => Field::NAME,
'formElement' => MultiSelect::NAME,
'dataScope' => static::FIELD_NAME_MULTISELECT,
'dataType' => Text::NAME,
'sortOrder' => $sortOrder,
'options' => $this->_getOptions(),
'visible' => true,
'disabled' => false,
],
],
],
];
}
/**
* Get example options as an option array:
* [
* label => string,
* value => option_id
* ]
*
* @return array
*/
protected function _getOptions()
{
$options = [
1 => [
'label' => __('Option 1'),
'value' => 1
],
2 => [
'label' => __('Option 2'),
'value' => 2
],
3 => [
'label' => __('Option 3'),
'value' => 3
],
];
return $options;
}
}
El almacenamiento de datos se realiza dentro del archivo 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, declare en el
app/code/Vendor/Product/etc/adminhtml/events.xml
archivo (estamos usando el alcance adminhtml porque el formulario no existe en el front-end):
<?xml version="1.0"?>
<config xmlns:xsi="http://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" />
</event>
</config>
Luego, cree la clase del observador que señalamos en el atributo de instancia app/code/Vendor/Product/Observer/ProductSaveAfter.php
:
<?php
namespace Vendor\Product\Observer;
use \Magento\Framework\Event\ObserverInterface;
use \Magento\Framework\Event\Observer as EventObserver;
use Vendor\Product\Ui\DataProvider\Product\Form\Modifier\CustomFieldset;
class ProductSaveAfter implements ObserverInterface
{
/**
* @param EventObserver $observer
*/
public function execute(\Magento\Framework\Event\Observer $observer)
{
/** @var \Magento\Catalog\Model\Product $product */
$product = $observer->getEvent()->getProduct();
if (!$product) {
return;
}
$exampleTextField = $product->getData(CustomFieldset::FIELD_NAME_TEXT);
$exampleSelectField = $product->getData(CustomFieldset::FIELD_NAME_SELECT);
$exampleMultiSelectField = $product->getData(CustomFieldset::FIELD_NAME_MULTISELECT);
// Manipulate data here
}
}
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 guardado de su modelo está relacionado con el guardado del producto, puede conducir a la recursión.