Admin Grid CRUD In Magento 2
In the previous article, I introduced How To Add Mass Actions In Magento 2. In this article, we will learn about Admin Grid CRUD In Magento 2.
This is a series on Magento 2 Extension Tutorial. The lessons are related to each other so you should read step by step.
Module File Structure
We updated our module file structure looks as follows:
Create Edit Form
First, You create Edit.php in the Block folder following the path: Magetop/Helloworld/Block/Adminhtml/Posts/Edit.php
<?php
namespace Magetop\Helloworld\Block\Adminhtml\Posts;
use Magento\Backend\Block\Widget\Form\Container;
use Magento\Backend\Block\Widget\Context;
use Magento\Framework\Registry;
class Edit extends Container
{
/**
* Core registry
*
* @var \Magento\Framework\Registry
*/
protected $_coreRegistry = null;
/**
* @param Context $context
* @param Registry $registry
* @param array $data
*/
public function __construct(
Context $context,
Registry $registry,
array $data = []
) {
$this->_coreRegistry = $registry;
parent::__construct($context, $data);
}
/**
* Class constructor
*
* @return void
*/
protected function _construct()
{
$this->_objectId = 'id';
$this->_controller = 'adminhtml_posts';
$this->_blockGroup = 'Magetop_Helloworld';
parent::_construct();
$this->buttonList->update('save', 'label', __('Save'));
$this->buttonList->add(
'saveandcontinue',
[
'label' => __('Save and Continue Edit'),
'class' => 'save',
'data_attribute' => [
'mage-init' => [
'button' => [
'event' => 'saveAndContinueEdit',
'target' => '#edit_form'
]
]
]
],
-100
);
$this->buttonList->update('delete', 'label', __('Delete'));
}
/**
* Retrieve text for header element depending on loaded news
*
* @return string
*/
public function getHeaderText()
{
$posts = $this->_coreRegistry->registry('magetop_blog');
if ($posts->getId()) {
$postsTitle = $this->escapeHtml($posts->getTitle());
return __("Edit News '%1'", $postsTitle);
} else {
return __('Add News');
}
}
/**
* Prepare layout
*
* @return \Magento\Framework\View\Element\AbstractBlock
*/
protected function _prepareLayout()
{
$this->_formScripts[] = "
function toggleEditor() {
if (tinyMCE.getInstanceById('post_content') == null) {
tinyMCE.execCommand('mceAddControl', false, 'post_content');
} else {
tinyMCE.execCommand('mceRemoveControl', false, 'post_content');
}
};
";
return parent::_prepareLayout();
}
}
Next, create file Magetop/Helloworld/Block/Adminhtml/Posts/Edit/Tabs.php
<?php
namespace Magetop\Helloworld\Block\Adminhtml\Posts\Edit;
use Magento\Backend\Block\Widget\Tabs as WidgetTabs;
class Tabs extends WidgetTabs
{
/**
* Class constructor
*
* @return void
*/
protected function _construct()
{
parent::_construct();
$this->setId('post_edit_tabs');
$this->setDestElementId('edit_form');
$this->setTitle(__('Post Information'));
}
/**
* @return $this
*/
protected function _beforeToHtml()
{
$this->addTab(
'post_info',
[
'label' => __('General'),
'title' => __('General'),
'content' => $this->getLayout()->createBlock(
'Magetop\Helloworld\Block\Adminhtml\Posts\Edit\Tab\Info'
)->toHtml(),
'active' => true
]
);
return parent::_beforeToHtml();
}
}
You create file Magetop/Helloworld/Block/Adminhtml/Posts/Edit/Form.php
<?php
namespace Magetop\Helloworld\Block\Adminhtml\Posts\Edit;
use Magento\Backend\Block\Widget\Form\Generic;
class Form extends Generic
{
/**
* @return $this
*/
protected function _prepareForm()
{
/** @var \Magento\Framework\Data\Form $form */
$form = $this->_formFactory->create(
[
'data' => [
'id' => 'edit_form',
'action' => $this->getData('action'),
'method' => 'post',
'enctype' => 'multipart/form-data'
]
]
);
$form->setUseContainer(true);
$this->setForm($form);
return parent::_prepareForm();
}
}
Then, you create Info.php according to the path: Magetop/Helloworld/Block/Adminhtml/Posts/Edit/Tab/Info.php
<?php
namespace Magetop\Helloworld\Block\Adminhtml\Posts\Edit\Tab;
use Magento\Backend\Block\Widget\Form\Generic;
use Magento\Backend\Block\Widget\Tab\TabInterface;
use Magento\Backend\Block\Template\Context;
use Magento\Framework\Registry;
use Magento\Framework\Data\FormFactory;
use Magento\Cms\Model\Wysiwyg\Config;
use Magetop\Helloworld\Model\System\Config\Status;
class Info extends Generic implements TabInterface
{
/**
* @var \Magento\Cms\Model\Wysiwyg\Config
*/
protected $_wysiwygConfig;
/**
* @var \Magetop\Helloworld\Model\System\Config\Status
*/
protected $_status;
/**
* @param Context $context
* @param Registry $registry
* @param FormFactory $formFactory
* @param Config $wysiwygConfig
* @param Status $status
* @param array $data
*/
public function __construct(
Context $context,
Registry $registry,
FormFactory $formFactory,
Config $wysiwygConfig,
Status $status,
array $data = []
) {
$this->_wysiwygConfig = $wysiwygConfig;
$this->_status = $status;
parent::__construct($context, $registry, $formFactory, $data);
}
/**
* Prepare form fields
*
* @return \Magento\Backend\Block\Widget\Form
*/
protected function _prepareForm()
{
/** @var $model \Magetop\Helloworld\Model\PostsFactory */
$model = $this->_coreRegistry->registry('magetop_blog');
/** @var \Magento\Framework\Data\Form $form */
$form = $this->_formFactory->create();
$form->setHtmlIdPrefix('post_');
$form->setFieldNameSuffix('post');
// new filed
$fieldset = $form->addFieldset(
'base_fieldset',
['legend' => __('General')]
);
if ($model->getId()) {
$fieldset->addField(
'id',
'hidden',
['name' => 'id']
);
}
$fieldset->addField(
'title',
'text',
[
'name' => 'title',
'label' => __('Title'),
'title' => __('Title'),
'required' => true
]
);
$fieldset->addField(
'image',
'text',
array(
'name' => 'image',
'label' => __('Image'),
'title' => __('Image'),
)
);
$fieldset->addField(
'status',
'select',
[
'name' => 'status',
'label' => __('Status'),
'options' => $this->_status->toOptionArray()
]
);
$fieldset->addField('description', 'editor', [
'name' => 'description',
'label' => 'Description',
'config' => $this->_wysiwygConfig->getConfig(),
'wysiwyg' => true,
'required' => false
]);
$data = $model->getData();
$form->setValues($data);
$this->setForm($form);
return parent::_prepareForm();
}
/**
* Prepare label for tab
*
* @return string
*/
public function getTabLabel()
{
return __('Posts Info');
}
/**
* Prepare title for tab
*
* @return string
*/
public function getTabTitle()
{
return __('Posts Info');
}
/**
* {@inheritdoc}
*/
public function canShowTab()
{
return true;
}
/**
* {@inheritdoc}
*/
public function isHidden()
{
return false;
}
}
Create Controller files
You create the files Edit, Delete, NewAction, Save in the Controller with the following path: Magetop/Helloworld/Controller/Adminhtml/Posts.
Edit.php
<?php
namespace Magetop\Helloworld\Controller\Adminhtml\Posts;
use Magetop\Helloworld\Controller\Adminhtml\Posts;
class Edit extends Posts
{
/**
* @return void
*/
public function execute()
{
$postId = $this->getRequest()->getParam('id');
$model = $this->_postsFactory->create();
if ($postId) {
$model->load($postId);
if (!$model->getId()) {
$this->messageManager->addError(__('This news no longer exists.'));
$this->_redirect('*/*/');
return;
}
}
// Restore previously entered form data from session
$data = $this->_session->getNewsData(true);
if (!empty($data)) {
$model->setData($data);
}
$this->_coreRegistry->register('magetop_blog', $model);
/** @var \Magento\Backend\Model\View\Result\Page $resultPage */
$resultPage = $this->_resultPageFactory->create();
$resultPage->setActiveMenu('Magetop_Helloworld::helloworld_menu');
$resultPage->getConfig()->getTitle()->prepend(__('Posts'));
return $resultPage;
}
}
NewAction.php
<?php
namespace Magetop\Helloworld\Controller\Adminhtml\Posts;
use Magetop\Helloworld\Controller\Adminhtml\Posts;
class NewAction extends Posts
{
/**
* Create new news action
*
* @return void
*/
public function execute()
{
$this->_forward('edit');
}
}
Delete.php
<?php
namespace Magetop\Helloworld\Controller\Adminhtml\Posts;
use Magetop\Helloworld\Controller\Adminhtml\Posts;
class Delete extends Posts
{
public function execute()
{
$postId = (int) $this->getRequest()->getParam('id');
if ($postId) {
/** @var $postModel \Magetop\Hellworld\Model\Posts */
$postModel = $this->_postsFactory->create();
$postModel->load($postId);
// Check this news exists or not
if (!$postModel->getId()) {
$this->messageManager->addError(__('This news no longer exists.'));
} else {
try {
// Delete news
$postModel->delete();
$this->messageManager->addSuccess(__('The news has been deleted.'));
// Redirect to grid page
$this->_redirect('*/*/');
return;
} catch (\Exception $e) {
$this->messageManager->addError($e->getMessage());
$this->_redirect('*/*/edit', ['id' => $postModel->getId()]);
}
}
}
}
}
Save.php
<?php
namespace Magetop\Helloworld\Controller\Adminhtml\Posts;
use Magetop\Helloworld\Controller\Adminhtml\Posts;
class Save extends Posts
{
/**
* @return void
*/
public function execute()
{
$isPost = $this->getRequest()->getPost();
if ($isPost) {
$postsModel = $this->_postsFactory->create();
$postsId = $this->getRequest()->getParam('id');
if ($postsId) {
$postsModel->load($postsId);
}
$formData = $this->getRequest()->getParam('post');
$postsModel->setData($formData);
try {
// Save news
$postsModel->save();
// Display success message
$this->messageManager->addSuccess(__('The news has been saved.'));
// Check if 'Save and Continue'
if ($this->getRequest()->getParam('back')) {
$this->_redirect('*/*/edit', ['id' => $postsModel->getId(), '_current' => true]);
return;
}
// Go to grid page
$this->_redirect('*/*/');
return;
} catch (\Exception $e) {
$this->messageManager->addError($e->getMessage());
}
$this->_getSession()->setFormData($formData);
$this->_redirect('*/*/edit', ['id' => $postsId]);
}
}
}
Create two layout
Create helloworld_posts_create.xml in Magetop/Helloworld/view/adminhtml/layout/helloworld_posts_create.xml
<?xml version="1.0" encoding="UTF-8"?>
<!--
/**
* helloworld_posts_create
*
* @copyright Copyright © 2020 Magetop. All rights reserved.
* @author [email protected]
*/
-->
<layout xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="../../../../../Magento/Core/etc/layout_single.xsd">
<update handle="helloworld_posts_edit"/>
</layout>
Create helloworld_posts_edit.xml in Magetop/Helloworld/view/adminhtml/layout/helloworld_posts_edit.xml
<?xml version="1.0" encoding="UTF-8"?>
<!--
/**
* helloworld_posts_edit
*
* @copyright Copyright © 2020 Magetop. All rights reserved.
* @author [email protected]
*/
-->
<page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" layout="admin-2columns-left" xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd">
<body>
<referenceContainer name="left">
<block class="Magetop\Helloworld\Block\Adminhtml\Posts\Edit\Tabs"
name="helloworld_posts_grid_block.edit.tabs"/>
</referenceContainer>
<referenceContainer name="content">
<block class="Magetop\Helloworld\Block\Adminhtml\Posts\Edit"
name="helloworld_posts_grid_block.edit"/>
</referenceContainer>
</body>
</page>
You access in Magento Admin Panel and check it.
I hope through this series you can create your own complete module. Good luck!
In addition to Admin Grid CRUD In Magento 2, you can read the articles How To Create New Theme In Magento 2.
Follow us for the more helpful article!
We hope this is a useful series for you.
Thank you for reading!
Save button and Save and Continue button are not working
Thanks for your contribution! We will check it against
Please provide whole source code
Thanks for reading our article, sorry we do not provide the source code for this example
In your controller classes, you include: use Magetop\Helloworld\Controller\Adminhtml\Posts;
But there are no Posts.php controllers defined.
You can please check this line : You create the files Edit, Delete, NewAction, Save in the Controller with the following path: Magetop/Helloworld/Controller/Adminhtml/Posts.
The function function toggleEditor() not working in magento 2.4.5 any more.
Can’t upload image when click to button.