Download the source for this entire series here!

CRUD – Retrieve

  1. Lets add a new block to the file structure
    app/
      etc/
        modules/
          - SavantDegrees_All.xml (Or what ever your company name might be)
      code/
        local/
          SavantDegrees/ (Or what ever your company name might be)
            Twits/ (Or whatever your module name might be)
              Block/
                Admin/
                  - Main.php
                  Main/
                    - Grid.php
                - HelloWorld.php
              controllers/
                - AdminController.php
                - IndexController.php
              etc/
                - config.xml
              Helper/
                - Data.php
              Model/
                - Tip.php
                Mysql4/
                  - Tip.php
                  Tip/
                    - Collection.php
              sql/
                twits_setup/
                  - mysql4-install-0.2.0.php
                  - mysql4-upgrade-0.1.0-0.2.0.php

    We’ll create folder called Admin to store all the admin related blocks. Inside we’ll have a Main.php file that contains the Grid Container. Why do we need a grid container? To put the title and Create button!

  2. The Main.php code

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    
    <?php
    class SavantDegrees_Twits_Block_Admin_Main extends Mage_Adminhtml_Block_Widget_Grid_Container
    {
        public function __construct()
        {
            $this->_addButtonLabel = Mage::helper('twits')->__('Add New Tip');
            parent::__construct();
     
            $this->_blockGroup = 'twits';
            $this->_controller = 'admin_main';
            $this->_headerText = Mage::helper('twits')->__('Tips(s)');
        }
    }

    Here you see a first use of the helper, which will assist in translation

  3. The Grid.php itself

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    
    <?php
    class SavantDegrees_Twits_Block_Admin_Main_Grid extends Mage_Adminhtml_Block_Widget_Grid
    {
     
        public function __construct()
        {
            parent::__construct();
            $this->setId('tipsGrid');
            $this->_controller = 'twits';
        }
     
        protected function _prepareCollection()
        {
            $model = Mage::getModel('twits/tip');
            $collection = $model->getCollection();
    		$this->setCollection($collection);
     
            return parent::_prepareCollection();
        }
     
     
     
        protected function _prepareColumns()
        {
     
            $this->addColumn('tip_id', array(
                'header'        => Mage::helper('twits')->__('ID'),
                'align'         => 'right',
                'width'         => '50px',
                'filter_index'  => 'dt.tip_id',
                'index'         => 'tip_id',
            ));
     
            $this->addColumn('name', array(
                'header'        => Mage::helper('twits')->__('Title'),
                'align'         => 'left',
                'width'         => '150px',
                'filter_index'  => 'dt.title',
                'index'         => 'title',
                'type'          => 'text',
                'truncate'      => 50,
                'escape'        => true,
            ));
     
            $this->addColumn('tags', array(
                'header'    	=> Mage::helper('twits')->__('Author'),
                'align'         => 'left',
                'filter_index'  => 'dt.author',
                'index'    	 	=> 'author',
                'type'     	 	=> 'text',
                'escape'		=> true,
            ));
     
            $this->addColumn('summary', array(
                'header'        => Mage::helper('twits')->__('Contents'),
                'align'         => 'left',
                'filter_index'  => 'dt.contents',
                'index'         => 'contents',
                'type'          => 'text',
                'escape'        => false,
            ));
     
            $this->addColumn('action',
                array(
                    'header'    => Mage::helper('twits')->__('Action'),
                    'width'     => '150px',
                    'type'      => 'action',
                    'getter'	=> 'getTipId',
                    'actions'   => array(
                        array(
                            'caption' => Mage::helper('twits')->__('Edit'),
                            'url'     => array(
                                'base'=>'*/*/edit'
                             ),
                             'field'   => 'id'
                        ),
                        array(
                            'caption' => Mage::helper('twits')->__('Delete'),
                            'url'     => array(
                                'base'=>'*/*/delete'
                             ),
                             'field'   => 'id'
                        )
                    ),
                    'filter'    => false,
                    'sortable'  => false
            ));
     
            return parent::_prepareColumns();
        }
     
        public function getRowUrl($row)
        {
            return $this->getUrl('*/*/edit', array(
                'id' => $row->getTipId(),
            ));
        }
    }

    If you scrutinize the code (which i’d advise against), you’ll see most of the code is geared towards the setup of the grid columns and the edit/delete urls i’ll eventually call to perform the other CRUD functions.
    But whats going on? Where do we use this code? The main code (being a Grid_Container automatically adds the child Grid code associated to it. By child we’re talking about the Grid.php file in the Main folder. The folder’s name follows the file. So if you changed the folder’s name to Main2, it wouldnt work. That being said, you can just put any block code in the folder and expect it to run. The reason why this all works now is cause the geniuses at Magento already did alot of work to call the Grid child to run. They have no super time travel powers to tell what else you’re gonna put in there. So, it simply wont work (yet).

  4. Now lets make our adminController.php use that block instead of Hello world.
    1
    2
    3
    4
    5
    6
    7
    8
    9
    
    class SavantDegrees_Twits_AdminController extends Mage_Adminhtml_Controller_Action
    {
        public function indexAction()
        {
    		$this->loadLayout()
    			->_addContent($this->getLayout()->createBlock('twits/admin_main'))
    			->renderLayout();
        }
    }

    Well it says createBlock doesnt it? What do you think it does? twits/admin_main as always refers to the twits namespace and the admin/main.php block file.

  5. Viola! Your very very very hard earned grid!
    Magento Admin Grid

» Anytime now … Part 6 – CRUD – Delete


7 Responses to “Howto: Repackageable custom extension development in Magento – Part 5 – CRUD – Retrieve”

  1. Muzafar Ali Says:

    Hi,
    thanks for sharing a beautiful article

  2. Will Says:

    Thnak you! I was struggling with a grid whos collection had a join which resulted in an ambigous column in the where clause. While not directly addressing this issue your example used the “filter_index” property which was exactly what I was looking for!

  3. gaweee Says:

    Hi 23,
    what you’re looking for is relatively tricky i assume. Magento’s way of piecing the Sales Orders and Invoices together is quite complicated.
    I have not dived that deep into the models manipulation yet so i’m uncertain how to do the advanced grouping/reporting required.
    But it should be doable. Where possible you’ll have to learn to work with the model's collection and filters, then go the rest of the way by your own calculations. =)
    For example you can get a collection of sales invoices, filter them by date, then add up the totals together. to get your periodic revenue, then go into the items to calculate the periodic cost and finally get the profit.
    Sounds easier than it really its. =p

  4. 23 Says:

    hey gaweee -
    thanks for your advices. my problem is that I can not find the depending collection.php or the place where I have to put the code in. I am also not able to find a fitting sql query, which I can manipulate like “SELECT ‘cost’ FROM …” or how to accumulate the costs over a specific time (i.e. monthly costs / profit) and calculate the periodic profit.

    I expect that I am too dumb to understand the needed framework and programming knowledge.
    gaweee – do you have a donate-button somewhere on your page and 10mins time? :)
    regards.

  5. gaweee Says:

    Hey 23,
    There are some events of a Grid that gets triggered after loading the Collection _afterLoad or something. you can always override those methods and manipulate the Model‘s Collection into the Grid‘s data. then point the right Index there. But that’s a really dirty way to do it.

    The right way is to use Grid Filters and Renderers. Example:

    getValue();
    		return array('like'=>'%'.$this->_escapeValue($value).'%');
    	}
    }

    As well as

    getRequest_path();
    		$sefurl = Mage::helper('twit/data')->removePrefix($sefurl,  Mage::getStoreConfig('twit/seo/some_url_prefix'));
    		$sefurl = Mage::helper('twit/data')->removeSuffix($sefurl,  Mage::getStoreConfig('twit/seo/some_url_suffix'));
     
    		return $sefurl;
    	}
    }

    Then you can add the column in the Grid this way:

    	$this->addColumn('request_path', array(
                'header'        => Mage::helper('twit')->__('URL'),
                'align'         => 'left',
                'width'         => '150px',
                'filter_index'  => 'request_path',
                'index'         => 'request_path',
                'type'          => 'text',
                'filter'		=> 'twit/some_module_main_grid_filter_url',
                'renderer'  	=> 'twit/some_module_main_grid_renderer_url',
                'escape'        => true,
            ));
  6. 23 Says:

    Hi – Thanks a lot for your awesome howtos! Nice job!

    My question is the following:
    I try to expand the sales report by two columns in order to show the cost and calculate the net profit.
    The changes in the app/code/local/mage/adminhtml/block/report/sales/sales/grid.php worked well.
    I added the following lines:

    $this->addColumn(‘cost’, array(
    ‘header’ => Mage::helper(‘sales’)->__(‘cost’),
    ‘index’ => ‘cost’,
    ‘type’ =>’currency’
    ));

    $this->addColumn(‘profit’, array(
    ‘header’ => Mage::helper(‘sales’)->__(‘net profit’),
    ‘index’ => ‘shipping_description’ //shipping_discription for testing purposes ;)
    ));

    I would like to know which entries for ‘index’ are available in this report and how to expand the corresponding collection.php to fetch the product relevant costs and calculate the net profit and paste it in a var.

    Maybe somebody would help me :(
    Kind Regards,
    23

  7. tight Says:

    I got an error while filtering results.
    Removing prefix “dt.” in filter_index’s value of $this->addColumn solved the problem.

Leave a Reply