CakePHP

CakePHP 1.3.xで CSVファイルのエクスポート機能を作ってみた

2015/01/11

過去に CakePHP1.3 で作成したシステムにCSVファイルのエクスポート機能を追加してほしいときたので、機能追加してみました。
忘備録も兼ねたポストで次回に備えたいと思います。

『CSV Helper』でCSVを作成する

今回は CakePHPのバージョンが 1.3.22だったので、ヘルパーである『CSV Helper』を使ってみたいと思います。

ダウンロードというか、公開されているページはこちら。
CSV Helper (PHP 5) :: The Bakery: Everything CakePHP

CsvHelper

公開されているものを転載します。
最後の「?>」は要らないので、書きません。

[php]
clear();
}

function clear() {
$this->line = array();
$this->buffer = fopen('php://temp/maxmemory:'. (5*1024*1024), 'r+');
}

function addField($value) {
$this->line[] = $value;
}

function endRow() {
$this->addRow($this->line);
$this->line = array();
}

function addRow($row) {
fputcsv($this->buffer, $row, $this->delimiter, $this->enclosure);
}

function renderHeaders() {
header("Content-type:application/vnd.ms-excel");
header("Content-disposition:attachment;filename=".$this->filename);
}

function setFilename($filename) {
$this->filename = $filename;
if (strtolower(substr($this->filename, -4)) != '.csv') {
$this->filename .= '.csv';
}
}

function render($outputHeaders = true, $to_encoding = null, $from_encoding = "auto") {
if ($outputHeaders) {
if (is_string($outputHeaders)) {
$this->setFilename($outputHeaders);
}
$this->renderHeaders();
}
rewind($this->buffer);
$output = stream_get_contents($this->buffer);
if ($to_encoding) {
$output = mb_convert_encoding($output, $to_encoding, $from_encoding);
}
return $this->output($output);
}
}
[/php]

アクションを作成

ダウンロード機能を実装するコントローラーに、ダウンロード用アクションを作成します。
そのまんま、download としてみました。

ヘルパー設定に「Csv」を記述するのを忘れずに。

サンプルのアクションは、都道府県と、欲しいデータ(ユーザ)の一覧を取得しています。
抽出したデータと、表の一行目の配列をセットしてビューに渡します。

app/controllers/users_controller.php
[php]
class UsersController extends AppController
{
// Model
var $uses = array('User');

// Helper
var $helpers = array('Html', 'Form', 'Csv');

public function download()
{
// 都道府県取得
$_prefs_master = $this->Prefecture->find( 'all',
array(
'conditions' => null,
'fields' => null,
'order' => array('Prefecture.id' => 'ASC'),
'recursive' => -1
)
);
$prefs_master = Set::combine($_prefs_master, '{n}.Prefecture.id', '{n}.Prefecture.name');

// ユーザデータ抽出
$users = $this->User->find( 'all',
array(
'conditions' => $conditions,
'fields' => null,
'order' => $order,
'recursive' => -1,
)
);

// 警告を出さない
Configure::write('debug', 0);

// レイアウトなし
$this->layout = '';

// 表の一行目を作成
$head = array('ID', '氏名', '登録日時', '電話番号', '都道府県', '市区町村', '以下住所');

// 任意のファイル名
$filename = 'UserList_' . date('Ymd_His');

// 出力
$this->set(compact('users', 'filename', 'head', 'prefs_master'));
}
}
[/php]

ビューファイル

最後にビューファイルの作成です。

app/views/download.ctp

コントローラーから渡されたデータを foreach() でグリグリと回しているだけです。

基本的に、CakePHPで作成したアプリケーションの文字コードはUTF-8だと思いますので、csvにする時に、sjisに変換しています。
機種依存文字などが含まれる場合は、sjis-win あたりがの方が良いかと思います。

これで、http://your-domain.com/users/download にアクセスすれば、設定したファイル名のCSVファイルをダウンロードします。

余談

本当は、この機能を管理画面(/admin/users/download)で使いたかったのですが、プレフィックスルーティンで管理画面を制御していたために、コントローラー側でレイアウトを無効としても、無効にならず、管理画面用のレイアウトファイルをcsvファイルとして出力するという事態に陥ってしまい、1時間ほど「あーでもないこーでもない」とやってました。

社内に置いてあるローカルサーバでしか運用しないので、(管理画面内ではなく)フロント側のURLとしても問題なかったのですが、プレフィックスルーティンを使っている場合、(ダウンロード機能の場合だけはプレフィックスルーティンを)無効にする、といった手段を講じる必要がありそうです。

とりあえずこれは未来の私へのメッセージ。
絶対に同じことで悩んでそうなので(苦笑)

CakePHP2.x系統での場合もまた記事にしたいと思います。

-CakePHP
-, , , ,