CakePHP
cakephp3

CakePHPのCsvView プラグインでお手軽CSV出力

公式
https://github.com/FriendsOfCake/cakephp-csvview

以下の説明はほぼ公式のドキュメントと内容は同じです。
以下の内容はは

  • CakePHP 3.3
  • CsvView 3.2

の場合です。

主な機能

  • 配列からCSV出力
  • QueryからCSV出力
  • ヘッダー、フッタを指定化
  • CSV文字コードの指定

インストールと有効化

インストール

composer require friendsofcake/cakephp-csvview:~3.0

インストール後、config/bootstrap.phpへプラグイン読み込みを追加

config/bootstrap.php
Plugin::load('CsvView');

動作確認

以下のコードをControllerに書いて確認

public function export()
{
    $data = [
        ['a', 'b', 'c'],
        [1, 2, 3],
        ['あなた', 'と', 'わたし'],
    ];
    $_serialize = ['data'];

    $this->viewBuilder()->className('CsvView.Csv');
    $this->set(compact('data','_serialize'));
}

以下が表示されるはずです。ちなみに、CsvView.CSvのところをJsonに変える結果がjsonになります。

a,b,c
1,2,3
あなた,と,わたし

まとめると

  • $_serialize にデータの変数名を指定
  • viewBuilder()で`CSvView.CSVを指定
  • $this->setで$data$_serialize をビューに渡す

でCSVが出力できます。
また、データは複数指定する事ができ、以下のコードは同じ結果になります。

public function export()
{
    $data = [['a', 'b', 'c']];
    $data_two = [[1, 2, 3]];
    $data_three = [['あなた', 'と', 'わたし']];

    $_serialize = ['data', 'data_two', 'data_three'];

    $this->viewBuilder()->className('CsvView.Csv');
    $this->set(compact('data', 'data_two', 'data_three', '_serialize'));
}

ヘッダとフッター

ヘッダとフッターをつけるには、_header_footerに配列でセットします。

public function export()
{
    $data = [
        ['a', 'b', 'c'],
        [1, 2, 3],
        ['あなた', 'と', 'わたし'],
    ];
    $_serialize = ['data'];
    $_header = ['Column 1', 'Column 2', 'Column 3'];
    $_footer = ['Totals', '400', '$3000'];

    $this->viewBuilder()->className('CsvView.Csv');
    $this->set(compact('data','_serialize', '_header', '_footer'));
}
"Column 1","Column 2","Column 3"
a,b,c
1,2,3
あなた,と,わたし
Totals,400,$3000

ファイルでのダウンロード

大抵はCSVが画面に表示されてもあまり嬉しくなく、ファイルにダウンロードしたいと思います。以下のコードに変更します。

public function export()
{
    $data = [
        ['a', 'b', 'c'],
        [1, 2, 3],
        ['あなた', 'と', 'わたし'],
    ];
    $_serialize = ['data'];
    $_header = ['Column 1', 'Column 2', 'Column 3'];
    $_footer = ['Totals', '400', '$3000'];

    /**
     * Windows対応
     */
    $_csvEncoding = 'CP932';
    $_newline = "\r\n";
    $_eol = "\r\n";

    $this->response->download('my_file.csv');
    $this->viewBuilder()->className('CsvView.Csv');
    $this->set(compact('data', '_serialize', '_header', '_footer', '_csvEncoding', '_newline', '_eol'));
}

$this->response->download('my_file.csv') でブラウザにダウンロードを指定します。
また、大抵はExcelで開きたいと言う要望がありますので、文字コードをWindows-SJIS、改行をCRLFに変更します。

  • _csvEncoding : CSV文字の文字コード。iconvで変換。CP932がWindowsの文字コード

DBから直接CSV出力

Postsテーブルの内容から直接CSVを出力する場合。

public function export()
{
    $posts = $this->Posts->find('all');
    $_serialize = 'posts';
    $_header = ['Post ID', 'Title', 'Created'];
    $_extract = [
        'id',
        function ($row) {
            return $row['title'];
        },
        'created'
    ];

    $this->viewBuilder()->className('CsvView.Csv');
    $this->set(compact('posts', '_serialize', '_header', '_extract'));
}

_serializeにQuery、_extractに出力したいカラム名を指定すれば、Queryが実行されCSVが出力されます。

_extractは CakePHPの Hash::extract()を利用しており、callableを利用できるので値を編集できます。

複雑なCSVを出力する

_serializeにnull を指定すると、templateを利用して自前でCSVを出力できます。
以下の場合、テンプレートはcsvディレクトリにあるものが指定され、 src/Template/Posts/csv/export.ctpになります。

src/Controller/PostsController.php
public function export()
{
    $posts = $this->Post->find('all');
    $_serialize = null;
    $this->viewBuilder()->className('CsvView.Csv');
    $this->set(compact('posts', '_serialize'));
}

以下のように、CSVのデータ部分のみを出力するTemplateを作成します。

src/Template/Posts/csv/export.ctp
foreach ($posts as $post) {
    echo $post->id . ',' . $post->title . ',' . $post->created . PHP_EOL;
}

CSV制御オプション

CSVの出力を変更するのに、以下の変数が利用できます。

変数名 デフォルト 説明
_delimiter ',' データ区切り文字
_enclosure '"' データのクオート文字
_eol "\n" データ改行文字
_newline "\n" 新規行
_bom false BOMを出力するか
_null '' データがnullの表示値
_dataEncoding 'UTF-8' データの文字コード。iconvを利用
_csvEncoding 'UTF-8' csv表示の文字コード。iconvを利用