Tracing Magento from “Export CSV” to “Save File – OK” button

Tracing Magento from “Export CSV” to “Save File – OK” button

First of all, this post is beginners guide about tracing in Magento. I’ve created 2 parts. First one is about how to find important parts in Magento core app – I decided to explain exporting collections to CSV (this requirement you’ll need on almost every project) and in second part we’ll go through Magento getCsvFile() method and explain some properties there. This first one is basic and I’ll lead you through steps “how to trace” steps from exporting to download process in Magento. If you’re already familiar with steps that we’ll do feel free to skip this post and jump to Part 2.
If you’re relatively new to Magento and you are not so familiar how grid containers works in Magento and where is placed Export to: CSV Export button keep reading.

Let’s start with tracing and explaining few steps before we implement new and improved functionality. This is required step when you want to implement something new on existing framework. You need to know how it works.

Starting place could be sales_order grid in Magento administration. If you visit something like http://magento1510.loc/index.php/admin/sales_order/ you’ll see “Export to: – CSV – Export” button.

Let’s find what will happen in code if we click on that “Export” button and why you have those options there.

If you open file app/code/core/Mage/Adminhtml/controllers/Sales/OrderController.php and search to see which Block is called, you’ll not find initial block that system will use for sales_order grid. Additionally, you can see next method in our controller:

/**
* Export order grid to CSV format
*/
public function exportCsvAction()
{
$fileName = 'orders.csv';
$grid = $this->getLayout()->createBlock('adminhtml/sales_order_grid');
$this->_prepareDownloadResponse($fileName, $grid->getCsvFile());
}

in app/code/core/Mage/Adminhtml/controllers/Sales/OrderController.php file. This method we’ll look more deeply eventually later, shortly, that’s the method that will be run if we click on “Export to CSV” button.

So if definition of our Block (View in MVC) isn’t in controller file, then it must be in layout folder. In default community edition (1510) (as you can see from my example URL) find file app/design/adminhtml/default/default/layout/sales.xml and look for node adminhtml_sales_order_index. If you are not using Eclipse or some other PDT you can search your Magento project by regular expression to find handle adminhtml_sales_order_index, or more precisely in app/design/adminhtml/default/default/layout folder.
Why we have “_index” at the end of our handle? If you look again our example URL, http://magento1510.loc/index.php/admin/sales_order/, you can see that we have frontName admin, sales_order is our controller name (…Sales/Order.php) and index is our default action (indexAction()), if action isn’t specified. If you visit http://magento1510.loc/index.php/admin/sales_order/index/ same result you’ll get on screen. Searching through Magento files, like searching for this handle, is developer daily routine. You can see node frontName in module’s configuration file, app/code/core/Mage/Adminhtml/etc/config.xml.

In file app/design/adminhtml/default/default/layout/sales.xml we can see, as some of us could guess, that our Block is placed in our adminhtml module, sales_order block: < block type=”adminhtml/sales_order”

Now if you open file app/code/core/Mage/Adminhtml/Block/Sales/Order.php you can see that our block is actually container for other blocks (Mage_Adminhtml_Block_Sales_Order extends Mage_Adminhtml_Block_Widget_Grid_Container). In magic method __construct we can see that only _controller property is set to sales_order which implies that system will call some other blocks – and default templates (magento core team didn’t override anything in parent class).

Even in this Block we don’t have our template definition. So let’s now open extended class Mage_Adminhtml_Block_Widget_Grid_Container that is placed in app/code/core/Mage/Adminhtml/Block/Widget/Grid/Container.php file. Now in __construct() method we can see: $this->setTemplate(‘widget/grid/container.phtml’);.

File is located in app/design/adminhtml/default/default/template/widget/grid/container.phtml and in that file you can see call to < ?php echo $this->getGridHtml() ?>. Because we are in block Order.php and here we can’t see getGridHtml() method defined, we need to look in parent classes to see where it’s defined. So let’s first look in parent class Mage_Adminhtml_Block_Widget_Grid_Container. Here we can see that parent class has getGridHtml() method defined:

public function getGridHtml()
{
return $this->getChildHtml('grid');
}

Little digression.
But how to jump through various extended classes? If you’re using Eclipse or some similar PDT when you click on method/class name while holding the Ctrl button (Command button for Mac), it navigates to the page where the function or class is defined. Or you can put cursor on that method/class and press “F3”. Your PDT should jump to that class/method. You can read more here about how to use PDT with ZF. Remember that Magento is built on Zend Framework.

Let’s go back to our code.
What now mean getChildHtml(‘grid’)? Before we answer on that question let’s see properties of this class.

From child class we know about our _controller property ( $this->_controller = ‘sales_order’; ).
And from Container.php:
protected $_blockGroup = ‘adminhtml’;
Let’s now look in method _prepareLayout():

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

we can see here that we are creating new child block ‘grid’ with block group name $this->_blockGroup.’/’ . $this->_controller . ‘_grid’, $this->_controller . ‘.grid’ and this answer our question what mean getChildHtml(‘grid’).

If we interpolate this we will get createBlock(‘adminhtml/sales_order_grid’, ‘sales_order.grid’).
adminhtml/sales_order_grid‘ is factory group name and ‘sales_order.grid‘ is the “name” of newly created block – similar as we would define it in our layout XML files.

Now we should open file app/code/core/Mage/Adminhtml/Block/Sales/Order/Grid.php. Here you can see what is set for our grid, in our sales_order controller, and why we see all of those information there (buttons, collection, mass actions, etc.).

Now let’s find method _prepareColumns() and at the end of that method try to add

$this->addExportType('*/*/inchoo', Mage::helper('sales')->__('Inchoo'));

, just before line

$this->addExportType('*/*/exportCsv', Mage::helper('sales')->__('CSV'));

Now you should have inside of _prepareColumns method 3 calls to method addExportType().

Now visit / refresh sales_order grid in Magento administration ( http://magento1510.loc/index.php/admin/sales_order/ ) and you should see “Export to: – Inchoo – Export” button. If you click on it, you’ll be redirected to 404. page http://magento1510.loc/index.php/admin/sales_order/inchoo/. Remember, when we added line $this->addExportType(‘*/*/inchoo’, Mage::helper(‘sales’)->__(‘Inchoo’)); we’ve actually created call to “inchooAction()” from sales_order controller. If you wish you can create method inchooAction() in sales_order controller with a following content:

public function inchooAction()
{
exit('we are here!');
}

and again you can click on export button – you should see blank page with “we are here!” content on it. So if you see it, we are on same wave! Revert any changes in core files.

Now we see meaning of line $this->addExportType(‘*/*/exportCsv’, Mage::helper(‘sales’)->__(‘CSV’)); and why we see option CSV for “Export” button in sales_order grid. Basically, we are calling method exportCsvAction() from our controller, app/code/core/Mage/Adminhtml/controllers/Sales/OrderController.php.

Content of method exportCsvAction():

/**
* Export order grid to CSV format
*/
public function exportCsvAction()
{
$fileName = 'orders.csv';
$grid = $this->getLayout()->createBlock('adminhtml/sales_order_grid');
$this->_prepareDownloadResponse($fileName, $grid->getCsvFile());
}

As we can see from code above, we are creating new adminhtml/sales_order_grid object and based on that instance inside _prepareDownloadResponse() method we are calling getCsvFile() method. getCsvFile() method is placed in file app/code/core/Mage/Adminhtml/Block/Widget/Grid.php and it returns an array:

return array(
'type' => 'filename',
'value' => $file,
'rm' => true // can delete file after use
);

Little digresion.
If you don’t know object’s class name, you can always type something like:

<?php
echo get_class($object);
exit;
?>

and at the bottom of your page (page source) you’ll see object’s class name – if $object is type of object.
Additionally, if you’re in some method and you know that Magento system will be in execution here in it’s request flow but you’re interested in all previous steps that Magento did in that process you can type something like:

<?php
//... we are in some method
throw new Exception ( "Stop with execution here and show me steps how did you come here!");
?>

and you’ll see full stack trace. Keep in mind that you need set display_erros(1); in index.php file + you can set developer mode to ON.

Let’s go back to our code.
Look closely inside method getCsvFile(). Shortly, Magento will grab whole collection and save that collection to specified folder as md5() CSV file. Then file will be eventually deleted:

$io = new Varien_Io_File();
 
$path = Mage::getBaseDir('var') . DS . 'export' . DS;
$name = md5(microtime());
$file = $path . DS . $name . '.csv';
 
$io->setAllowCreateFolders(true);
$io->open(array('path' => $path));
$io->streamOpen($file, 'w+');
$io->streamLock(true);

And we’re done! We’ve gone through all important steps. Now it’s time to see how we can rewrite Magento export functionality and enhance it little bit.

In our next step we’ll modify call to $this->_exportIterateCollection(‘_exportCsvItem’, array($io));, but more accurately we’ll create new getCsvFile() method. Let’s call new method getCsvFileEnhanced() just to see how we can rewrite existing method or add new on top of existing functionality. Note, if we decide to add our new method with a same name that Magento already has in our scope, we’ll overwrite it, but if we add a new name, as we’ll do in next post, we’ll actually extend core functionality. Step2: Enhanced export – collection to a file.

You made it all the way down here so you must have enjoyed this post! You may also like:

Filter order grid by multiple ID’s Petar Sambolek
Petar Sambolek, | 14

Filter order grid by multiple ID’s

Prepared filter for Magento admin grids Ivan Galambos
Ivan Galambos, | 7

Prepared filter for Magento admin grids

Solving problems with Category tree database information Nikola Stojiljkovic
Nikola Stojiljkovic, | 19

Solving problems with Category tree database information

22 comments

  1. i want to export datas in grid created by own or phtml file to excel. how can i give action to the export button and controller action in magento admin panel.

  2. Hello,
    Great post, thank you! Could someone please tell me how to change default field delimiter from comma to semicolon?
    Thank you for your help!
    Regards
    Martin

  3. $fileName = ‘Web Report_’.date(‘Y_m_d_h_i_s’).’.xml’;
    $content = $this->getLayout()->createBlock(‘web/adminhtml_web_grid’);
    $this->_prepareDownloadResponse($fileName, $content->getXmlFile());

    Thank You For CSV Export but XML export is not working
    little help me ..

  4. I like the above post but m not sure if that is exactly what i m looking for. Actually i want to have an EXPORT to-CSV feature in purchase order in the front end for the Customer to be able to view and export their order history in CSV. Likewise, if we can export product details also in csv.

  5. I had the same problem as Rajveer. It shows in fresh installation but not in on of my existing site. I cannot afford to reinstall as site is live. Rajveer, were you able to solve the problem? Please share the solution.

    Ivan, can you please help me on this issue?

  6. I will do the same. And Thank you so much for such a nice respone. This blog and Inchoo rocks!!

  7. @Rajveer

    I’ve installed Magento 1700 & 1702 with sample data and I was able to see export button and to export everything. Try to reinstall your Magento project (or install new one).

    Good luck!

  8. I didn’t modify anything.All the things are there by default in core.
    I only tried that rewrite(which you suggested) in local and still it has not shown up.I even cleared the cache now.Still no.

    And thank you very much for so much help.I will wait for your reply tomorrow…

  9. Did you clear cache after adding modification?

    If you’ve added those 2 lines, or at least one in _prepareColumns:

    $this->addExportType('*/*/exportCsv', Mage::helper('sales')->__('CSV'));

    you should see your export button. I’ll recheck tomorrow CE 1.7 but everything that you see is basic thing and those things shouldn’t be modified.

  10. On line 145 & 146 the two lines are there which u wrote:
    $this->addExportType(‘*/*/exportCsv’, Mage::helper(‘sales’)->__(‘CSV’));
    $this->addExportType(‘*/*/exportExcel’, Mage::helper(‘sales’)->__(‘Excel XML’));
    I am sorry I understood wrong.So I think everything is intact. Why is it not coming by default?? Can there be problem with cache?? I am really confused…..Sorry I am a newbie to Magento..

  11. Everything is intact. I have also tried rewriting that grid as is mentioned in your link.But still it has not shown up.

    I have found evrything intact in app/design/adminhtml/default/default/template/widget/grid.phtml
    and same in app/code/core/Mage/Adminhtml/Block/Sales/Order/Grid.php

    However I didn’t found ‘Mage_Adminhtml_Block_Sales_Order_Grid’ around line 145 &146 .I looked in grid.phtml but its not there.Do I have to look in some other file? Please correct me…..

    However the below defintion is in app/code/core/Mage/Adminhtml/Block/Sales/Order/Grid.php around line 34:
    class Mage_Adminhtml_Block_Sales_Order_Grid extends Mage_Adminhtml_Block_Widget_Grid
    {

    public function __construct()
    {
    parent::__construct();
    $this->setId(‘sales_order_grid’);
    $this->setUseAjax(true);
    $this->setDefaultSort(‘created_at’);
    $this->setDefaultDir(‘DESC’);
    $this->setSaveParametersInSession(true);
    }

  12. In app/design/adminhtml/default/default/template/widget/grid.phtml you should see:

    <td class="export a-right">
                <img src="<?php echo $this->getSkinUrl('images/icon_export.gif') ?>" alt="" class="v-middle"/>&nbsp; <?php echo $this->__('Export to:') ?>
                <select name="<?php echo $this->getId() ?>_export" id="<?php echo $this->getId() ?>_export" style="width:8em;">
                <?php foreach ($this->getExportTypes() as $_type): ?>
                    <option value="<?php echo $_type->getUrl() ?>"><?php echo $_type->getLabel() ?></option>
                <?php endforeach; ?>
                </select>
                <?php echo $this->getExportButtonHtml() ?>
            </td>

    If you didn’t rewrite anything you should see that option by default.

    Check also Mage_Adminhtml_Block_Sales_Order_Grid around line 145. & 146. You should see there in _prepareColumns method:

            $this->addExportType('*/*/exportCsv', Mage::helper('sales')->__('CSV'));
            $this->addExportType('*/*/exportExcel', Mage::helper('sales')->__('Excel XML'));
  13. but Ivan that default option is not coming itself in sales->orders panel. Do I need to enable it from somewhere??

  14. Hi,
    i have all the codes in all the specified files but this default export to csv/xml option is not coming in sales orders panel.
    I have searched so much but nothing found for help.
    Please help…

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <blockquote cite=""> <code> <del datetime=""> <em> <s> <strike> <strong>. You may use following syntax for source code: <pre><code>$current = "Inchoo";</code></pre>.

Tell us about your project

Drop us a line. We'd love to know more about your project.