Вход Регистрация
Файл: protected/extensions/ECSVExport.php
Строк: 419
<?php

/**
 * export a csv file (string) from given CSqlDataProvider
 * usage in your controller:
 * Yii::import('ext.CSVExport');
 * $provider = YourClass::model()->createCSqlProvider()
 * or
 * $provider = Yii::app()->db->creatCommand(...)->queryAll();
 * $csv = new ECSVExport($provider);
 * $content = $csv->toCSV();                    
 * Yii::app()->getRequest()->sendFile($filename, $content, "text/csv", false);
 * exit();
 * 
 * You can also do this now:
 * $cmd = Yii::app()->db->createCommand("SELECT * FROM track_test LIMIT 10");
 * $csv = new ECSVExport($cmd);        
 * $csv->setOutputFile($outputFile);
 * $csv->toCSV();
 *
 * @author Kenrick Buchanan
 * @version 0.6.6
 */

class ECSVExport
{
    
/**
     * show column headers in csv file
     * @var boolean $includeColumnHeaders
     */
    
public $includeColumnHeaders true;
    
    
/**
     * sometimes excel chokes on newlines in string, this will fix that
     * @var boolean $replaceNewLines strip newlines from each column
     */
    
public $stripNewLines true;
    
    
/**
     * run through whole resultset, appending to output stream, using paging (if on)
     * @var boolean $exportFull
     */
    
public $exportFull true;
    
    
/**
     * convert activedata provider to a cdbcommand for speed
     * @var boolean $convertActiveDataProvider
     */
    
public $convertActiveDataProvider true;
    
    
/**
     *
     * string filename
     * @var string $_outputFile 
     */
    
protected $_outputFile;
    
    
/**
     * stream pointer
     * @var resource $_filePointer
     */
    
protected $_filePointer;
    
    
/**
     * data provider that will generate or contain resultset
     * @var mixed CSqlDataProvider|Array|CActiveDataProvider|CDbCommand $_dataProvider
     */
    
protected $_dataProvider;
    
    
/**
     * per row callable function
     * @var callable $_callback
     */    
    
protected $_callback;
    
    
/**
     * csv headers
     * @var array $_headers 
     */
    
protected $_headers = array();
    
    
/**
     *
     * columns to exclude from final file
     * @var array $_exclude 
     */
    
protected $_exclude = array();
    
    
/**
     * column delimiter
     * @var string $_delimiter 
     */
    
protected $_delimiter ",";
    
    
/**
     * string to enclose fields when delimiter is found in field
     * @var string $_enclosure 
     */
    
protected $_enclosure '"';
    
    
/**
     * determine if overwriting output file or just append to existing
     * $this->setToAppend()
     * @var boolean
     */
    
protected $_appendCsv false;
    
    
/**
     *
     * @param mixed $dataProvider array|CSqlDataProvider|CActiveDataProvider|CDbCommand
     * @param boolean $exportFull
     * @param boolean $includeColumnHeaders
     * @param string $delimiter
     * @param string $enclosure 
     */    
    
public function __construct($dataProvider$exportFull=true$includeColumnHeaders=true$delimiter=null$enclosure=null
    {
        
$this->_dataProvider $dataProvider;
        
$this->exportFull = (bool) $exportFull;
        
$this->includeColumnHeaders = (bool) $includeColumnHeaders;
        if(
$delimiter$this->_delimiter $delimiter;
        if(
$enclosure$this->_enclosure $enclosure;
    }
    
    
/**
     * get data provider
     * @return mixed $this->_dataProvider
     */
    
public function getDataProvider()
    {
        return 
$this->_dataProvider;
    }
    
    
/**
     * call this function to not force CActiveDataProvider to be converted to command
     * for speed and memory at the expense of losing the with() functionality
     *
     * @return ECSVExport 
     */
    
public function dontConvertProvider()
    {
        
$this->convertActiveDataProvider false;
        return 
$this;
    }
    
    
/**
     * sets flag to have it append to file instead of just overwriting it
     * @return void 
     */
    
public function setToAppend()
    {
        
$this->_appendCsv true;
        return 
$this;
    }
    
    
/**
     *
     * set csv delimiter, defaults to ,
     * @param type $delimiter
     * @return ECSVExport 
     */
    
public function setDelimiter($delimiter)
    {
        
$this->_delimiter $delimiter;
        return 
$this;
    }
    
    
/**
     * get current delimiter
     * @return type 
     */
    
public function getDelimiter()
    {
        return 
$this->_delimiter;
    }
    
    
/**
     *
     * set csv enclosure, defaults to "
     * @param type $enclosure
     * @return ECSVExport 
     */
    
public function setEnclosure($enclosure)
    {
        
$this->_enclosure $enclosure;
        return 
$this;
    }
    
    
/**
     *
     * @return string
     */
    
public function getEnclosure()
    {
        return 
$this->_enclosure;
    }
    
    
/**
     *
     * set filename of csv file you want to create
     * @param type $filename
     * @return ECSVExport 
     */
    
public function setOutputFile($filename)
    {
        
$this->_outputFile $filename;
        return 
$this;
    }
    
    
/**
     * get output file
     * @return string
     */
    
public function getOutputFile()
    {
        return 
$this->_outputFile;
    }
       
    
/**
     * function to be called for each row in set
     * @param mixed callable|array $callback
     * @return ECSVExport
     * @throws Exception on uncallable variable
     */
    
public function setCallback($callback)
    {
        if(
is_callable($callback)) {
            
$this->_callback $callback;
            return 
$this;
        } else {
            throw new 
Exception('Callback must be callable. Duh.');
        }
    }
    
    
/**
     * get per row function    
     * @return mixed $this->_callback
     */
    
public function getCallback()
    {
        return 
$this->_callback;
    }
    
    
/**
     * existing column names remapped to other strings resultcolumn=>new name
     * @param array $headers
     * @return ECSVExport 
     */
    
public function setHeaders(array $headers)
    {
        
$this->_headers $headers;
        return 
$this;
    }
    
    
/**
     * get current csv headers
     * @return array $this->_headers
     */
    
public function getHeaders()
    {
        return 
$this->_headers;
    }
    
    
/**
     *
     * @param string $key
     * @param string $value
     * @return ECSVExport 
     */
    
public function setHeader($key$value)
    {
        
$this->_headers[$key] = $value;
        return 
$this;
    }
    
    
/**
     *
     * @param type $noshow
     * @return ECSVExport 
     */
    
public function setExclude($noshow)
    {
        if(
is_array($noshow)) {
            
$this->_exclude $noshow;
            return 
$this;
        } else {
            
$this->_exclude[] = (string) $noshow;
        }
    }
    
    
/**
     * get excluded fields
     * @return array $this->_exclude
     */
    
public function getExclude()
    {
        return 
$this->_exclude;
    }
    
    
/**
     * turn off going through whole resultset, taking current page into account
     * @return ECSVExport 
     */
    
public function exportCurrentPageOnly()
    {
        
$this->exportFull false;
        return 
$this;
    }
    
    
/**
     * create a csv string, or file if $outputFile is set
     * 
     * @param string $outputFile
     * @param string $delimiter
     * @param string $enclosure
     * @param boolean $includeHeaders
     * @return mixed string|boolean|integer csv string when no outputFile is specified
     * boolean if the writing failed, or integer of num bytes written to file 
     */
    
public function toCSV($outputFile=null$delimiter=null$enclosure=null$includeHeaders=true)
    {
        
// check that data provider is something useful
        
$isGood false;
        
        if(
$this->_dataProvider instanceof CActiveDataProvider) {
            
$isGood true;
        }
        
        if(
$this->_dataProvider instanceof CSqlDataProvider) {
            
$isGood true;
        }
        
        if(
$this->_dataProvider instanceof CDbCommand) {
            
$isGood true;
        }
        
        if(
is_array($this->_dataProvider)) {
            
$isGood true;
        }
        
        if(!
$isGood) {
            throw new 
Exception('Bad data provider given as source to '.__CLASS__);
        }
        
        if(
$outputFile !== null) {
            
$this->setOutputFile($outputFile);
        }
        
        if(!
$includeHeaders) {
            
$this->includeColumnHeaders false;
        }
        
        if(
$delimiter !== null) {
            
$this->_delimiter $delimiter;
        }
        
        if(
$enclosure !== null) {
            
$this->_enclosure $enclosure;
        }
        
        
// create file pointer
        
$this->_filePointer =  fopen("php://temp"'w');
        
$this->_writeData();        
        
rewind($this->_filePointer);
        
        
// make sure you can write to file!
        
if($this->_outputFile !== null) {
            
// write stream to file
            
return $this->_appendCsv file_put_contents($this->_outputFile$this->_filePointerFILE_APPEND LOCK_EX
                                     : 
file_put_contents($this->_outputFile$this->_filePointerLOCK_EX);
            
        } else {
            return 
stream_get_contents($this->_filePointer);    
        }
    }
    
    
/**
     * where the magic happens. depending on type of dataProvider, it uses
     * different methods to get the data efficiently and to write to file
     * pointer in memory. the most effecient is either a small array or
     * by just passing in a CDbCommand instance 
     * @throws Exception - no data found
     */
    
protected function _writeData()
    {        
        
$firstTimeThrough true;        
        if(
$this->_dataProvider instanceof CActiveDataProvider) {            
            if(
$this->convertActiveDataProvider) {
                
$criteria $this->_dataProvider->getCriteria();
                
$model $this->_dataProvider->model;
                
$criteria $model->getCommandBuilder()
                                    ->
createCriteria($criteria,array());
                
$this->_dataProvider $model->getCommandBuilder()
                                             ->
createFindCommand($model->getTableSchema(), 
                                                                 
$criteria);                                
                unset(
$model$criteria);
            } else {
                
// suggested implementation from marcovtwout    
                
$models $this->_dataProvider->getData();
                
$dataReader = array();
                
$attributes $this->_dataProvider->model->getMetaData()->columns;
                
// since we are already looping through results, don't bother
                // passing results to _loopRow, just write it here.
                
foreach ($models as &$model) {
                    
$row = array();
                    
                    foreach (
$attributes as $attribute => $col) {
                        
$row[$attribute] = $model->{$attribute};
                    }
                    
                    if(
$firstTimeThrough) {
                        
$this->_writeHeaders($row);
                        
$firstTimeThrough false;                    
                    }
                    
$this->_writeRow($row);
                }
                unset(
$models$attributes);
                return;
            }            
        }
        
        if(
$this->_dataProvider instanceof CSqlDataProvider) {            
            if(
$this->exportFull) {
                
$this->_dataProvider->setId('csvexport');
                
$this->_dataProvider->getPagination()->setItemCount($this->_dataProvider->getTotalItemCount());                
                
$pageVar $this->_dataProvider->getPagination()->pageVar;
                
$_GET[$pageVar] = 0;                
                
$totalPages $this->_dataProvider->getPagination()->getPageCount();                
                
$this->setToAppend();
                for(
$i=1$i<=$totalPages$i++) {                    
                    
$_GET[$pageVar] = $i;
                    
$this->_dataProvider->getPagination()->setCurrentPage($i);                                        
                    
$_getData $this->_dataProvider->getData();
                    
$this->_loopRows($_getData);                    
                    
$this->includeColumnHeaders = !(bool) $i;
                }                
            } else {
                
$this->_loopRows($this->_dataProvider->getData());
            }
                        
            return;
        }
        
        if(
$this->_dataProvider instanceof CDbCommand) {
            
$dataReader $this->_dataProvider->query();  
            
$this->_loopRows($dataReader);            
            return;
        }
        
        if(
is_array($this->_dataProvider)) {
            
$this->_loopRows($this->_dataProvider);
            return;
        } 
        
        
// if program made it this far something happened
        
throw new Exception('Data source failed to retrieve data, are you sure you passed something useable?');
    }
    
    
/**
     * loop through result set
     * @param mixed CDbDataReader|array $dp 
     */
    
public function _loopRows(&$dp)
    {
        
$firstTimeThrough true;
        if(
$dp instanceof CDbDataReader) {
            while((
$row $dp->read()) !== false) {
                if(
$firstTimeThrough) {
                    
$this->_writeHeaders($row);
                    
$firstTimeThrough false;                    
                }
                
$this->_writeRow($row);
            }
        } else {
            
$total count($dp);
            for(
$i=0$i<$total$i++) {
                if(
$firstTimeThrough) {
                    
$this->_writeHeaders($dp[$i]);
                    
$firstTimeThrough false;                    
                }
                
$this->_writeRow($dp[$i]);
            }
        }
    }
    
    
/**
     * Write headers to csv file, taking into account string replacements and exclusions     
     * @param array $row
     * @return void 
     */
    
protected function _writeHeaders($row)
    {
        if(!
$this->includeColumnHeaders) {
            return;
        }
        
        if(
$row instanceof CActiveRecord) {
            
$headers array_keys($row->getAttributes());
        } else {
            
$headers array_keys($row);
        }
                
        
// remove excluded
        
if(count($this->_exclude) > 0) {
            foreach(
$this->_exclude as $e) { 
                
$key array_search($e$headers);
                if(
$key !== false) {                    
                    unset(
$headers[$key]);                        
                }
            }
        }            
        
        if(
count($this->_headers) > 0) {
            foreach(
$headers as &$header) {
                if(
array_key_exists($header$this->_headers)) {
                    
$header $this->_headers[$header];             
                }
            }
        }                
        
        
fputcsv($this->_filePointer$headers$this->_delimiter$this->_enclosure);
    }
    
    
/**
     * Write array row to current {$this->_filePointer}, taking into account exclusions
     * @param array $row 
     * @return void
     */
    
public function _writeRow($row)
    {
        if(
$row instanceof CActiveRecord) {
            
$row $row->getAttributes();
        }
        
// remove excluded
        
if(count($this->_exclude) > 0) {
            foreach(
$this->_exclude as $e) { 
                if(
array_key_exists($e$row)) {
                    unset(
$row[$e]);
                }
            }
        }
        
        if(
$this->stripNewLines) {            
            
array_walk($row, array('ECSVExport','lambdaFail'));
        }
               
        if(isset(
$this->_callback) && $this->_callback) {
            
fputcsv($this->_filePointercall_user_func($this->_callback$row), $this->_delimiter$this->_enclosure);                       
        } else {
            
fputcsv($this->_filePointer$row$this->_delimiter$this->_enclosure);
        }
        unset(
$row);
    }
    
    public static function 
lambdaFail(&$value$key)
    {
        
$value str_replace("rn"," "$value);
    }
}
Онлайн: 2
Реклама