前提・実現したいこと
CakePHP3 で JavaScript から JSON 形式のデータを送信し、Controller で JSON 形式データを使って処理した結果をテンプレート(ctp)で HTML や CSV 出力したいのですが、テンプレートが呼ばれません。
コントローラーのビューを確認($this->viewClass)したところ、ビューが JosnView となっているためだと思われます。
単純な POST 形式での送信受信では viewClass は空でした。
どのよにすれば Json 形式で送受信したデータをテンプレートを使って HTML や CSV 形式で応答できるのでしょうか?
補足情報(FW/ツールのバージョンなど)
CentOS 7
PHP 5.6.38
CakePHP 3.2.12
気になる質問をクリップする
クリップした質問は、後からいつでもMYページで確認できます。
またクリップした質問に回答があった際、通知やメールを受け取ることができます。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。

回答2件
0
tacsheaven さん
有難う御座いました。
ご支援の頂きましたことで、CSV ファイル出力が出来るようになりました。
ポイントしては、
1) Controller のアクション内で
$this->viewBuilder()->className('');
する
2) Controller#beforeRender で Conten-Type を設定する
3) ajax の受信データの形式(dataType)を適切に設定(HTML: 'html', CSV: 'text' etc...)する
4) ajax で CSV ファイル形式で受信したデータを元に Download 内部リンクを生成&Clickする
かと思います。
◆JavaScript
function csvExport() { var url = 'http://?????/XXXXX/csvExport/' + param; var obj = {key1:value1,key2:value2, etc...}; var jsonData = JSON.stringify(obj); var ajaxInfo = { type: 'POST', dataType: 'text', // Notes: 受信(レスポンス)データのデータ形式を 'text' にする data: jsonData, processData: false, contentType: 'application/json', timeStamp: new Date().getTime() }; $.ajax( url, ajaxInfo ).done(function( data ) { // Notes: // 受信した CSV ファイルをダウンロードできるようにする // (Excel でも文字コード: UTF-8 で開けるように BOM を設定) let bom = new Uint8Araay([0xEF, 0xBB, 0xBF]); let downloadData = new Blob([bom, data], {type: 'text/csv'}); let fileName = 'output.csv'; if (window.navigator.msSaveBlob) { window.navigator.msSaveBlob(downloadData, fileName); } else { let downloadUrl = (window.URL || window.webkitURL).createObjectURL(downloadData); let link = document.createElement('a'); link.href = downloadUrl; link.download = fileName; link.click(); (window.URL || window.webkitURL).revokeObjectURL(downloadUrl); } }).fail(function(jqXHR, textStatus, errorThrown) { window.alert(jqXHR.responseText); }); }
◆Controller
class XXXXXController extends AppController { public $helpers = array('Csv'); public function initialize() { parent::initialize(); $this->loadComponent('Flash'); $this->loadCompanent('RequestHandler'); } public function beforeRender(Event $event) { // Notes: // RequestHandlerComponet#beforeRender 内で Content-Type に関るする // 処理が行われるため、その後に呼ばれるController#beforeRenderを // override し、Content-Type を text/csv に上書きする $this->response->type('csv'); $this->response->download($fileName); } public function csvExport($param) { // JSON 形式データを取得 $data = $this->request->data(); // key: value で各データ取得しながら、CSV 元データを生成 $val = $data['[key]'); $csvRows = array(['item1-1', 'item1-2', etc ...], ['item2-1', 'item2-2', etc...], etc...); $fileName = 'output.csv'; ... $this->set('csvRows', csvRows); $this->set('fileName', $fileName); $this->viewBuilder()->className(''); $this->viewBuilder()->layout(false); } }
◆XXXXX/ajax/csv_export.ctp
<?php $this->Csv->setFilename($fileName); foreach($csvRows as $row) { $this->Csv->addRow($row); } echo $this->Csv->render(false);
◆CsvHelper.php
<?php namespace App\View\Helper; use Cake\View\Helper; class CsvHelper extends Helper { private $delimiter = ','; private $enclosure = '"'; private $filename = 'Export.csv'; private $line = array(); private $buffer = null; public function initialize(array $config) { parent::initialize($config); $this->clear(); } public function __destruct() { $this->closeBuffer(); } public function clear() { $this->closeBuffer(); $this->line = array(); $this->buffer = fopen('php://temp/maxmemory:'.(5*1024*1024), 'r+'); } public function setDelimiter($param) { $this->$delimiter = $param; } public function addField($value) { $this->line[] = $value; } public function endRow() { $this->addRow($this->line); $this->line = array(); } public function addRow($row) { fputcsv($this->buffer, $row, $this->delimiter, $this->enclosure); } public function setFilename($filename) { $this->filename = $filename; if (strtolower(substr($this->filename, -4)) != '.csv') { $this->filename .= '.csv'; } } public function render($outputHeaders = true, $toEncoding = null, $fromEncoding = "auto") { if ($outputHeaders) { if (is_string($outputHeaders)) { $this->setFilename($outputHeaders); } $this->renderHeaders(); } rewind($this->buffer); $output = stream_get_contents($this->buffer); if ($toEncoding) { $output = mb_convert_encoding($output, $toEncoding, $fromEncoding); } return $output; } private function renderHeaders() { // Notes: // ログで // Warning: Warning (2): Cannot modify header information - headers already sent by // (output started at /var/www/html/vendor/cakephp/cakephp/src/Error/Debugger.php:742) in // [/var/www/html/src/View/Helper/CsvHelper.php, line 104] // となるため、コメントアウト // header("Content-Type: text/csv"); // header("Content-Disposition: attachment; filename=".$this->filename); } private function closeBuffer() { if (null != $this->buffer) { fclose($this->buffer); $this->buffer = null; } } }
投稿2019/01/29 09:35
総合スコア14
0
ベストアンサー
CakePHP の RequestHandlerComponent の動作により、リクエストの Accept ヘッダの内容によって自動的にビューのクラスが変わります。
※Accept: application/json ならば自動的に jsonView になる
ビューを展開する前(controller のアクション内)で、$this->viewBuilder() の設定を変更してやればビュークラスを入れ替えることができます。
PHP
1$this->viewBuilder()->className('');
でできたりしそうですが。(環境がないので試していませんが)
投稿2019/01/25 03:07
総合スコア13707
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。

あなたの回答
tips
太字
斜体
打ち消し線
見出し
引用テキストの挿入
コードの挿入
リンクの挿入
リストの挿入
番号リストの挿入
表の挿入
水平線の挿入
プレビュー
質問の解決につながる回答をしましょう。 サンプルコードなど、より具体的な説明があると質問者の理解の助けになります。 また、読む側のことを考えた、分かりやすい文章を心がけましょう。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。