In the previous article, I wrote about some basic concepts of Adminhtml’s architecture. Today I aim to dig deeper into the form and grid widgets and show you the easiest way to use them in your extension.
Resources for your Magento Store:
Magestore’s 30+ Best Magento Extensions and Magento 2 Extensions that all you need.
Our “must-read” guides and tutorials about Magento 1 and Magento 2
1. Structure and template
Firstly, I will talk about Grid Widgets in Magento back-end. The Grid Widgets in Magento have some blocks as below:
- Grid container: extended from the class Mage_Adminhtml_Block_Widget_Grid_Container with the default template widget/grid/container.phtml. The grid container contains the grid’s header (title and buttons) and the grid’s content
- Grid content: extended from the class Mage_Adminhtml_Block_Widget_Grid and its default template is widget/grid.phtml. The grid content includes a data grid, paging grid, filter data and massaction for grid. An important method of grid is addColumn.
- Massaction: based on Mage_Adminhtml_Block_Widget_Grid_Massaction with the default template: widget/grid/massaction.phtml. Massaction is used to operate a list of data in a grid.
- Serializer: works with grid data (by javascript) and transforms it to serial.
In Magento, the grid container automatically finds the grid content block (based on two protected attributes: _blockGroup, _controller) to render grid to HTML.
Secondly, the Form in Magento back-end is a basic template. The Form Widgets in Magento have some blocks as the followings:
- Form container: extended from the class Mage_Adminhtml_Block_Widget_Form_Container with the default template: widget/form/container.phtml. The Form container includes form’s components such as header, content, footer and javascript.
- Form content: extended from the class Mage_Adminhtml_Block_Widget_Form with the default template: widget/form.phtml. The Form content includes form’s elements such as fieldset, text… (the list of form’s elements in the folder lib/Varien/Data/Form/Element).
- Form tabs: extended from class Mage_Adminhtml_Block_Widget_Tabs with the default template: widget/tabs.phtml. Form tabs are used to divide a long form to multiple tabs. It uses Javascript to add the content for the form.
Similar to the grid container, the form container automatically finds the form content block (based on protected attributes: _blockGroup and _controller) to render form to HTML.
2. How to use a grid in your extension
Now, we will create an adminhtml grid with some steps below:
Step 1: Create a grid container block. For example: app\code\local\Magestore\Tests\Block\Adminhtml\Tests.php
<?php
class Magestore_Tests_Block_Adminhtml_Tests extends Mage_Adminhtml_Block_Widget_Grid_Container
{
public function __construct(){
$this->_controller = 'adminhtml_tests';
$this->_blockGroup = 'tests';
$this->_headerText = Mage::helper('tests')->__('Item Manager');
$this->_addButtonLabel = Mage::helper('tests')->__('Add Item');
parent::__construct();
}
}
In this block, we need to declare some protected attributes:
_blockGroup: offten is module name
_controller: offten is controller name
_headerText: header text for grid
Step 2: Create a grid block
Because the grid container above has the attribute _controller equal ‘adminhtml_test’, so we need to create a grid block app\code\local\Magestore\Tests\Block\Adminhtml\Tests\Grid.php
<?php
class Magestore_Tests_Block_Adminhtml_Tests_Grid extends Mage_Adminhtml_Block_Widget_Grid
{
public function __construct(){
parent::__construct();
$this->setId('testsGrid');
$this->setDefaultSort('tests_id');
$this->setDefaultDir('ASC');
$this->setSaveParametersInSession(true);
}
protected function _prepareCollection(){
$collection = Mage::getModel('tests/tests')->getCollection();
$this->setCollection($collection);
return parent::_prepareCollection();
}
protected function _prepareColumns(){
$this->addColumn('tests_id', array(
'header' => Mage::helper('tests')->__('ID'),
'align' =>'right',
'width' => '50px',
'index' => 'tests_id',
));
$this->addColumn('title', array(
'header' => Mage::helper('tests')->__('Title'),
'align' =>'left',
'index' => 'title',
));
return parent::_prepareColumns();
}
protected function _prepareMassaction(){
$this->setMassactionIdField('tests_id');
$this->getMassactionBlock()->setFormFieldName('tests');
$this->getMassactionBlock()->addItem('delete', array(
'label' => Mage::helper('tests')->__('Delete'),
'url' => $this->getUrl('*/*/massDelete'),
'confirm' => Mage::helper('tests')->__('Are you sure?')
));
return $this;
}
public function getRowUrl($row){
return $this->getUrl('*/*/edit', array('id' => $row->getId()));
}
}
Step 3: Show the grid in a controllers/action by editing the layout file: app\design\adminhtml\default\default\layout\tests.xml
<?xml version="1.0"?>
<layout version="0.1.0">
<testsadmin_adminhtml_tests_index>
<reference name="content">
<block type="tests/adminhtml_tests" name="tests" />
</reference>
</testsadmin_adminhtml_tests_index>
</layout>
3. How to use a form in your extension
To use a form in your extension, it’s necessary to create form’s blocks and attach them to your controller.
Step 1: Create a form container block (app\code\local\Magestore\Tests\Block\Adminhtml\Tests\Edit.php)
<?php
class Magestore_Tests_Block_Adminhtml_Tests_Edit extends Mage_Adminhtml_Block_Widget_Form_Container
{
public function __construct(){
parent::__construct();
$this->_objectId = 'id';
$this->_blockGroup = 'tests';
$this->_controller = 'adminhtml_tests';
$this->_mode = 'edit';
$this->_updateButton('save', 'label', Mage::helper('tests')->__('Save Item'));
$this->_updateButton('delete', 'label', Mage::helper('tests')->__('Delete Item'));
}
public function getHeaderText(){
if(Mage::registry('tests_data') && Mage::registry('tests_data')->getId())
return Mage::helper('tests')->__("Edit Item '%s'", $this->htmlEscape(Mage::registry('tests_data')->getTitle()));
return Mage::helper('tests')->__('Add Item');
}
}
Similar to the grid container, you have to declare some protected attributes, besides you can set _mode attribute (default is ‘edit‘).
Step 2: Create a form content block
Because form container attribute _mode is ‘edit‘, you need to create form block:
(app\code\local\Magestore\Tests\Block\Adminhtml\Tests\Edit\Form.php)
<?php
class Magestore_Tests_Block_Adminhtml_Tests_Edit_Form extends Mage_Adminhtml_Block_Widget_Form
{
protected function _prepareForm(){
$form = new Varien_Data_Form(array(
'id' => 'edit_form',
'action' => $this->getUrl('*/*/save', array(
'id' => $this->getRequest()->getParam('id'),
)),
'method' => 'post',
'enctype' => 'multipart/form-data'
));
$form->setUseContainer(true);
$this->setForm($form);
return parent::_prepareForm();
}
}
This block only defines a form that has no items. The form item will be added by a Tabs block as below:
Step 3: Create a Tabs block
(app\code\local\Magestore\Tests\Block\Adminhtml\Tests\Edit\Tabs.php)
<?php
class Magestore_Tests_Block_Adminhtml_Tests_Edit_Tabs extends Mage_Adminhtml_Block_Widget_Tabs
{
public function __construct(){
parent::__construct();
$this->setId('tests_tabs');
$this->setDestElementId('edit_form');
$this->setTitle(Mage::helper('tests')->__('Item Information'));
}
protected function _beforeToHtml(){
$this->addTab('form_section', array(
'label' => Mage::helper('tests')->__('Item Information'),
'title' => Mage::helper('tests')->__('Item Information'),
'content' => $this->getLayout()->createBlock('tests/adminhtml_tests_edit_tab_form')->toHtml(),
));
return parent::_beforeToHtml();
}
}
In this block, we add tab form_section to a form ‘tests/adminhtml_tests_edit_tab_form‘, so we need to create that block:
(app\code\local\Magestore\Tests\Block\Adminhtml\Tests\Edit\Tab\Form.php)
<?php
class Magestore_Tests_Block_Adminhtml_Tests_Edit_Tab_Form extends Mage_Adminhtml_Block_Widget_Form
{
protected function _prepareForm(){
$form = new Varien_Data_Form();
$this->setForm($form);
if (Mage::getSingleton('adminhtml/session')->getTestsData()){
$data = Mage::getSingleton('adminhtml/session')->getTestsData();
Mage::getSingleton('adminhtml/session')->setTestsData(null);
}elseif(Mage::registry('tests_data'))
$data = Mage::registry('tests_data')->getData();
$fieldset = $form->addFieldset('tests_form', array('legend'=>Mage::helper('tests')->__('Item information')));
$fieldset->addField('title', 'text', array(
'label' => Mage::helper('tests')->__('Title'),
'class' => 'required-entry',
'required' => true,
'name' => 'title',
));
$form->setValues($data);
return parent::_prepareForm();
}
}
Step 4: Add a form to controllers/action in the controller file
public function editAction() {
$id = $this->getRequest()->getParam('id');
$model = Mage::getModel('tests/tests')->load($id);
if ($model->getId() || $id == 0) {
$data = Mage::getSingleton('adminhtml/session')->getFormData(true);
if (!empty($data))
$model->setData($data);
Mage::register('tests_data', $model);
$this->loadLayout();
$this->_setActiveMenu('tests/tests');
$this->getLayout()->getBlock('head')->setCanLoadExtJs(true);
$this->_addContent($this->getLayout()->createBlock('tests/adminhtml_tests_edit'))
->_addLeft($this->getLayout()->createBlock('tests/adminhtml_tests_edit_tabs'));
$this->renderLayout();
} else {
Mage::getSingleton('adminhtml/session')->addError(Mage::helper('tests')->__('Item does not exist'));
$this->_redirect('*/*/');
}
}
Here you can see two functions: _addContent and _addLeft to add the form’s content and tabs for the controllers/action.
This part ends here. Hope that you can take and extend the Magento experience that I’ve shared for your own needs.
2 Comments
I don’t understand which model loads on this line:
$model = Mage::getModel(‘tests/tests’)->load($id);
I found this in line 4 on step 4 of form using. Can anybody comment this moment ?
Hi,
Thank you very much for this very very very good post! This one explains a lot more then many others do and since I’m developing a form with multiple tabs I really needed to understand this! I am very grateful for this! Now I know why my save action didn’t work for all tabs in my form 🙂
Thank you again!