CakePHP2でContent-Typeを変更する時のハマりポイント

いろいろなブログで既に書いてあるので今更ですが、
挙動に微妙にハマったので注意すべき箇所をメモしておこうと思う。

ピュアPHPならheader()を使うところ、CakePHPでは出力前後にコールバックするメソッドが色々あるため、専用の方法が用意されている。


基本的にここに書いてある通りで、イレギュラーなことしなければいけます。

『リクエストとレスポンスオブジェクト - レスポンスクラスを変更する - コンテンツタイプを扱う』
http://book.cakephp.org/2.0/ja/controllers/request-response.html#id8


注意しなければならないのは、WebAPIを作るなどでjsonを吐き出すだけなら、例えば以下のように

<?php

class HogeController {
    public function unnko() {
        $this->layout = false;
        $this->autoRender = false;
        $json = '{"a":"deru"}';
        echo $json;
    }
}

?>

これでviewファイルをいちいち作らずコントローラだけで完結できる。
だがこれだと、実は先述のCakeResponse::type()を使ってContent-Typeをいくら変えても、必ずtext/plainで出力されてしまう。

jsonとして返す場合、$this->viewClassを利用する方法もネットに情報がいっぱいあります。action名に拡張子をつけて出力が変わるこのやり方、便利だとは思うけどmediaViewは2.3で撤廃らしい。変化が早い…)


例えばswfかなんかを解析してapplication/x-shockwave-flashで出力したい時などに、読み込んだファイルを単にechoするだけではうまくいかない。

面倒でもちゃんとctpファイルを作って、viewに変数をセットしてあげる必要がある。

<?php

class HogeController {
    public function swf() {
        $this->layout = false;
        $this->response->type('swf');
        $swfObject = new FlashLite();
        $swf = $swfObject->getSwf();
        $this->set(compact('swf'));
    }
}

?>

ちなみにswfはContent-TypeとしてCakeResponseに既に用意されているので何も考えず'swf'を指定すればうまくいきますが、CakeResponseに用意されていないContent-Typeを指定する場合はドキュメントの通り

<?php
    $this->response->type(array('unnko' => 'toilet/x-human-output'));
?>

と配列で指定してあげれば、それ以降に

<?php
    $this->response->type('unnko');
?>

の指定が有効になります。


既に何が登録されているか見たければ
lib/Cake/Network/CakeResponse.php
に書いてあります。