Magento Fatal Error - setSaveParametersInSession() on a non-object

Take a look at [How to create a custom grid from scratch][1] and custom module with custom database table

Grid.php : Incorrect and missing

class <Namespace>_<Module>_Block_Adminhtml_<Module> extends Mage_Adminhtml_Block_Widget_Grid_Container
{
    public function __construct()
    {
        $this->_controller = 'adminhtml_<module>';
        $this->_blockGroup = '<module>';
        $this->_headerText = Mage::helper('<module>')->__('Item Manager');
        $this->_addButtonLabel = Mage::helper('<module>')->__('Add Item');
        parent::__construct();
    }
}


class <Namespace>_<Module>_Block_Adminhtml_<Module>_Grid extends Mage_Adminhtml_Block_Widget_Grid
{
    public function __construct()
    {
        parent::__construct();
        $this->setId('<module>Grid');
        // This is the primary key of the database
        $this->setDefaultSort('<module>_id');
        $this->setDefaultDir('ASC');
        $this->setSaveParametersInSession(true);
        $this->setUseAjax(true);
    }

Have a look on the error to which Magento refers.

protected function _prepareLayout()
{
    $this->setChild( 'grid',
        $this->getLayout()->createBlock( $this->_blockGroup.'/' . $this->_controller . '_grid',
        $this->_controller . '.grid')->setSaveParametersInSession(true) );
    return parent::_prepareLayout();
}

Here the function that holds setSaveParametersInSession() is _prepareLayout(). This function is processed during layout preparation time carried out by magento. If you have a closer look on the method, you will understand that, it is triying to set a child block to grid block that you have defined via layout file ($this stands for the grid block).

In case of admin grid block, actually we just defines the outer block of grid in our layout file. Magento then set a child block to this grid block and then use it for its internally in order to generate the entire grid section. So the collection that we set in grid block, will then use by this child block and will process accordingly. Why Magento generates child blocks programmatically ? This is because, almost all time, magento admin grid looks same . Only the collection that loading in that grid changes. So Magento allows us to _prepareCollection() in our custom grid block so that it the entire grid page uses our custom collection. You dont need to do any complex thing in order to generate the complex grid structure.

Now I want your concenration on this code

 createBlock( $this->_blockGroup.'/' . $this->_controller . '_grid', $this->_controller . '.grid')

this is what become an invalid object in your context. As you can see it tries to generate a block. As per the definition inside your grid block (ORD_UpdatePro_Block_Adminhtml_Grid. this is a wrong class actually. I come to this point later), this code can be rewrite like this.

 createBlock('updatepro/adminhtml_grid_grid', 'adminhtml_grid.grid')

The first argument stands for type of the block and second argurment stands for name of the newly generating block. The type of your block means, Magento will look for ORD_UpdatePro_Block_Adminhtml_Grid_Grid block class inside your module. Unfortunately Magento cannot found out that class because, that class really not exist. So magento complaints it.

Actually the block that should generate in this context is ORD_UpdatePro_Block_Adminhtml_Updatepro_Grid (As per the best practices) and I hope you have that file is actually defined inside your module at app/code/local/RD/UpdatePro/Block/Adminhtml/Updatepro/Grid.php.

Now let us look how can we generate this name inside your grid container block. Oh wait. Your grid block seems wrong. It should be ORD_UpdatePro_Block_Adminhtml_UpdatePro instead of ORD_UpdatePro_Block_Adminhtml_Grid. But block that you defined now is recognizing by Magento. That is why the error itself is raised!!! So let us look why it is recognized. In your layout file, you have this.

<reference name="content">
  <block type="updatepro/adminhtml_grid"  name="updatepro" template="updatepro/afficher.phtml" />
</reference>

The block that you including here is ORD_UpdatePro_Block_Adminhtml_Grid. So magento is able to recognize your block, because it is defined backend of your module. However as per the best practice, it is wrong. Your layout should looks like this.

 <reference name="content">
  <block type="updatepro/adminhtml_updatepro"  name="updatepro" template="updatepro/afficher.phtml" />
</reference>

Now your block points to the block ORD_UpdatePro_Block_Adminhtml_UpdatePro and it should defined at app/code/local/ORD/UpdatePro/Block/Adminhtml/UpdatePro.php.

Inside this you need to look on below property values which is actually using to generate child grid block as I explained before.

    $this->_controller = 'adminhtml_updatepro';
    $this->_blockGroup = 'updatepro';

Now as per the definition of this private properties, the function in question will look like this.

createBlock('updatepro/adminhtml_update_grid', 'adminhtml_updatepro.grid')

and this eventually looks for the block ORD_UpdatePro_Block_Adminhtml_Updatepro_Grid. If you have this block is defined at the backside of your module (app/code/local/RD/UpdatePro/Block/Adminhtml/Updatepro/Grid.php), then everything is super cool. No confusion for us and no confusion for magento. Story should have a happy endings then !!!

What is the big point?

Beware this private properties. $this->_blockGroup and $this->_controller.

$this->_blockGroup should be the block alias name that you have specified insid your module's config.xml file. In normal case it will looks like [namespace]_[modulename] $this->_controller should be the trailing block paths that is pointing towards your grid container block. In normal case it would be adminhtml_[modulename]