読者です 読者をやめる 読者になる 読者になる

ダメプログラマの技術メモ

プログラミングの技術メモや駄文など

CakePHP2.x系でRESTful API(JSON)のSQLデバッグを簡単に行う方法

この記事で行うことは、

http://127.0.0.1/cakephp/Test/index

のようにアクセスすればjsonのレスポンスが返り、

http://127.0.0.1/cakephp/Test/index?debug

のようにアクセスすれば通常のweb画面が表示される(SQLログの確認ができる)方法の解説です。

ソースファイル

Controller/AppController.php

<?php
class AppController extends Controller {

	public $uses = array('Music');

	public function beforeFilter() {
//		$data = $this->Music->findById(1);
//		$this->renderJson($data);
	}

	public function invokeAction(CakeRequest $request) {
		parent::invokeAction($request);
//		$data = $this->Music->findById(1);
//		$this->renderJson($data);
	}

	public function renderJson($data) {
		if (isset($this->request->query['debug'])) {
			$this->set('data', json_encode($data, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE));
			$this->render('/debug/index');
		} else {
			$this->response->type('application/json');
			$this->response->body(json_encode($data, JSON_UNESCAPED_UNICODE));
		}
		$this->response->send();
		exit;
	}
}

renderJsonメソッドの中でhtmlを表示する処理とjsonを返す処理を行っています。

どちらの処理を行うかはdebugパラメータの有無で判断しています。

htmlを表示する場合

$dataをjsonエンコードしてテンプレート変数にセットしています。

その際、jsonの見やすさを考慮してJSON_PRETTY_PRINTと、日本語をユニコードエスケープさせたくないのでJSON_UNESCAPED_UNICODEを指定しています。ただし、どちらもPHP5.4以上でしか使用できないのでご注意を。。。

ビューファイルはコントローラ/アクション毎に用意するのではなく共通の/View/Debug/index.ctpを使用しています。

最後に CakeResponse::send()でレスポンスを送出して、処理を終了させています。

JSONを返す場合

まずコンテンツタイプを「application/json」に変更しています。

その後はレスポンスボディに$dataをjsonエンコードしたものをセットして、htmlと同様にレスポンス送出⇒処理終了の流れになっています。

なお、renderJsonメソッドはアクションメソッド内だけでなく、beforeFilterやinvokeActionの中でも使用することができます。

Controller/TestController.php

<?php
class TestController extends AppController {

	public function index() {
		$data = $this->Music->find('all');
		$this->renderJson($data);
	}
}

renderJsonメソッドの使用例です。

Model/Music.php

<?php
class Music extends AppModel {
}

テスト用のモデルクラスになります。

View/Debug/index.ctp

<pre>
<?php echo $data; ?>
</pre>

jsonを見やすくするために<pre>タグで囲っています。

実行結果

jsonを返す場合

f:id:damepg:20140506093702j:plain

Web画面を表示する場合

f:id:damepg:20140506093717j:plain

最後に

実は最初、RequestHandlerComponentを使用してjsonとhtmlを切り替えていたのですが、beforeRenderで複雑な処理を記述したら何故かhtmlでアクセスした時だけbeforeRenderが何度も呼び出される現象が発生してしまい、その解決方法がわからないため今回のような方法をとりました。

まぁ、今回の方がわかりやすいので結果オーライかな(;´・ω・)