Contextualizando
O que é UI Component?
Os Ui Components são usados para representar elementos distintos da interface do usuário, como tabelas, botões, formulários e outros. São componentes simples e flexíveis projetados para renderização da interface do usuário, estes componentes são responsáveis por renderizar fragmentos de página e fornecer/suportar interações adicionais de componentes JavaScript.
Os UI Components são implementados no módulo Magento_UI. Para utilizar os Ui Components em um módulo personalizado é necessário adicionar uma dependência para o módulo Magento_UI no arquivo composer.json
do módulo.
No Magento 2 os Ui Components básicos são os formulários e as grades de listagens, todos os outros são secundários. Os componentes básicos são declarados nos arquivos de layout da página, já os componentes secundários são declarados nos arquivos de configuração das instâncias dos componentes de nível superior.
Saiba como inserir ui_components em uma página no post "Como criar arquivos de layout Magento 2".
Formulário
Os formulários são utilizados para disponibilizar os campos para serem cadastrados e/ou editados de uma entidade, sendo que esses campos podem ser divididos por conjuntos de campos (tabulações laterais) para especificar a quais campos pertencem a área.
Código para criar um formulário
Provedor de Dados
É a classe PHP responsável por providenciar os dados do banco e deixar disponível através do atributo name
. A interface \Magento\Framework\View\Element\UiComponent\DataProvider\DataProviderInterface
deve ser implementada pela classe \{Vendor}\{Module}\Ui\Component\{EntityName}\FormDataProvider
para criar e retornar os dados para o formulário da página.
<?php
namespace {Vendor}\{Module}\Ui\Component\{EntityName};
use Magento\Ui\DataProvider\AbstractDataProvider;
use {Vendor}\{Module}\Model\ResourceModel\{EntityName}\CollectionFactory;
use {Vendor}\{Module}\Model\ResourceModel\{EntityName}\Collection;
use {Vendor}\{Module}\Model\{EntityName};
class FormDataProvider extends AbstractDataProvider
{
private Collection $collection;
private array $loadedData;
public function __construct(
string $name,
string $primaryFieldName,
string $requestFieldName,
CollectionFactory $collectionFactory,
array $meta = [],
array $data = []
) {
$this->collection = $collectionFactory->create();
parent::__construct(
$name,
$primaryFieldName,
$requestFieldName,
$meta,
$data
);
}
public function getData(): array
{
if (isset($this->loadedData)) {
return $this->loadedData;
}
if (!$this->collection->getSize()) {
return $this->loadedData = [];
}
if ($this->collection->getSize()) {
/** @var {EntityName} $item */
foreach ($this->collection->getItems() as $item) {
$this->loadedData[$item->getId()] = $item->getData();
}
}
return $this->loadedData;
}
}
ui_component.xml
Arquivos ui_components devem seguir a estrutura de pastas \{Vendor}\{Module}\view\{area}\ui_components\{ui_component_name}.xml
.
O caminho da área pode ser frontend ou adminhtml que define onde o templates será aplicado. Para inserir um template no painel administrativo do Magento utilizá-se a área adminhtml, e para inserir um template na parte visual da loja do site utilizá-se a área frontend (não é muito usual serem utilizados nessa área).
<?xml version="1.0"?>
<form xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Ui:etc/ui_configuration.xsd">
<argument name="data" xsi:type="array">
<item name="js_config" xsi:type="array">
<item name="provider" xsi:type="string">{ui_component}.{ui_component}_data_source</item>
</item>
<item name="label" xsi:type="string" translate="true">{Label}</item>
</argument>
<settings>
<buttons>
<button name="{button_name}" class="{Vendor}\{Module}\Block\Adminhtml\{Directory}\{ButtonClassName}"/>
</buttons>
<namespace>{ui_component}</namespace>
<layout>
<navContainerName>left</navContainerName>
<type>tabs</type>
</layout>
<deps>
<dep>{ui_component}.{ui_component}_data_source</dep>
</deps>
</settings>
<dataSource name="{ui_component}_data_source">
<argument name="data" xsi:type="array">
<item name="js_config" xsi:type="array">
<item name="component" xsi:type="string">Magento_Ui/js/form/provider</item>
</item>
</argument>
<settings>
<validateUrl path="{route_id}/{controller_directory}/{controller_name}"/>
<submitUrl path="{route_id}/{controller_directory}/{controller_name}"/>
</settings>
<aclResource>{Vendor}_{Module}::{parentResourceId}</aclResource>
<dataProvider class="{Vendor}\{Module}\Ui\Component\{EntityName}\FormDataProvider" name="{ui_component}_data_source">
<settings>
<requestFieldName>{id}</requestFieldName>
<primaryFieldName>{entity_id}</primaryFieldName>
</settings>
</dataProvider>
</dataSource>
<fieldset name="{fieldset_name}">
<settings>
<disabled>{true/false}</disabled>
<label>{Fieldset Label}</label>
<visible>{true/false}</visible>
<additionalClasses>
<class name="{class-name}">{true/false}</class>
</additionalClasses>
<level>{integer}</level>
<collapsible>{true/false}</collapsible>
<opened>{true/false}</opened>
</settings>
</fieldset>
</form>
O nó <form>
representa o componente de formulário que é uma coleção de campos que podem ser agrupados em guias e fieldsets.
Argument
O nó <argument>
é uma estrutura arbitrária que declara a configuração do componente de formulário que inclui dados que são utilizados para inicializar um objeto. O nó filho <item name="provider">
é responsável por transferir os dados para o nó <dataSource>
. O valor deste item é dividido em duas partes (que é separado por um ponto final), o primeiro valor é responsável por indicar o nome do UI component, já a segunda parte é responsável pelo nome do <dataSource>
, que é destinado a processar os dados no servidor e fazer o UI component processar esses dados.
Settings
O nó <settings>
é responsável por configurar o nó pai <form>
.
- O nó
<buttons>
: é responsável por adicionar botões no menu superior do formulário. Cada botão que queira adicionar basta criar um nó filho chamado<button>
e preencher um atributo chamadoname
para este nó, que será o id deste botão. Para configurar o botão, basta criar nós filhos (<label>
,<url>
e<class>
). - O nó
<namespace>
: é o nó responsável por identificar o formulário e passar ao back-end para realizar ações (validar, endiar, etc). - O nó
<layout>
: é responsável por definir qual o layout que o UI Component irá assumir. O nó filho<type>
indica onde os fieldsets ficarão reparados. O nó<navContainerName>
indica qual a posição da tabulação ficará de acordo com o atributolayout
do arquivo de layout da página. - O nó
<deps>
: deve possuir um nó filho<dep>
e possuir o mesmo valor do<item name="provider">
.
Data Source
o nó <dataSource>
referencia a classe que é responsável por obter os dados solicitados e interagir com o UI component (m*uitos *UI components necessitam deste nó para o seu funcionamento).
O atributo component="Magento_Ui/js/form/provider"
é utilizado para um provedor de dados para o formulário em formato específico que é compartilhado entre todos os UI components no escopo do componente do formulário. É recomendado que o atributo seja nomeado como name=”{ui_component_name}_data_source”
.
- O nó
<settings>
: é responsável por configurar o nó pai<dataSource>
e neste é possível definir qual será o controlador responsável por validar os dados do formulário através do nó<validateUrl>
, e o nó<submitUrl>
é responsável por definir para qual o controlador será enviado os dados do formulário. - O nó
<aclResource>
: define a qual recurso ACL está vinculado e se o usuário logado poderá ter acesso com base no seu papel de usuário, cada usuário ficará limitado aos recursos selecionados do seu papel. - O nó
<dataProvider>
: é a classe responsável por tratar os dados retornado do Provedor de Dados, esta classe deve ser referenciada através do atributo class e é possível definir a classe responsável por essa execução que deve estender a classe\Magento\Ui\DataProvider\AbstractDataProvider
. O nó<dataProvider>
tem o nó filho<settings>
, onde é possível determinar o campo para usar como id para a grade no banco de dados (através do nó filho<primaryFieldName>
) e para a solicitação (através do nó filho<requestFieldName>
).
Fieldsets
O componente fieldset implementa um contêiner para elementos de formulário agrupados visualmente, como botões e campos de formulário. O nó <settings>
é responsável por configurar o conjunto de campos, e possui os seguintes nós filhos:
Nó | Descrição | Tipo |
---|---|---|
disabled | Estado do componente inicial. Quando true, os usuários não podem realizar ações no elemento. | bool |
label | Legenda para um item no contexto. | string |
visible | Visibilidade do componente inicial. Quando false, o componente ficará oculto. | bool |
additionalClasses | Classes personalizadas adicionadas ao bloco no componente do DOM. | Objeto (nó filho XML: {true/false}) |
level | Indica explicitamente o nível de aninhamento. | int |
collapsible | Ativa/desativa a funcionalidade de retrair para ocultar os campos. | bool |
opened | Estado inicial expandido . Aplicado quando a funcionalidade de está habilitada. | bool |
Campos
Atributos | Descrição | Tipo |
---|---|---|
class | Caminho para a classe PHP responsável pela implementação de backend do componente. | string |
component | O caminho para o arquivo .js do componente em termos de RequireJS. | string |
displayArea | Renderiza o componente no local declarado no layout. | string |
elementTmpl | O caminho para o modelo .html do tipo de campo específico. | string |
extends | Estende a configuração do componente especificado. | string |
formElement | Elemento do formulário. | type |
name | O índice do elemento no escopo da coleção atual que será usado para construir seu identificador exclusivo. | string |
provider | Referência o provedor de dados do componente. | string |
sortOrder | Posição do elemento. | integer |
template | O caminho para o modelo .html do componente. | string |
disabled | Estado do componente inicial. Quando definido como verdadeiro, os usuários não podem realizar ações no elemento. | bool |
label | Label do campo. | string |
visible | Visibilidade do componente inicial. | bool |
notices | A matriz de avisos que devem ser associados por chave com o valor da opção selecionada. | array |
Input
<field name="{input_name}" formElement="input" sortOrder="{integer}">
<settings>
<visible>{true/false}</visible>
<label translate="true">{Label}</label>
</settings>
</field>
Text
<field name="{text_name}" formElement="input" sortOrder="{integer}">
<settings>
<elementTmpl>ui/form/element/text</elementTmpl>
<label translate="true">{Label Text}</label>
</settings>
</field>
Textarea
<field name="{textarea_name}" formElement="textarea" sortOrder="{integer}">
<settings>
<label translate="true">{Label Textarea}</label>
</settings>
</field>
Select
<field name="{select_name}" formElement="select" sortOrder="40">
<settings>
<label translate="true">{Label Select}</label>
</settings>
<formElements>
<select>
<settings>
<options>
<option name="{option_name}" xsi:type="array">
<item name="value" xsi:type="string">{option_value}</item>
<item name="label" xsi:type="string">{Option Label}</item>
</option>
</options>
<caption translate="true">{-- Please Select --}</caption>
</settings>
</select>
</formElements>
</field>
Multiselect
<field name="{multiselect_name}" formElement="multiselect" sortOrder="{integer}">
<settings>
<dataType>text</dataType>
<label translate="true">{Label Multiselect}</label>
<dataScope>multiselect_name</dataScope>
</settings>
<formElements>
<multiselect>
<settings>
<options>
<option name="{option_name}" xsi:type="array">
<item name="value" xsi:type="string">{option_value}</item>
<item name="label" xsi:type="string">{Option Label}</item>
</option>
</options>
</settings>
</multiselect>
</formElements>
</field>
Checkbox
<field name="{checkbox_name}" formElement="checkbox" sortOrder="{integer}">
<settings>
<label translate="true">{Label Checkbox}</label>
<tooltip>
<description translate="true">{Description}</description>
</tooltip>
</settings>
<formElements>
<checkbox>
<settings>
<prefer>checkbox</prefer>
<valueMap>
<map name="false" xsi:type="boolean">false</map>
<map name="true" xsi:type="boolean">true</map>
</valueMap>
</settings>
</checkbox>
</formElements>
</field>
<field name="{checkbox_toggle_name}" formElement="checkbox" sortOrder="{integer}">
<settings>
<label translate="true">{Label Checkbox}</label>
<tooltip>
<description translate="true">{Description}</description>
</tooltip>
</settings>
<formElements>
<checkbox>
<settings>
<prefer>toggle</prefer>
<valueMap>
<map name="false" xsi:type="boolean">false</map>
<map name="true" xsi:type="boolean">true</map>
</valueMap>
</settings>
</checkbox>
</formElements>
</field>
Radio
<field name="{radio_name}" formElement="checkbox" sortOrder="{integer}">
<settings>
<label translate="true">{Label Radio}</label>
<tooltip>
<description translate="true">{Description}</description>
</tooltip>
</settings>
<formElements>
<checkbox>
<settings>
<prefer>radio</prefer>
<valueMap>
<map name="false" xsi:type="boolean">false</map>
<map name="true" xsi:type="boolean">true</map>
</valueMap>
</settings>
</checkbox>
</formElements>
</field>
<radioset name="{radioset_name}" sortOrder="{integer}">
<argument name="data" xsi:type="array">
<item name="config" xsi:type="array">
<item name="additionalInfo" xsi:type="string">{Additional information}</item>
</item>
</argument>
<settings>
<label translate="true">{Label Radioset}</label>
<options>
<option name="{option_name}" xsi:type="array">
<item name="value" xsi:type="string">{option_value}</item>
<item name="label" xsi:type="string">{Option Label}</item>
</option>
</options>
</settings>
</radioset>
Date Time
<field name="{date_name}" formElement="date" sortOrder="{integer}">
<argument name="data" xsi:type="array">
<item name="config" xsi:type="array">
<item name="source" xsi:type="string">{source_name}</item>
</item>
</argument>
<settings>
<validation>
<rule name="validate-date" xsi:type="boolean">{true/false}</rule>
</validation>
<dataType>{type}</dataType>
<label translate="true">{Label Date}</label>
<dataScope>{scope_name}</dataScope>
</settings>
</field>
ColorPicker
<colorPicker name="{colorspicker_name}" class="Magento\Ui\Component\Form\Element\ColorPicker" component="Magento_Ui/js/form/element/color-picker" sortOrder="{integer}">
<settings>
<label translate="true">{Label Color}</label>
<elementTmpl>ui/form/element/color-picker</elementTmpl>
<colorFormat>rgb</colorFormat>
<colorPickerMode>full</colorPickerMode>
<dataScope>colors_filter</dataScope>
</settings>
</colorPicker>
File
<file name="file_name" sortOrder="{integer}">
<argument name="data" xsi:type="array">
<item name="config" xsi:type="array">
<item name="label" xsi:type="string">{Label File}</item>
<item name="visible" xsi:type="boolean">{true/false}</item>
<item name="formElement" xsi:type="string">fileUploader</item>
<item name="uploaderConfig" xsi:type="array">
<item name="url" xsi:type="url" path="{router_id}/{controller_folder}/{controller_name}"/>
</item>
</item>
</argument>
</file>
<field name="file_uploader_name" formElement="fileUploader" sortOrder="{integer}">
<settings>
<label translate="true">{Label File Uploader}</label>
</settings>
<formElements>
<fileUploader>
<settings>
<uploaderConfig>
<param xsi:type="string" name="url">{router_id}/{controller_folder}/{controller_name}</param>
</uploaderConfig>
</settings>
</fileUploader>
</formElements>
</field>
HtmlContent
O componente HtmlContent fornece a capacidade de processar e renderizar uma estrutura de layout ou um bloco diretamente dentro de uma configuração de componente do UI. O processamento e a renderização são executados no lado do servidor.
A estrutura de layout dentro de HtmlContent deve conter apenas um bloco de nível superior. O bloco de nível superior pode conter quantos blocos filhos ou contêineres forem necessários. Todos os blocos dentro de HtmlContent são integrados ao layout, então os blocos externos podem se referir a eles e vice-versa.
<htmlContent name="{html_component_name}">
<block class="{Vendor}\{Module}\Block\Adminhtml\{Directory}\{ClassName}" name="{block_name}" template="{Vendor_Module}::{directory}/{file}.phtml">
<arguments>
<argument name="{argument_name}" xsi:type="{type}">{value}</argument>
</arguments>
<block class="{Vendor}\{Module}\Block\Adminhtml\{Directory}\{ClassName}" name="{block_name}" template="{Vendor_Module}::{directory}/{file}.phtml" />
</block>
</htmlContent>
Botão do Menu
Esta classe é responsável por configurar o botão que ficará no menu, para isso está classe deve implementar a interface \Magento\Framework\View\Element\UiComponent\Control\ButtonProviderInterface
e implementar o método getButtonData(): array
, retornando array com as configurações do botão.
<?php
namespace {Vendor}\{Module}\Block\Adminhtml\{Directory};
use Magento\Framework\View\Element\UiComponent\Control\ButtonProviderInterface;
use Magento\Framework\UrlInterface;
class {ButtonClassName} implements ButtonProviderInterface
{
public function __construct(
private UrlInterface $urlBuilder
) {
}
public function getUrl(string $route = '', array $params = []): string
{
return $this->urlBuilder->getUrl($route, $params);
}
public function getButtonData(): array
{
return [
'label' => __('{Label Button}'),
'on_click' => sprintf("location.href = '%s';", $this->getUrl('{router_id}/{controller_directory}/{controller_name}')),
'class' => '{class_name}',
'sort_order' => {integer}
];
}
}
Finalizando
Valores entre chaves (
{test}
) devem ser alterados na implementação do código.
Habilitando as alterações
Apague os arquivos que são gerados na compilação do Magento e execute o comando PHP para gerar a configuração das injeções de dependência e todas as classes ausentes que precisam ser geradas (proxys, interceptors, etc) e para limpar todos os caches de armazenamento em cache do processos.
rm -rf var/generation/
rm -rf generated/
php bin/magento setup:di:compile
php bin/magento cache:clean
php bin/magento flush
Diretórios e Arquivos
Segue a a lista de diretórios e arquivos que devem ser criados.
- app/
- code/
- {Vendor}/
- {Module}/
- Block/
- Adminhtml/
- {ClassName}.php
- etc/
- di.xml
- module.xml
- Ui/
- Component/
- {EntityName}/
- FormDataProvider.php
- view/
- adminhtml/
- layout/
- {router_id}_{controller_directory}_{controller_name}.xml
- ui_component/
- {ui_component}.xml
- registration.php
- composer.json