[Zend Framework] Zend_Controller: ContextSwitch アクションヘルパーを利用して、ひとつのコントローラー/アクションでhtml, xml, json, csv出力に対応する

いままではcsv出力のために同じような内容のactionを書いていたわけですが、何かしら効率的な方法があるのではないかと調べてみたらありました。
ZendFrameworkのバージョンは、1.12.3です。

[markdown]

公式を眺めて探してみると、ContextSwitch アクションヘルパーをつかうと希望する処理ができそう。
こちらを参考にさせて頂きました。

> – [アクションヘルパー – Zend_Controller – Zend Framework](http://framework.zend.com/manual/1.12/ja/zend.controller.actionhelpers.html#zend.controller.actionhelpers.contextswitch)
> – [AJAX機能とのスムーズな連携 – Zend_Controllerの新しいアクションヘルパー – (2/4):CodeZine](http://codezine.jp/article/detail/5631?p=2)
> – [php – export csv in zend framework – Stack Overflow](http://stackoverflow.com/questions/1136264/export-csv-in-zend-framework)
> – [[Zend Framework] Zend_ControllerアクションヘルパーのContextSwitch – wadslog](http://wadslab.net/2008/04/zend_controller-3/)
> – [Zend Framework – PIB – Seesaa Wiki(ウィキ)](http://wiki.livedoor.jp/kou1okada/d/Zend%20Framework)
> – [zend framework – how do I set up a contextSwitch to generate a csv file – Stack Overflow](http://stackoverflow.com/questions/7188636/how-do-i-set-up-a-contextswitch-to-generate-a-csv-file)
> – [controller – Download files with zend contextSwitch() Action Helper – Stack Overflow](http://stackoverflow.com/questions/6167336/download-files-with-zend-contextswitch-action-helper)

## ソース

いろいろと実装方法があるようなんですが、コントローラーのinitで設定してみました。
コントローラー内のcsActionで利用する前提です。

追記:2013/06/06
よそで使い回すときに後述のテンプレート内よりも、contextSwitch内でヘッダーを定義した方が便利だったので、下記ソースを変更しました。

“`php:csController.php
public function init() {
$contextSwitch = $this->_helper->getHelper(‘contextSwitch’);
$contextSwitch->addActionContext(‘cs’, ‘xml’);
$contextSwitch->addActionContext(‘cs’, ‘json’);
$filename = time() . ‘.csv’;
$contextSwitch->addContext(‘csv’,
array(‘suffix’ => ‘csv’,
‘headers’ => array(‘Content-Type’ => ‘application/csv’,
‘Content-Disposition’ => ‘attachment; filename=”‘.$filename.'”‘,
‘Pragma’ => ‘public’,
‘Expires’ => ‘0’,
‘Cache-control’ => ‘public’)
));
$contextSwitch->addActionContext(‘cs’, ‘csv’);
$contextSwitch->initContext();
}
“`

xmlとjsonは、標準で対応しているので「addActionContext」するだけで使えます。
最初のcsでcsActionで使うことを示します。

その他のフォーマットは、独自に作成できます。
「addContext」でcsvという名前のフォーマットを作成し、拡張子とヘッダーを定義しています。
追加の仕方は同じく「addActionContext」で可能です。

actionはいつも通りviewに値を渡せば良いだけでした。
コントローラーに記述を加える必要はなく、addActionContextで指定したviewファイルを用意するだけです。

“`php:csAction
public function csAction() {
$results = array(
array(‘title’ => ‘路傍の石’, ‘author’ => ‘山本有三’, ‘pub’ => ‘1937’),
array(‘title’ => ‘羅生門’, ‘author’ => ‘芥川龍之介’, ‘pub’ => ‘1915’),
array(‘title’ => ‘城の崎にて’, ‘author’ => ‘志賀直哉’, ‘pub’ => ‘1917’)
);
$this->view->assign(‘results’,$results);
}
“`

上記の場合、 cs.phtml でhtml(ブラウザ表示)を担当させます。

“`php:cs.phtml
results as $row): ?>
escape($row[‘title’]) ?> : escape($row[‘author’]) ?> (escape($row[‘pub’]) ?>)

“`

いつも通り `http://[サーバ]/[コントローラ名]/cs` で下記のように表示されます。

[![cs 2013-05-29
22-21-06](https://www.d-wood.com/wpmt/wp-content/uploads/2013/05/cs-2013-05-29-22-21-06.png)](https://www.d-wood.com/wpmt/wp-content/uploads/2013/05/cs-2013-05-29-22-21-06.png)

xmlには、cs.xml.phtml というファイルを用意します。
jsonは、標準ではviewファイルなしで出力できます。
追加した定義は、作成したコンテキスト名のviewテンプレートを作ればOKです。
この場合、cs.csv.phtml を用意します。

“`php:cs.csv.phtml
results as $row) {
$data = $this->escape($row[‘title’]) . ‘,’
.$this->escape($row[‘author’]) . ‘,’
.$this->escape($row[‘pub’]) . PHP_EOL;
echo mb_convert_encoding($data, “SJIS”, “UTF-8”);
}
“`

csvに必要なファイル名や、日本語変換などもこちらにまとめて書けるので、コントローラーはすっきりとなります。

追記:2013/06/06
よそで使い回すときに上記のテンプレート内よりも、前述のcontextSwitch内でヘッダーを定義した方が便利だったので変更しました。

`http://[サーバ]/[コントローラ名]/cs?format=csv` でアクセスするとファイルがダウンロードされます。

[![cs 2013-05-29
22-22-57](https://www.d-wood.com/wpmt/wp-content/uploads/2013/05/cs-2013-05-29-22-22-57.png)](https://www.d-wood.com/wpmt/wp-content/uploads/2013/05/cs-2013-05-29-22-22-57.png)

Mac OS Xで扱う場合、UTF-8のままの方が都合が良いわけですが、いちおうSJISに変換しました。

## CSVの仕様

このあたりも調べるとダブルクォーテーションの対応とか、いろいろありますね。

– [CSVファイルフォーマットの解説:CodeZine](http://codezine.jp/article/detail/2364)
– [PHPでのCSV出力について : アシアルブログ](http://blog.asial.co.jp/721)
– [floatingdays: PHPで CSVをダウンロードするための参考サイトとサンプルコード](http://fdays.blogspot.jp/2010/12/php-csv.html)
– [PHPExcel – Home](http://phpexcel.codeplex.com/)

fputcsv関数を使うのがよさそうですが、今回のようなケースではどういった実装が良いのかまだイメージできない感じです。

修行不足ですね。

追記:2013/07/24
fputcsv がどんなものかを試してみました。

> [Zend_Layout – fputcsv を利用して、配列をCSVに変換/ダウンロード | deadwood](https://www.d-wood.com/blog/2013/07/24_4349.html)

[/markdown]