Call our sales line
08000 484 679
Home > Magento Tutorials > Magento Model Basics Part 3 – Building Your Grid

Magento Model Basics Part 3 – Building Your Grid

Posted on: 1st Mar 2013 By: Adam Moss 2 Comments

Magento Models Part 3

The final chapter in my ‘model basics’ series is all about making your model editable from the Magento admin. So far we’ve created our actual model, set up a model collection, created a database table for the model to use and we’ve created an admin controller to eventually access our grid from.

If you haven’t read them yet, I suggest you read them first:

  1. Magento Model Basics Part 1 – Creating Your Model
  2. Magento Model Basics Part 2 – Preparing Your Admin

In this post I’ll go through how we put our grid together. It involves 3 steps:

  1. Make a grid container to display on our controller
  2. Building the actual grid columns and content
  3. Creating a form container
  4. Creating an edit form for making new, and editing existing instances of your model

Block/Adminhtml/Photograph.php

The first block we create is the grid container – we know this because it extends the admin grid container. You may remember that we referenced this block as the content for our main controller in photo.xml in our last tutorial.

<?php

class Creare_Photo_Block_Adminhtml_Photograph extends Mage_Adminhtml_Block_Widget_Grid_Container
{
    public function __construct()
    {
        $this->_blockGroup = 'photo';
        $this->_controller = 'adminhtml_photograph';
        $this->_headerText = Mage::helper('photo')->__('Photographs');
        parent::__construct();
    }
}

The block group and controller are absolutely essential that are entered correctly, otherwise your entire grid will never show up. Despite the naming convention, $this->_controller does not refer to your controller path. It is actually the block path to your Grid.php file which we’ll make in a minute. $this->blockGroup  refers to your block group as set in config.xml.

If you check out the parent class, you’ll see how the two items are used to define a path:

$this->_blockGroup.'/' . $this->_controller . '_grid'

Which becomes: photo/adminhtml_photograph_grid

Sounds awfully familiar to a block type declaration in your layout XML eh?

Block/Adminhtml/Photograph/Grid.php

The actual grid lies in the exact path that we specify in our container class. It consists of just four methods. The initial construct builds some basic info to be used by the parent grid class. Then we create our collection to be used in the grid – how about we use our photograph model collection?

<?php

class Creare_Photo_Block_Adminhtml_Photograph_Grid extends Mage_Adminhtml_Block_Widget_Grid
{
    public function __construct()
    {
        parent::__construct();
        $this->setId('photograph_grid');
        $this->setDefaultSort('entity_id');
        $this->setDefaultDir('asc');
        $this->setSaveParametersInSession(true);
    }

    protected function _prepareCollection()
    {
        $collection = Mage::getModel('photo/photograph')->getCollection();
        $this->setCollection($collection);
        return parent::_prepareCollection();
    }

    protected function _prepareColumns()
    {
        $this->addColumn('entity_id', array(
            'header'    => Mage::helper('photo')->__('ID'),
            'align'     =>'right',
            'width'     => '50px',
            'index'     => 'entity_id',
        ));

        $this->addColumn('title', array(
            'header'    => Mage::helper('photo')->__('Title'),
            'align'     =>'left',
            'index'     => 'title',
        ));

        $this->addColumn('img_path', array(
            'header'    => Mage::helper('photo')->__('Image Path'),
            'align'     =>'left',
            'index'     => 'img_path',
        ));

        return parent::_prepareColumns();
    }

    public function getRowUrl($row)
    {
        return $this->getUrl('*/*/edit', array('id' => $row->getId()));
    }
}

We then use the _prepareColumns() method to populate our grid with our model collection data. There are tons of tutorials out there which specify different column data types. Finally we create a link path for getRowUrl() should a row be clicked upon. We know that we want to be able to edit our model information so we’ll direct the user to our editAction on the current controller.

Block/Adminhtml/Photograph/Edit.php

Now we create a container for our edit form. You may remember that we specified this block in our photo.xml layout updates as the content for the edit action. As with the grid container, we need to specify the path to our content by setting a blockGroup, controller and mode at in our _construct method of this class. If you want you can add some JavaScript which allows the user to ‘Save And Continue Edit’.

<?php

class Creare_Photo_Block_Adminhtml_Photograph_Edit extends Mage_Adminhtml_Block_Widget_Form_Container
{
    public function __construct()
    {
        parent::__construct();

        $this->_objectId = 'id';
        $this->_blockGroup = 'photo';
        $this->_controller = 'adminhtml_photograph';
        $this->_mode = 'edit';

        $this->_addButton('save_and_continue', array(
                  'label' => Mage::helper('adminhtml')->__('Save And Continue Edit'),
                  'onclick' => 'saveAndContinueEdit()',
                  'class' => 'save',
        ), -100);
        $this->_updateButton('save', 'label', Mage::helper('photo')->__('Save Photograph'));

        $this->_formScripts[] = "
            function toggleEditor() {
                if (tinyMCE.getInstanceById('form_content') == null) {
                    tinyMCE.execCommand('mceAddControl', false, 'edit_form');
                } else {
                    tinyMCE.execCommand('mceRemoveControl', false, 'edit_form');
                }
            }

            function saveAndContinueEdit(){
                editForm.submit($('edit_form').action+'back/edit/');
            }
        ";
    }

    public function getHeaderText()
    {
        if (Mage::registry('photograph_data') && Mage::registry('photograph_data')->getId())
        {
            return Mage::helper('photo')->__('Edit Photograph "%s"', $this->htmlEscape(Mage::registry('photograph_data')->getTitle()));
        } else {
            return Mage::helper('photo')->__('New Photograph');
        }
    }
}

In the parent container class, as with the grid the block is created as a child of this container using the following code in _prepareLayout():

$this->_blockGroup . '/' . $this->_controller . '_' . $this->_mode . '_form'

Which becomes: photo/adminhtml_photograph_edit_form

The getHeaderText() method at the bottom of the class checks for an instance of our model. If none exists in the registry it will treat it as a new model, otherwise it will treat it as an existing one being edited. Simple eh?

Block/Adminhtml/Photograph/Edit/Form.php

It is possible to divide your form into tabs which makes your form layout a bit more user-friendly. I’ll go into that in a future tutorial, but in this case it’s all gonna be on the same page.

<?php

class Creare_Photo_Block_Adminhtml_Photograph_Edit_Form extends Mage_Adminhtml_Block_Widget_Form
{
    protected function _prepareForm()
    {
        if (Mage::registry('photograph_data'))
        {
            $data = Mage::registry('photograph_data')->getData();
        }
        else
        {
            $data = array();
        }

        $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);

        $fieldset = $form->addFieldset('photograph_form', array(
             'legend' =>Mage::helper('photo')->__('Photograph Information')
        ));

        $fieldset->addField('title', 'text', array(
             'label'     => Mage::helper('photo')->__('Photograph Name'),
             'class'     => 'required-entry',
             'required'  => true,
             'name'      => 'title'
        ));

        $fieldset->addField('img_path', 'text', array(
             'label'     => Mage::helper('photo')->__('Image Path'),
             'class'     => 'required-entry',
             'required'  => true,
             'name'      => 'img_path'
        ));

        $form->setValues($data);

        return parent::_prepareForm();
    }
}

As before I have checked for a copy of my model in the registry – if one exists then the form is populated and it’s treated as an edit. Otherwise it’s treated as a new model. I’ve created one field-set and added a couple of fields to it.

The end result should be an admin grid which looks like this:

Grid

And the edit form should look kinda like this:

form

That’s the end of the 3-part series – you should now know the basics for creating a custom model. There’s so much more that you can do with models and different data types so have fun exploring the possibilities.

By Adam Moss

Adam is Ecommerce Manager and a PHP developer at Creare Group. Adam is responsible for training Magento development within the company. Follow Adam on Twitter: http://twitter.com/adampmoss. - .

2 Responses to “ Magento Model Basics Part 3 – Building Your Grid ”

  1. ElPresident
    #1 | 1st March 2013

    Thanks for the useful article, Adam. Can you explain the reasoning behind storing the images paths in a text attribute – wouldn’t you be better off making it a file/image type so that you can have an uploader on your admin form, plus take advantage of Magento’s image resizing helpers on the front-end?
    In my experience, customers don’t like having to use FTP. Or they like it a bit too much and start fiddling where they don’t belong.

  2. Adam Moss
    #2 | 1st March 2013

    Yes you’re absolutely right, you’d use a file upload rather than writing an image path. To keep this tutorial as simple as possible I just used a text field to avoid cluttering the controller with too much code.

Post A Comment

Your comments:
Enclose code snippets within the appropriate tags: [php][/php]   [js][/js]   [xml][/xml]   [css][/css]   [html][/html]
E.g: [php]<?php echo "hello world"; ?>[/php]

Search Blog

Follow us on Twitter

Archives

For the record...

Views & opinions in this blog are those of the individual and do not necessarily reflect those of E-commerce Web Design or the Creare Group.