Wednesday, May 25, 2011

CakePHP CSV Export & Helper

Ok, so I made a simple CakePHP helper for generating/exporting CSV files and thought I would share how I did it.

1. Create the file /app/views/helpers/csv.php with the following code:
<?php

class CsvHelper extends AppHelper {

    var $delimiter = ',';
    var $enclosure = '"';
    var $filename = 'Export.csv';
    var $raw_data;

    function headers($content_type) {
        header("Content-type:$content_type;");
        header("Content-disposition:attachment;filename=" . $this->filename);
    }
    
    function addCell($value) {
        $this->raw_data .= $this->enclosure . $value . $this->enclosure . $this->delimiter;
    }

    function endRow() {
        $this->raw_data = substr($this->raw_data, 0, strrpos($this->raw_data, $this->delimiter)) . "\n";
    }

    function addRow($row) {
        foreach($row as $cell) {
            $this->addCell($cell);
        }
        $this->endRow();
    }
    
    function setFilename($filename) { 
        $this->filename = $filename; 
        if (strtolower(substr($this->filename, -4)) != '.csv') { 
            $this->filename .= '.csv'; 
        } 
    }
    
    function serialize($data, $add_header_row = true) {
        $row_number = 1;
        foreach($data as $listing) {
            foreach($listing as $model_name => $model_data) {
                foreach ($model_data as $field_name => $field_value) {
                    if ($row_number == 1) {
                        $headerRow[] = $model_name.".".$field_name;
                        $firstRow[] = $field_value;
                    } else {
                        $this->addCell($field_value);
                    }
                }
            }
            if ($row_number == 1) {
                $this->addRow($headerRow);
                $this->addRow($firstRow);
                unset($headerRow);
                unset($firstRow);
            } else {
                $this->endRow();
            }
            $row_number++;
        }
    }

    function download($filename = null, $content_type = "application/vnd.ms-excel") {
        if ($filename) { 
            if (is_string($filename)) $this->setFilename($filename);
        }
        $this->headers($content_type);
        echo utf8_decode($this->raw_data);
    }

    function toString() {
        header("Content-type:text/plain;");
        echo utf8_decode($this->raw_data);
    }

}

?>
2. Add the following line to the controller where you'd like to use the CSV helper:
var $helpers = array('Csv');
3. Create the file /app/views/layouts/csv/default.ctp with the following code:
<?php echo $content_for_layout; ?>
This is just a blank layout template used to contain our CSV content.

4. Populate the data and set the layout file by adding the relevant function to your controller. Example:
function export() {
    $this->Posts->recursive = -1;
    $this->set('Posts', $this->Post->find('all'));
    $this->layout = 'csv/default';
}
5. Create the file /app/views/posts/export.ctp and serialize the model data to CSV:
$csv->serialize($posts);
$csv->download("Posts.csv");
There are also some other methods in the helper that might be helpful for your purpose. They are addRow($row), addCell($value), endRow() and toString(). I'd suggest starting with calling the toString() method rather than download() and make sure the output looks as expected.

Would love to hear any feedback that people.

0 comments:

Post a Comment