Yii 1.1: Exporting CGridView results to CSV file

19 followers

How to create a simple CSV exporting for CGridView search results

A few days ago, i worked for CGridView exporting functional for my client. He asked me to create a simple exporting to a CSV file a CGridView search results.

That's very easy. Let's start...

Create an export button in your template.

I just created an Export Button above my grid.

<?php echo CHtml::button('Export', array('id'=>'export-button','class'=>'span-3 button')); ?>

Extending CGridView javascript code.

This javascript code does: 1. bind an .export() execution by clicking an export button, defined above. 2. extinds an yiiGridView javascript class for function update.

$('#export-button').on('click',function() {
    $.fn.yiiGridView.export();
});
$.fn.yiiGridView.export = function() {
    $.fn.yiiGridView.update('dates-grid',{ 
        success: function() {
            $('#dates-grid').removeClass('grid-view-loading');
            window.location = '". $this->createUrl('exportFile')  . "';
        },
        data: $('.search-form form').serialize() + '&export=true'
    });
}

Add actions to your controller

Because CGridView always uses for update the same action as initial render CGridView we need to use this action for our purpose in a next way: Add next peace of code at the top of action your CGridView render.

if(Yii::app()->request->getParam('export')) {
    $this->actionExport();
    Yii::app()->end();
}

It will run our actionExport if GET['export'] set.

Action Export (will use CGridView dataprovider defined in a model()->search())

public function actionExport()
{
    $fp = fopen('php://temp', 'w');
 
    /* 
     * Write a header of csv file
     */
    $headers = array(
        'd_date',
        'client.clientFirstName',
        'client.clientLastName',
        'd_time',
    );
    $row = array();
    foreach($headers as $header) {
        $row[] = MODEL::model()->getAttributeLabel($header);
    }
    fputcsv($fp,$row);
 
    /*
     * Init dataProvider for first page
     */
    $model=new MODEL('search');
    $model->unsetAttributes();  // clear any default values
    if(isset($_GET['MODEL'])) {
        $model->attributes=$_GET['MODEL'];
    }
    $dp = $model->search();
 
    /*
     * Get models, write to a file, then change page and re-init DataProvider
     * with next page and repeat writing again
     */
    while($models = $dp->getData()) {
        foreach($models as $model) {
            $row = array();
            foreach($headers as $head) {
                $row[] = CHtml::value($model,$head);
            }
            fputcsv($fp,$row);
        }
 
        unset($model,$dp,$pg);
        $model=new MODEL('search');
        $model->unsetAttributes();  // clear any default values
        if(isset($_GET['MODEL']))
            $model->attributes=$_GET['MODEL'];
 
        $dp = $model->search();
        $nextPage = $dp->getPagination()->getCurrentPage()+1;
        $dp->getPagination()->setCurrentPage($nextPage);
    }
 
    /*
     * save csv content to a Session
     */
    rewind($fp);
    Yii::app()->user->setState('export',stream_get_contents($fp));
    fclose($fp);
}

Last action to download CSV file

public function actionGetExportFile()
{
    Yii::app()->request->sendFile('export.csv',Yii::app()->user->getState('export'));
    Yii::app()->user->clearState('export');
}

Hope everything is clear. Enjoy your Yii CGridView.

Total 9 comments

#14156 report it
EdmYiiUser at 2013/07/23 09:21am
Why two requests?

Why sending an ajax request and saving the filter in the setState and then doing another plain request to send the file? Can't we do this with only one request?

#12250 report it
CTala at 2013/03/09 04:18pm
Thanks Steve for the amswer.

I just got confused because we are not adding it ass a Yii Add Script function.

So this JS I just need to put in the javascript part of the main layout in my case.

#12249 report it
SteveD at 2013/03/09 04:02pm
The JavaScript goes...

@CTala: The JavaScript goes in the same file as the first code snippet (the one that makes the Export button). That is, in the same view file that contains the CGridView. It makes the button work.

#12246 report it
CTala at 2013/03/09 02:17pm
Where

Where did you add that javaScript ? +

By the way, thanks for the how to !

#9736 report it
Binc at 2012/09/07 11:54am
Thanks!

Instead of dropping an extension somewhere, this article shows me how the mechanisms work, so I can adapt it to my needs easily.

Just a small thing: the last action should be named 'actionExportFile' instead of 'actionGetExportFile' or else the javascript at the top should be adapted.

#8957 report it
SteveD at 2012/07/09 04:11pm
Unnecessary pagination loop

When I tried this code I kept getting an infinite loop accessing the data. Then I realized that the entire outer loop that handles pagination isn't needed. Instead, just set the pagination of the CActiveDataProvider returned by the model search method to false.

In other words, insert this after the first call of the search function:

$dp->setPagination(false);

Then eliminate the outer loop and all the pagination stuff. So instead of this block of code:

$dp = $model->search();
 
/*
* Get models, write to a file, then change page and re-init DataProvider
* with next page and repeat writing again
*/
while($models = $dp->getData()) {
foreach($models as $model) {
    $row = array();
    foreach($headers as $head) {
    $row[] = CHtml::value($model,$head);
    }
    fputcsv($fp,$row);
}
 
unset($model,$dp,$pg);
$model=new MODEL('search');
$model->unsetAttributes();  // clear any default values
if(isset($_GET['MODEL']))
    $model->attributes=$_GET['MODEL'];
 
$dp = $model->search();
$nextPage = $dp->getPagination()->getCurrentPage()+1;
$dp->getPagination()->setCurrentPage($nextPage);
}

We're just left with this:

$dp = $model->search();
$dp->setPagination(false);
 
/*
 * Get models, write to a file
 */
 
$models = $dp->getData();
foreach($models as $model) {
    $row = array();
    foreach($headers as $head) {
        $row[] = CHtml::value($model,$head);
    }
    fputcsv($fp,$row);
}
#7028 report it
RusAlex at 2012/02/20 04:28am
this article not how to write an extension

is about how to make csv exporting. it's for understanding how to create it fast. When someone will need alot of exporting, he will write a class for this.

#7026 report it
phreak at 2012/02/20 04:22am
EExcelView

Well, I just use my extension EExcelView to do this :)

#7025 report it
stereochrome at 2012/02/20 04:20am
..

i've built something similar in one of my yii-apps. it gets a bit annoying if you need lots of csv exports because there is lots of code to write and maintain which does almost exactly what the corresponding cgridview does only using another data export format. maybe an extension to cgridview would be the better way.

Leave a comment

Please to leave your comment.

Write new article