PHP
Laravel
blade

【Laravel5.8】bladeを使ってCSVを作れなかった

いやースマブラに勇者参戦ですよ、これは楽しみすぎますね。

さらにゼルダ続編も出るとか、また寝る時間がなくなってしまいますね。

さて、それとは全く関係ないのですが、LaravelでCSVダウンロードしたいという要件があったのですよ。

目的は達成したのですが、解決は特にしていません。

単に1テーブルとか、1対1のテーブルを結合して出力するだけであれば、withで拾ってコントローラあたりで適当に整形するのが楽だし早いでしょう。

しかし世の中そう単純にはいかないもので、1対多のテーブルを複数まとめてひとつのCSVに出力しろだとか、そもそも関係ないテーブルを並べてひとつのCSVに出力しろだとか言われるわけです。

そんなときはどうするのが最も適切でしょうか。ちゃぶ台を返す?


fooController.php

    $csv = [];

$csv[] = ['テーブル1'];
foreach($model1 as $v){
$csv[] = [$v->id, $v->data1, $v->data2];
}

$csv[] = ['テーブル2'];
foreach($model2 as $v){
$csv[] = [$v->id, $v->data1, $v->data2, $v->data3];
}


コントローラに延々こんなことを書いていく?

なんか嫌なのでどこか外に出したい。

ならテンプレートでいいんじゃないか?

bladeの機能とか使えるしな。

ということで持っていってみたわけですが、実際普通にテンプレート書くのとほとんど同じなので、むしろタグがないだけ簡単です。


csv.blade.php

テーブル1

@foreach ($model1 as $v)
{{ $v->id }},{{ $v->data1 }},{{ $v->data2 }}
@endforeach
テーブル2
@foreach ($model2 as $v)
{{ $v->id }},{{ $v->data1 }},{{ $v->data2 }},{{ $v->data3 }}
@endforeach

やったぜ。

…これCSVエスケープできてないやん。

ダメやんプレイやん。

テンプレート上で各出力項目にCSVエスケープ関数を通さないといけないわけですが、実はPHPには文字列に素で使えるCSVエスケープ関数がありません。

fputcsvSplFileObjectも、リソースやオブジェクトに対してどうにかするものであって、{!! csvspecialchars($v->id) !!}みたいなことはできません。

まあ探せばユーザサイドのCSVエスケープ実装なんていくらでも出てくるので、Blade::directiveに突っ込んでテンプレから呼べばいいといえばいいのですが、どうにも美しくない気がして微妙なところ。

何よりBlade::directiveが、create_functionばりに実装を文字列で渡さないといけないのが生理的に受け付けない。

関数返すようにできないんですかね?

ていうか、調べてみたらディレクティブってめっちゃevalしてるんですね。

特に調べたわけじゃないけど、なんとなくちょっと怖くない?

ということで、結局どこに持っていくのが一番適切なんだろう。

なお、冒頭のやつは最終的にコントローラにだばだば書いた。