This post will provide a simple, easy to follow step-by-step guide on how to add a form in Magento 2, using the UI component functionality. This will also follow on from the Step by Step Guide to Adding a Grid.
Presumptions
developer
mode.app/code/[Vendor]/[Module]
. Please also take note of when to use lowercase and uppercase.app/code/[Vendor]/[Module]/etc/di.xml
are references to where the files should be created/edited. The line does not need to reside within the files themselves.Steps
1. Create an Add.php
controller which will forward it the edit action.
// app/code/[Vendor]/[Module]/Controller/Adminhtml/Entity/Add.php
<?php
namespace [Vendor]\[Module]\Controller\Adminhtml\Entity;
use [Vendor]\[Module]\Controller\Adminhtml\Entity;
class Add extends Entity
{
/**
* Forward to edit
*/
public function execute()
{
$resultForward = $this->resultForwardFactory->create();
return $resultForward->forward('edit');
}
}
2. Create the Edit.php
class.
// app/code/[Vendor]/[Module]/Controller/Adminhtml/Entity/Edit.php
<?php
namespace [Vendor]\[Module]\Controller\Adminhtml\Entity;
use [Vendor]\[Module]\Controller\Adminhtml\Entity;
class Edit extends Entity
{
/**
* @return \Magento\Framework\View\Result\Page
*/
public function execute()
{
$entityId = $this->getRequest()->getParam('entity_id');
$resultPage = $this->resultPageFactory->create();
$resultPage->setActiveMenu('[Vendor]_[Module]::entity')
->addBreadcrumb(__('Entity'), __('Entity'))
->addBreadcrumb(__('Manage Entity'), __('Manage Entity'));
if ($entityId === null) {
$resultPage->addBreadcrumb(__('New Entity'), __('New Entity'));
$resultPage->getConfig()->getTitle()->prepend(__('New Entity'));
} else {
$resultPage->addBreadcrumb(__('Edit Entity'), __('Edit Entity'));
$resultPage->getConfig()->getTitle()->prepend(
$this->entityRepository->getById($entityId)->getName()
);
}
return $resultPage;
}
}
3. Modify the parent Entity.php
controller class and add in the $entityRepository
as a dependency.
// app/code/[Vendor]/[Module]/Controller/Adminhtml/Entity.php
<?php
namespace [Vendor]\[Module]\Controller\Adminhtml;
use Magento\Backend\App\Action;
use Magento\Backend\App\Action\Context;
use Magento\Framework\Registry;
use Magento\Framework\View\Result\PageFactory;
use Magento\Backend\Model\View\Result\ForwardFactory;
use [Vendor]\[Module]\Api\EntityRepositoryInterface;
abstract class Entity extends Action
{
/**
* Authorization level of a basic admin session
*
* @see _isAllowed()
*/
const ACTION_RESOURCE = '[Vendor]_[Module]::entity';
/**
* Core registry
*
* @var Registry
*/
protected $coreRegistry;
/**
* Result Page Factory
*
* @var PageFactory
*/
protected $resultPageFactory;
/**
* Result Forward Factory
*
* @var ForwardFactory
*/
protected $resultForwardFactory;
/**
* Entity Repository Interface
*
* @var EntityRepositoryInterface
*/
protected $entityRepository;
/**
* Entity constructor.
*
* @param Registry $registry
* @param PageFactory $resultPageFactory
* @param ForwardFactory $resultForwardFactory
* @param EntityRepositoryInterface $entityRepository
* @param Context $context
*/
public function __construct(
Registry $registry,
PageFactory $resultPageFactory,
ForwardFactory $resultForwardFactory,
EntityRepositoryInterface $entityRepository,
Context $context
) {
$this->coreRegistry = $registry;
$this->resultPageFactory = $resultPageFactory;
$this->resultForwardFactory = $resultForwardFactory;
$this->entityRepository = $entityRepository;
parent::__construct($context);
}
}
3. Add the adminhtml layout file for the edit action to include the UI component.
// app/code/[Vendor]/[Module]/view/adminhtml/layout/[module]_entity_edit.xml
<?xml version="1.0"?>
<page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd">
<body>
<referenceContainer name="content">
<uiComponent name="[module]_entity_form" />
</referenceContainer>
</body>
</page>
4. Add the form UI component.
// app/code/[Vendor]/[Module]/view/adminhtml/ui_component/[vendor]_entity_form.xml
<?xml version="1.0" encoding="UTF-8"?>
<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">[module]_entity_form.[vendor]_entity_form_data_source</item>
<item name="deps" xsi:type="string">[module]_entity_form.[vendor]_entity_form_data_source</item>
</item>
<item name="label" xsi:type="string" translate="true">Entity Information</item>
<item name="config" xsi:type="array">
<item name="dataScope" xsi:type="string">data</item>
<item name="namespace" xsi:type="string">[module]_form</item>
</item>
<item name="template" xsi:type="string">templates/form/collapsible</item>
<item name="buttons" xsi:type="array">
<item name="back" xsi:type="string">[Vendor]\[Module]\Block\Adminhtml\Entity\Edit\BackButton</item>
<item name="delete" xsi:type="string">[Vendor]\[Module]\Block\Adminhtml\Entity\Edit\DeleteButton</item>
<item name="reset" xsi:type="string">[Vendor]\[Module]\Block\Adminhtml\Entity\Edit\ResetButton</item>
<item name="save" xsi:type="string">[Vendor]\[Module]\Block\Adminhtml\Entity\Edit\SaveButton</item>
<item name="save_and_continue" xsi:type="string">[Vendor]\[Module]\Block\Adminhtml\Entity\Edit\SaveAndContinueButton</item>
</item>
</argument>
<dataSource name="[module]_entity_form_data_source">
<argument name="dataProvider" xsi:type="configurableObject">
<argument name="class" xsi:type="string">[Vendor]\[Module]\Model\DataProvider</argument>
<argument name="name" xsi:type="string">[module]_entity_form_data_source</argument>
<argument name="primaryFieldName" xsi:type="string">entity_id</argument>
<argument name="requestFieldName" xsi:type="string">entity_id</argument>
<argument name="data" xsi:type="array">
<item name="config" xsi:type="array">
<item name="submit_url" xsi:type="url" path="[module]/entity/save"/>
</item>
</argument>
</argument>
<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>
</dataSource>
<fieldset name="entity_details">
<argument name="data" xsi:type="array">
<item name="config" xsi:type="array">
<item name="label" xsi:type="string" translate="true">Entity Details</item>
</item>
</argument>
<field name="entity_id">
<argument name="data" xsi:type="array">
<item name="config" xsi:type="array">
<item name="visible" xsi:type="boolean">false</item>
<item name="dataType" xsi:type="string">text</item>
<item name="label" xsi:type="string" translate="true">Entity ID</item>
<item name="formElement" xsi:type="string">input</item>
<item name="source" xsi:type="string">data</item>
<item name="dataScope" xsi:type="string">entity_id</item>
</item>
</argument>
</field>
<field name="name">
<argument name="data" xsi:type="array">
<item name="config" xsi:type="array">
<item name="dataType" xsi:type="string">text</item>
<item name="label" xsi:type="string" translate="true">Name</item>
<item name="formElement" xsi:type="string">input</item>
<item name="source" xsi:type="string">data</item>
<item name="dataScope" xsi:type="string">name</item>
</item>
</argument>
</field>
<field name="description">
<argument name="data" xsi:type="array">
<item name="config" xsi:type="array">
<item name="formElement" xsi:type="string">wysiwyg</item>
<item name="source" xsi:type="string">data</item>
<item name="label" xsi:type="string" translate="true">Description</item>
<item name="dataScope" xsi:type="string">description</item>
<item name="validation" xsi:type="array">
<item name="required-entry" xsi:type="boolean">true</item>
</item>
</item>
</argument>
</field>
<field name="is_active">
<argument name="data" xsi:type="array">
<item name="config" xsi:type="array">
<item name="dataType" xsi:type="string">boolean</item>
<item name="label" xsi:type="string" translate="true">Enabled</item>
<item name="formElement" xsi:type="string">checkbox</item>
<item name="source" xsi:type="string">block</item>
<item name="dataScope" xsi:type="string">is_active</item>
<item name="prefer" xsi:type="string">toggle</item>
<item name="valueMap" xsi:type="array">
<item name="true" xsi:type="number">1</item>
<item name="false" xsi:type="number">0</item>
</item>
<item name="default" xsi:type="number">1</item>
</item>
</argument>
</field>
</fieldset>
<form>
5. Create the button block classes.
// app/code/[Vendor]/[Module]/Block/Adminhtml/Entity/Edit/Generic.php
<?php
namespace [Vendor]\[Module]\Block\Adminhtml\Entity\Edit;
use Magento\Backend\Block\Widget\Context;
use Magento\Framework\Exception\NoSuchEntityException;
use [Vendor]\[Module]\Api\EntityRepositoryInterface;
class Generic
{
/**
* @var Context
*/
protected $context;
/**
* @var EntityRepositoryInterface
*/
protected $entityRepository;
/**
* Generic constructor.
*
* @param Context $context
* @param EntityRepositoryInterface $entityRepository
*/
public function __construct(
Context $context,
EntityRepositoryInterface $entityRepository
) {
$this->context = $context;
$this->entityRepository = $entityRepository;
}
/**
* Return Entity ID
*
* @return int|null
*/
public function getEntityId()
{
try {
return $this->entityRepository->getById(
$this->context->getRequest()->getParam('entity_id')
)->getId();
} catch (NoSuchEntityException $e) {
return null;
}
}
/**
* Generate url by route and parameters
*
* @param string $route
* @param array $params
* @return string
*/
public function getUrl($route = '', $params = [])
{
return $this->context->getUrlBuilder()->getUrl($route, $params);
}
}
// app/code/[Vendor]/[Module]/Block/Adminhtml/Entity/Edit/BackButton.php
<?php
namespace [Vendor]\[Module]\Block\Adminhtml\Entity\Edit;
use Magento\Framework\View\Element\UiComponent\Control\ButtonProviderInterface;
class BackButton extends Generic implements ButtonProviderInterface
{
/**
* Get button data
*
* @return array
*/
public function getButtonData()
{
return [
'label' => __('Back'),
'on_click' => sprintf("location.href = '%s';", $this->getBackUrl()),
'class' => 'back',
'sort_order' => 10
];
}
/**
* Get URL for back (reset) button
*
* @return string
*/
public function getBackUrl()
{
return $this->getUrl('*/*/');
}
}
// app/code/[Vendor]/[Module]/Block/Adminhtml/Entity/Edit/DeleteButton.php
<?php
namespace [Vendor]\[Module]\Block\Adminhtml\Entity\Edit;
use Magento\Framework\View\Element\UiComponent\Control\ButtonProviderInterface;
class DeleteButton extends Generic implements ButtonProviderInterface
{
/**
* Get button data
*
* @return array
*/
public function getButtonData()
{
$data = [];
if ($this->getEntityId()) {
$data = [
'label' => __('Delete Entity'),
'class' => 'delete',
'on_click' => 'deleteConfirm(\'' . __(
'Are you sure you want to do this?'
) . '\', \'' . $this->getDeleteUrl() . '\')',
'sort_order' => 20,
];
}
return $data;
}
/**
* @return string
*/
public function getDeleteUrl()
{
return $this->getUrl('*/*/delete', ['entity_id' => $this->getEntityId()]);
}
}
// app/code/[Vendor]/[Module]/Block/Adminhtml/Entity/Edit/ResetButton.php
<?php
namespace [Vendor]\[Module]\Block\Adminhtml\Entity\Edit;
use Magento\Framework\View\Element\UiComponent\Control\ButtonProviderInterface;
class ResetButton implements ButtonProviderInterface
{
/**
* Get button data
*
* @return array
*/
public function getButtonData()
{
return [
'label' => __('Reset'),
'class' => 'reset',
'on_click' => 'location.reload();',
'sort_order' => 30
];
}
}
// app/code/[Vendor]/[Module]/Block/Adminhtml/Entity/Edit/SaveButton.php
<?php
namespace [Vendor]\[Module]\Block\Adminhtml\Entity\Edit;
use Magento\Framework\View\Element\UiComponent\Control\ButtonProviderInterface;
class SaveButton implements ButtonProviderInterface
{
/**
* Get button data
*
* @return array
*/
public function getButtonData()
{
return [
'label' => __('Save Entity'),
'class' => 'save primary',
'data_attribute' => [
'mage-init' => ['button' => ['event' => 'save']],
'form-role' => 'save',
],
'sort_order' => 90,
];
}
}
// app/code/[Vendor]/[Module]/Block/Adminhtml/Entity/Edit/SaveAndContinueButton.php
<?php
namespace [Vendor]\[Module]\Block\Adminhtml\Entity\Edit;
use Magento\Framework\View\Element\UiComponent\Control\ButtonProviderInterface;
class SaveAndContinueButton implements ButtonProviderInterface
{
/**
* Get button data
*
* @return array
*/
public function getButtonData()
{
return [
'label' => __('Save and Continue Edit'),
'class' => 'save',
'data_attribute' => [
'mage-init' => [
'button' => ['event' => 'saveAndContinueEdit'],
],
],
'sort_order' => 80,
];
}
}
6. Add the DataProvider
class.
// app/code/[Vendor]/[Module]/Model/DataProvider.php
<?php
namespace [Vendor]\[Module]\Model;
use Magento\Ui\DataProvider\AbstractDataProvider;
use Magento\Ui\DataProvider\Modifier\ModifierInterface;
use Magento\Ui\DataProvider\Modifier\PoolInterface;
use [Vendor]\[Module]\Model\ResourceModel\Entity\CollectionFactory;
class DataProvider extends AbstractDataProvider
{
/**
* @var PoolInterface
*/
protected $pool;
/**
* @param string $name
* @param string $primaryFieldName
* @param string $requestFieldName
* @param CollectionFactory $entityCollectionFactory
* @param PoolInterface $pool
* @param array $meta
* @param array $data
*/
public function __construct(
$name,
$primaryFieldName,
$requestFieldName,
CollectionFactory $entityCollectionFactory,
PoolInterface $pool,
array $meta = [],
array $data = []
) {
$this->collection = $entityCollectionFactory->create();
$this->pool = $pool;
parent::__construct($name, $primaryFieldName, $requestFieldName, $meta, $data);
$this->meta = $this->prepareMeta($this->meta);
}
/**
* Prepares Meta
*
* @param array $meta
* @return array
*/
public function prepareMeta(array $meta)
{
return $meta;
}
/**
* Get data
*
* @return array
*/
/**
* Get data
*
* @return array
*/
public function getData()
{
if (isset($this->loadedData)) {
return $this->loadedData;
}
$items = $this->collection->getItems();
foreach ($items as $page) {
$this->loadedData[$page->getId()] = $page->getData();
}
$data = $this->dataPersistor->get('module_messages');
if (!empty($data)) {
$page = $this->collection->getNewEmptyItem();
$page->setData($data);
$this->loadedData[$page->getId()] = $page->getData();
$this->dataPersistor->clear('module_messages');
}
return $this->loadedData;
}
}
7. Within the di.xml
(note you can create another one in the adminhtml directory), add the $modifiers
arguments.
// app/code/[Vendor]/[Module]/etc/adminhtml/di.xml
<?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="[Vendor][Module]UiDataProviderEntityFormModifierPool" type="Magento\Ui\DataProvider\Modifier\Pool">
<arguments>
<argument name="modifiers" xsi:type="array">
<item name="entity_data" xsi:type="array">
<item name="class" xsi:type="string">[Vendor]\[Module]\Ui\DataProvider\Entity\Form\Modifier\EntityData</item>
<item name="sortOrder" xsi:type="number">10</item>
</item>
</argument>
</arguments>
</virtualType>
<type name="[Vendor]\[Module]\Model\DataProvider">
<arguments>
<argument name="pool" xsi:type="object">[Vendor][Module]UiDataProviderEntityFormModifierPool</argument>
</arguments>
</type>
</config>
8. Add the modifier class.
// app/code/[Vendor]/[Module]/Ui/DataProvider/Entity/Form/Modifier/EntityData.php
<?php
namespace [Vendor]\[Module]\Ui\DataProvider\Entity\Form\Modifier;
use Magento\Ui\DataProvider\Modifier\ModifierInterface;
use [Vendor]\[Module]\Model\ResourceModel\Entity\CollectionFactory;
class EntityData implements ModifierInterface
{
/**
* @var \[Vendor]\[Module]\Model\ResourceModel\Entity\Collection
*/
protected $collection;
/**
* @param CollectionFactory $entityCollectionFactory
*/
public function __construct(
CollectionFactory $entityCollectionFactory
) {
$this->collection = $entityCollectionFactory->create();
}
/**
* @param array $meta
* @return array
*/
public function modifyMeta(array $meta)
{
return $meta;
}
/**
* @param array $data
* @return array
*/
public function modifyData(array $data)
{
$items = $this->collection->getItems();
/** @var $entity \[Vendor]\[Module]\Model\Entity */
foreach ($items as $entity) {
$_data = $entity->getData();
$entity->setData($_data);
$data[$entity->getId()] = $_data;
}
return $data;
}
}
If you’ve made it this far, your form will successfully load!
9. Add a Save.php
controller class so that the form data can be saved.
// app/code/[Vendor]/[Module]/Controller/Adminhtml/Entity/Save.php
<?php
namespace [Vendor]\[Module]\Controller\Adminhtml\Entity;
use Magento\Framework\Registry;
use Magento\Framework\View\Result\PageFactory;
use Magento\Backend\Model\View\Result\ForwardFactory;
use Magento\Backend\App\Action\Context;
use Magento\Framework\Message\Manager;
use Magento\Framework\Api\DataObjectHelper;
use [Vendor]\[Module]\Api\EntityRepositoryInterface;
use [Vendor]\[Module]\Api\Data\EntityInterface;
use [Vendor]\[Module]\Api\Data\EntityInterfaceFactory;
use [Vendor]\[Module]\Controller\Adminhtml\Entity;
class Save extends Entity
{
/**
* @var Manager
*/
protected $messageManager;
/**
* @var EntityRepositoryInterface
*/
protected $entityRepository;
/**
* @var EntityInterfaceFactory
*/
protected $entityFactory;
/**
* @var DataObjectHelper
*/
protected $dataObjectHelper;
/**
* Save constructor.
*
* @param Registry $registry
* @param EntityRepositoryInterface $entityRepository
* @param PageFactory $resultPageFactory
* @param ForwardFactory $resultForwardFactory
* @param Manager $messageManager
* @param EntityInterfaceFactory $entityFactory
* @param DataObjectHelper $dataObjectHelper
* @param Context $context
*/
public function __construct(
Registry $registry,
EntityRepositoryInterface $entityRepository,
PageFactory $resultPageFactory,
ForwardFactory $resultForwardFactory,
Manager $messageManager,
EntityInterfaceFactory $entityFactory,
DataObjectHelper $dataObjectHelper,
Context $context
) {
parent::__construct($registry, $resultPageFactory, $resultForwardFactory, $entityRepository, $context);
$this->messageManager = $messageManager;
$this->entityFactory = $entityFactory;
$this->entityRepository = $entityRepository;
$this->dataObjectHelper = $dataObjectHelper;
}
/**
* Save action
*
* @return \Magento\Framework\Controller\ResultInterface
*/
public function execute()
{
$data = $this->getRequest()->getPostValue();
$resultRedirect = $this->resultRedirectFactory->create();
if ($data) {
$id = $this->getRequest()->getParam('entity_id');
if ($id) {
$model = $this->entityRepository->getById($id);
} else {
unset($data['entity_id']);
$model = $this->entityFactory->create();
}
try {
$this->dataObjectHelper->populateWithArray($model, $data, EntityInterface::class);
$this->entityRepository->save($model);
$this->messageManager->addSuccessMessage(__('You saved this data.'));
$this->_getSession()->setFormData(false);
if ($this->getRequest()->getParam('back')) {
return $resultRedirect->setPath('*/*/edit', ['entity_id' => $model->getId(), '_current' => true]);
}
return $resultRedirect->setPath('*/*/');
} catch (\Magento\Framework\Exception\LocalizedException $e) {
$this->messageManager->addErrorMessage($e->getMessage());
} catch (\RuntimeException $e) {
$this->messageManager->addErrorMessage($e->getMessage());
} catch (\Exception $e) {
$this->messageManager->addException($e, __('Something went wrong while saving the entity.'));
}
$this->_getSession()->setFormData($data);
return $resultRedirect->setPath('*/*/edit', [
'entity_id' => $this->getRequest()->getParam('entity_id')
]);
}
return $resultRedirect->setPath('*/*/');
}
}
10. Modify the [module]_entity_grid.xml
file and add in <actionsColumn>
configuration.
// app/code/[Vendor]/[Module]/view/adminhtml/layout/[module]_entity_grid.xml
<?xml version="1.0" encoding="UTF-8"?>
<listing xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Ui:etc/ui_configuration.xsd">
....
<columns>
....
<actionsColumn name="actions" class="[Vendor]\[Module]\Ui\Component\Listing\Column\EntityActions">
<argument name="data" xsi:type="array">
<item name="config" xsi:type="array">
<item name="indexField" xsi:type="string">entity_id</item>
<item name="urlEntityParamName" xsi:type="string">entity_id</item>
</item>
</argument>
</actionsColumn>
</columns>
</listing>
11. Add the EntityActions.php
class.
// app/code/[Vendor]/[Module]/Ui/Component/Listing/Column/EntityActions.php
<?php
namespace [Vendor]\[Module]\Ui\Component\Listing\Column;
use Magento\Framework\View\Element\UiComponent\ContextInterface;
use Magento\Framework\View\Element\UiComponentFactory;
use Magento\Ui\Component\Listing\Columns\Column;
use Magento\Framework\UrlInterface;
class EntityActions extends Column
{
const URL_PATH_EDIT = '[module]/entity/edit';
const URL_PATH_DELETE = '[module]/entity/delete';
/**
* URL builder
*
* @var \Magento\Framework\UrlInterface
*/
protected $urlBuilder;
/**
* @param ContextInterface $context
* @param UiComponentFactory $uiComponentFactory
* @param UrlInterface $urlBuilder
* @param array $components
* @param array $data
*/
public function __construct(
ContextInterface $context,
UiComponentFactory $uiComponentFactory,
UrlInterface $urlBuilder,
array $components = [],
array $data = []
) {
parent::__construct($context, $uiComponentFactory, $components, $data);
$this->urlBuilder = $urlBuilder;
}
/**
* Prepare Data Source
*
* @param array $dataSource
* @return array
*/
public function prepareDataSource(array $dataSource)
{
if (isset($dataSource['data']['items'])) {
foreach ($dataSource['data']['items'] as & $item) {
if (isset($item['entity_id'])) {
$item[$this->getData('name')] = [
'edit' => [
'href' => $this->urlBuilder->getUrl(
static::URL_PATH_EDIT,
[
'entity_id' => $item['entity_id']
]
),
'label' => __('Edit')
],
'delete' => [
'href' => $this->urlBuilder->getUrl(
static::URL_PATH_DELETE,
[
'entity_id' => $item['entity_id']
]
),
'label' => __('Delete'),
'confirm' => [
'title' => __('Delete "${ $.$data.name }"'),
'message' => __('Are you sure you want to delete the Entity: "${ $.$data.name }"?')
]
]
];
}
}
}
return $dataSource;
}
}
12. Add the Delete.php
controller.
// app/code/[Vendor]/[Module]/Controller/Adminhtml/Entity/Delete.php
<?php
namespace [Vendor]\[Module]\Controller\Adminhtml\Entity;
use Magento\Framework\Exception\LocalizedException;
use Magento\Framework\Exception\NoSuchEntityException;
use [Vendor]\[Module]\Controller\Adminhtml\Entity;
class Delete extends Entity
{
/**
* @return \Magento\Framework\Controller\Result\Redirect
*/
public function execute()
{
$resultRedirect = $this->resultRedirectFactory->create();
$entityId = $this->getRequest()->getParam('entity_id');
if ($entityId) {
try {
$this->entityRepository->deleteById($entityId);
$this->messageManager->addSuccessMessage(__('The entity has been deleted.'));
$resultRedirect->setPath('[module]/entity/index');
return $resultRedirect;
} catch (NoSuchEntityException $e) {
$this->messageManager->addErrorMessage(__('The entity no longer exists.'));
return $resultRedirect->setPath('[module]/entity/index');
} catch (LocalizedException $e) {
$this->messageManager->addErrorMessage($e->getMessage());
return $resultRedirect->setPath('[module]/entity/index', ['entity_id' => $entityId]);
} catch (\Exception $e) {
$this->messageManager->addErrorMessage(__('There was a problem deleting the data'));
return $resultRedirect->setPath('[module]/entity/edit', ['entity_id' => $entityId]);
}
}
$this->messageManager->addErrorMessage(__('We can\'t find the entity to delete.'));
$resultRedirect->setPath('[module]/entity/index');
return $resultRedirect;
}
}
13. Modify the [module]_entity_grid.xml
file to include a mass actions dropdown.
// app/code/[Vendor]/[Module]/view/adminhtml/ui_component/[module]_entity_grid.xml
<?xml version="1.0" encoding="UTF-8"?>
<listing xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Ui:etc/ui_configuration.xsd">
....
<container name="listing_top">
....
<massaction name="listing_massaction">
<argument name="data" xsi:type="array">
<item name="config" xsi:type="array">
<item name="selectProvider" xsi:type="string">[module]_entity_grid.[module]_entity_grid.[module]_entity_grid_columns.ids</item>
<item name="indexField" xsi:type="string">entity_id</item>
</item>
</argument>
<action name="delete">
<argument name="data" xsi:type="array">
<item name="config" xsi:type="array">
<item name="type" xsi:type="string">delete</item>
<item name="label" xsi:type="string" translate="true">Delete</item>
<item name="url" xsi:type="url" path="[module]/entity/massDelete"/>
<item name="confirm" xsi:type="array">
<item name="title" xsi:type="string" translate="true">Delete items</item>
<item name="message" xsi:type="string" translate="true">Are you sure you want to delete selected items?</item>
</item>
</item>
</argument>
</action>
<action name="disable">
<argument name="data" xsi:type="array">
<item name="config" xsi:type="array">
<item name="type" xsi:type="string">disable</item>
<item name="label" xsi:type="string" translate="true">Disable</item>
<item name="url" xsi:type="url" path="[module]/entity/massDisable"/>
</item>
</argument>
</action>
<action name="enable">
<argument name="data" xsi:type="array">
<item name="config" xsi:type="array">
<item name="type" xsi:type="string">enable</item>
<item name="label" xsi:type="string" translate="true">Enable</item>
<item name="url" xsi:type="url" path="[module]/entity/massEnable"/>
</item>
</argument>
</action>
</massaction>
</container>
....
</listing>
14. Add the mass action related classes.
// app/code/[Vendor]/[Module]/Controller/Adminhtml/Entity/MassAction.php
<?php
namespace [Vendor]\[Module]\Controller\Adminhtml\Entity;
use Magento\Backend\App\Action\Context;
use Magento\Framework\Exception\LocalizedException;
use Magento\Framework\Registry;
use Magento\Framework\View\Result\PageFactory;
use Magento\Backend\Model\View\Result\ForwardFactory;
use Magento\Ui\Component\MassAction\Filter;
use [Vendor]\[Module]\Api\EntityRepositoryInterface;
use [Vendor]\[Module]\Controller\Adminhtml\Entity;
use [Vendor]\[Module]\Model\Entity as EntityModel;
use [Vendor]\[Module]\Model\ResourceModel\Entity\CollectionFactory;
abstract class MassAction extends Entity
{
/**
* @var Filter
*/
protected $filter;
/**
* @var CollectionFactory
*/
protected $collectionFactory;
/**
* @var EntityRepositoryInterface
*/
protected $entityRepository;
/**
* @var ForwardFactory
*/
protected $resultForwardFactory;
/**
* @var string
*/
protected $successMessage;
/**
* @var string
*/
protected $errorMessage;
/**
* MassAction constructor.
*
* @param Filter $filter
* @param Registry $registry
* @param EntityRepositoryInterface $entityRepository
* @param PageFactory $resultPageFactory
* @param Context $context
* @param CollectionFactory $collectionFactory
* @param ForwardFactory $resultForwardFactory
* @param $successMessage
* @param $errorMessage
*/
public function __construct(
Filter $filter,
Registry $registry,
EntityRepositoryInterface $entityRepository,
PageFactory $resultPageFactory,
Context $context,
CollectionFactory $collectionFactory,
ForwardFactory $resultForwardFactory,
$successMessage,
$errorMessage
) {
parent::__construct($registry, $resultPageFactory, $resultForwardFactory, $entityRepository, $context);
$this->filter = $filter;
$this->entityRepository = $entityRepository;
$this->collectionFactory = $collectionFactory;
$this->resultForwardFactory = $resultForwardFactory;
$this->successMessage = $successMessage;
$this->errorMessage = $errorMessage;
}
/**
* @param EntityModel $entity
* @return mixed
*/
abstract protected function massAction(EntityModel $entity);
/**
* @return \Magento\Framework\Controller\Result\Redirect
*/
public function execute()
{
try {
$collection = $this->filter->getCollection($this->collectionFactory->create());
$collectionSize = $collection->getSize();
foreach ($collection as $entity) {
$this->massAction($entity);
}
$this->messageManager->addSuccessMessage(__($this->successMessage, $collectionSize));
} catch (LocalizedException $e) {
$this->messageManager->addErrorMessage($e->getMessage());
} catch (\Exception $e) {
$this->messageManager->addExceptionMessage($e, __($this->errorMessage));
}
$redirectResult = $this->resultRedirectFactory->create();
$redirectResult->setPath('[module]/entity/index');
return $redirectResult;
}
}
// app/code/[Vendor]/[Module]/Controller/Adminhtml/Entity/MassEnable.php
<?php
namespace [Vendor]\[Module]\Controller\Adminhtml\Entity;
use [Vendor]\[Module]\Model\Entity;
class MassEnable extends MassAction
{
/**
* @param Entity $entity
* @return $this
*/
protected function massAction(Entity $entity)
{
$entity->setIsActive(true);
$this->entityRepository->save($entity);
return $this;
}
}
// app/code/[Vendor]/[Module]/Controller/Adminhtml/Entity/MassEnable.php
<?php
namespace [Vendor]\[Module]\Controller\Adminhtml\Entity;
use [Vendor]\[Module]\Model\Entity;
class MassDisable extends MassAction
{
/**
* @param Entity $entity
* @return $this
*/
protected function massAction(Entity $entity)
{
$entity->setIsActive(false);
$this->entityRepository->save($entity);
return $this;
}
}
// app/code/[Vendor]/[Module]/Controller/Adminhtml/Entity/MassDelete.php
<?php
namespace [Vendor]\[Module]\Controller\Adminhtml\Entity;
use [Vendor]\[Module]\Model\Entity;
class MassDelete extends MassAction
{
/**
* @param Entity $entity
* @return $this
*/
protected function massAction(Entity $entity)
{
$this->entityRepository->delete($entity);
return $this;
}
}
15. Add the success and error messages for the mass actions within di.xml
.
// app/code/[Vendor]/[Module]/etc/adminhtml/di.xml
<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
....
<type name="[Vendor]\[Module]\Controller\Adminhtml\Entity\MassDelete">
<arguments>
<argument name="successMessage" xsi:type="string" translate="true">A total of %1 record(s) have been deleted.</argument>
<argument name="errorMessage" xsi:type="string" translate="true">An error occurred while deleting record(s).</argument>
</arguments>
</type>
<type name="[Vendor]\[Module]\Controller\Adminhtml\Entity\MassDisable">
<arguments>
<argument name="successMessage" xsi:type="string" translate="true">A total of %1 record(s) have been disabled.</argument>
<argument name="errorMessage" xsi:type="string" translate="true">An error occurred while disabling selected record(s).</argument>
</arguments>
</type>
<type name="[Vendor]\[Module]\Controller\Adminhtml\Entity\MassEnable">
<arguments>
<argument name="successMessage" xsi:type="string" translate="true">A total of %1 record(s) have been enabled.</argument>
<argument name="errorMessage" xsi:type="string" translate="true">An error occurred while enabling record(s).</argument>
</arguments>
</type>
</config>
Enjoy your new Grid and Form UI Components!
Note: This article is based on Magento Open Source version 2.1.9.