CakePHPのfind()で取得したデータが全てstring型になるのを、DBのカラムの型に合わせてint型で値を取得する方法(mysql)


CakePHP2からはPDOを使ってDBアクセスするようになりました。PDO(mysql)では、デフォルト設定でデータをfetchするとint型のカラムでもstring型として結果が返ってきます。CakePHPもこの影響を受けており、jsonデータなどに変換する際や、型を厳密に扱いたい場合に影響がます。(CakePHP1では、PDOを使っていませんがintカラムはstringで返ってきます)


この問題を解決するには、PHP5.3以上の環境でPDOのPDO::ATTR_EMULATE_PREPARESをオフにすれば良いです。PDOがmysqlndドライバを利用することが前提なのですが、PHP5.4からはデフォルトでmysqlndドライバが利用されるので大丈夫です。今回はPHP5.4の環境で検証しました。

PHP5.3ではPDOがmysqlndドライバを利用するためにコンパイルオプションを指定するか、パッケージインストールでphp-mysqlndを入れるなどが必要です。
参考 http://stackoverflow.com/questions/13159518/how-to-enable-mysqlnd-for-php


mysqlndについてや、PDOとの関係などは下記の資料がまとまっています。
http://blog.layer8.sh/ja/2013/03/12/php-mysql-pdo-mysqlnd/


さて、CakePHP2でPDOのフラグオプションにPDO::ATTR_EMULATE_PREPARES = falseを指定すれば良いのですが、mysqlデータソースを見るとアプリケーション側から指定する仕組みがないため、コントローラの中などでPDOインスタンスを取得してセットすることにしましょう。
例えば、jsonを返すコントローラのアクションの中で下記のようにすればfindの結果は型が正しい状態で返ってきます。

<?php
$pdo = $this->Post->getDatasource()->getConnection();
$pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES,FALSE);
var_dump($this->Post->find());

やっていることは、Postモデルを使って(モデルは何でも良い)、getConnection()でPDOインスタンスを取得します。
あとはPDOクラスのsetAttribute()メソッドでPDO::ATTR_EMULATE_PREPARESにfalseを指定しています。


もしアプリケーション全体でこのオプションを有効にしたい場合は、AppModelやAppControllerで上記の指定をしておくか、CakePHPMySQLデータソースを継承して、connect()メソッドをオーバライドして制御するなどすれば対応できるでしょう。

追記

akiyan先生からのご指摘で、タイトルが紛らわしいと気付いたので変更しました。ありがとうございました。