Skip to content

Instantly share code, notes, and snippets.

@ogero
Created September 4, 2017 19:53
Show Gist options
  • Save ogero/785c8cfab343575aedf57d89d0efe86d to your computer and use it in GitHub Desktop.
Save ogero/785c8cfab343575aedf57d89d0efe86d to your computer and use it in GitHub Desktop.
Export grid to csv
<?php
/**
* GridView Export Behavior
* Requirements:
* Yii 1.1.3 or greater
* An explicit rule on the action that exports the csv like: '<controller:\w+>/<action:\w+>' => '<controller>/<action>'
* Usage:
* <pre>
* //(Step 1) Add this behavior to the controller like
public function behaviors() {
return array(
'exportableGrid' => array(
'class' => 'application.components.ExportableGridBehavior',
));
}
* //(Step 2) On actionAdmin() , add this line before render('admin') method
if ($this->isExportRequest()) {
$this->exportCSV(array('EXPORT DATE ',date('Y-m-d')), null, false);
$this->exportCSV($model, array_keys($model->attributeLabels()), false, 3);
$this->exportCSV($model->search(), array('id', 'comment', 'date:date', 'published:boolean:Comment approved', 'user.name', 'user.id'));
}
* //(Step 3) On the view that renders the grid, link some DOM element to the export action
$this->registerExportGridScript();
* //Then on any element add onClick="exportGrid('#gridId')"
* //Optionally add your own params to the export action like onClick="exportGrid('#gridId','myUrlEncodedKey=myUrlEncodedValue')"
* // (Optional) If you need to export a very large dataset, you need to add this before exportCSV()
set_time_limit(0);
* </pre>
* @version 2.2
* @author Geronimo Oñativia / https://pixdart.com
* @link http://www.yiiframework.com/extension/exportablegridbehavior
*/
class ExportableGridBehavior extends CBehavior {
public $exportParam = 'export'; //Param to be appended on url to fire an export
public $csvDelimiter = ','; //Columns delimiter
public $csvEnclosure = '"'; //Enclosure used on data when needed
public $filename = 'export.csv'; //Filename suggested to user when downloading
public $addUTF8BOM = true; //Adds \xEF\xBB\xBF to output
private $headersSent = false;
private $_formatter = null;
/**
* @return CFormatter the formatter instance. Defaults to the 'format' application component.
*/
protected function getFormatter() {
if ($this->_formatter === null)
$this->_formatter = Yii::app()->format;
return $this->_formatter;
}
/**
* Fetch from an array of strings, the column name, type and header
* @param type $columns ['enabled:boolean:LoginEnabled',]
* @return array array ie [[name=>enabled,type=>boolean,header=>LoginEnabled],]
*/
protected function createColumnsArray($columns) {
$columnsArray = [];
if (is_array($columns)) {
foreach ($columns as $text) {
if (!preg_match('/^([\w\.]+)(:(\w*))?(:(.*))?$/', $text, $matches))
throw new CException(Yii::t('zii', 'The attributes must be specified in the format of "Name:Type:Label", where "Type" and "Label" are optional.'));
$column = ['name' => $matches[1], 'type' => 'raw'];
if (isset($matches[3]) && $matches[3] !== '')
$column['type'] = $matches[3];
if (isset($matches[5]))
$column['header'] = $matches[5];
$columnsArray[] = $column;
}
}
return $columnsArray;
}
/**
* @param mixed $data A Traversable of CModel or a CModel where data will be fetch from
* @param array $columns Attribute names of CModel to be exported.
* @param bool $endApplication Application will be ended if true. false to keep going and export more data. Defautls to TRUE.
* @param integer $endLineCount Number of newlines to append below this data. Defaults to 0.
*/
public function exportCSV($data, $columns = null, $endApplication = true, $endLineCount = 0) {
$this->sendHeaders();
$fileHandle = fopen('php://output', 'w');
$columnsArray = $this->createColumnsArray($columns);
if ($data instanceof CActiveDataProvider) {
$this->csvRowHeaders($fileHandle, $columnsArray, $data->model);
$this->csvRowModels($fileHandle, new CDataProviderIterator($data, 150), $columnsArray);
} else if (is_array($data) && current($data) instanceof CModel) {
$this->csvRowHeaders($fileHandle, $columnsArray, current($data));
$this->csvRowModels($fileHandle, $data, $columnsArray);
} else if (is_array($data) && is_string(current($data))) {
fputcsv($fileHandle, $data, $this->csvDelimiter, $this->csvEnclosure);
} else if ($data instanceof CModel) {
$this->csvModel($fileHandle, $data, $columnsArray);
}
fprintf($fileHandle, str_repeat("\n", $endLineCount));
fclose($fileHandle);
if ($endApplication) {
Yii::app()->end(0, false);
exit(0);
}
}
private function csvRowHeaders($fileHandle, $columnsArray, CModel $model) {
$row = [];
foreach ($columnsArray as $column) {
$row[] = (isset($column['header']) ? $column['header'] : $model->getAttributeLabel($column['name']));
}
fputcsv($fileHandle, $row, $this->csvDelimiter, $this->csvEnclosure);
}
private function csvRowModels($fileHandle, Traversable $cModels, $columnsArray) {
foreach ($cModels as $cModel) {
$row = [];
foreach ($columnsArray as $column) {
$value = CHtml::value($cModel, $column['name']);
$row[] = ($value == null ? '' : $this->getFormatter()->format($value, $column['type']));
}
fputcsv($fileHandle, $row, $this->csvDelimiter, $this->csvEnclosure);
}
}
private function csvModel($fileHandle, CModel $cModel, $columnsArray) {
foreach ($columnsArray as $column) {
$row = [];
$row[] = (isset($column['header']) ? $column['header'] : $cModel->getAttributeLabel($column['name']));
$value = CHtml::value($cModel, $column['name']);
$row[] = ($value == null ? '' : $this->getFormatter()->format($value, $column['type']));
fputcsv($fileHandle, $row, $this->csvDelimiter, $this->csvEnclosure);
}
}
private function sendHeaders() {
if ($this->headersSent === false) {
$this->headersSent = true;
// disable caching
$now = gmdate("D, d M Y H:i:s");
header("Expires: Tue, 01 Jan 2013 00:00:00 GMT");
header("Cache-Control: max-age=0, no-cache, must-revalidate, proxy-revalidate");
header("Last-Modified: {$now} GMT");
// force download
header("Content-Type: application/force-download");
header("Content-Type: application/octet-stream");
header("Content-Type: application/download");
// disposition / encoding on response body
header("Content-Disposition: attachment;filename=\"{$this->filename}\"");
header("Content-Transfer-Encoding: binary");
if ($this->addUTF8BOM)
print "\xEF\xBB\xBF";
}
}
public function isExportRequest() {
return Yii::app()->request->getParam($this->exportParam, false);
}
/**
* Registers the export script
* To export a grid call function js:exportGrid('#myGrid')
* Optionally add an extra parameter like js:exportGrid('#myGrid','myUrlEncodedKey=myUrlEncodedValue')
*/
public function registerExportGridScript() {
Yii::app()->clientScript->registerScript('ExportableGridBehaviorScript', <<<SCRIPT
function exportGrid(gridSelector,extraParam) {
extraParam = typeof extraParam !== 'undefined' ? '&'+extraParam : '';
var downloadUrl=$(gridSelector).yiiGridView('getUrl');
downloadUrl+=((downloadUrl.indexOf('?')==-1)?'?':'&');
downloadUrl+='{$this->exportParam}=1';
downloadUrl+=extraParam;
window.open( downloadUrl ,'_blank');
}
SCRIPT
, CClientScript::POS_END);
}
}
?>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment