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に書いて確認

```php:
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が出力できます。
また、データは複数指定する事ができ、以下のコードは同じ結果になります。

```php:
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```に配列でセットします。

```php:
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が画面に表示されてもあまり嬉しくなく、ファイルにダウンロードしたいと思います。以下のコードに変更します。


```php:
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を出力する場合。

```php:
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()](http://book.cakephp.org/3.0/en/core-libraries/hash.html)を利用しており、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を利用|