【CakePHP】SQLが頭に浮かぶなら迷わずqueryメソッドを使おう

【CakePHP】SQLが頭に浮かぶなら迷わずqueryメソッドを使おう

こんにちは、inoueです。高校球児のようにちょっと連投。

CakePHPを使ってアプリケーション開発をしていると、「便利だなあ」と思う点と「面倒だなあ」と思う点があります。
特にDBアクセスまわりは、単純な1テーブルとのやりとりはフレームワークが楽をさせてくれるのですが、 複数テーブルをJOINしたり、MySQL関数を使いたいときは非常に面倒に思ってしまいます。

そんなとき、思い悩まずに済むのがモデルのqueryメソッドです。

使用方法

任意のSQLを記述し、それを引数として queryメソッドに渡せば、実行結果を配列で返してくれます。
例として、アクセスログを集計してページごとの日別アクセス数を求める場合はこんな感じ。

$sql = " SELECT blog_id, author_id, entry_id,";
$sql .= " DATE_FORMAT(access_datetime, '%Y-%m-%d') total_date,";
$sql .= " COUNT(*) click_count";
$sql .= " FROM access_logs";
$sql .= " WHERE access_datetime < '". date("Y-m-d"). " 0:00:00" ."'";
$sql .= " GROUP BY blog_id, author_id, entry_id, total_date;";

$return = $this->AccessLog->query($sql);

ここで注意したいのが、戻り値の配列の構成。
COUNT()などMySQL関数を使ったカラムとテーブルのカラムは次のように別々にまとめられています。
取得結果をforeach()等でまわして処理をする際注意が必要です。

$return = 
Array
(
    [0] => Array
    (
        [0] => Array
        (
            [click_count] => 10
            [total_date] => 2009-02-18
        )

        [access_logs] => Array
        (
            [blog_id] => 1
            [author_id] => 4
            [entry_id] => 53
        )
    )
    ...
)

また、queryメソッドではモデル名ではなく、実際のテーブル名を直接記述するので、 テスト環境と本番環境でテーブル名のプレフィクスあり/なしが変わる場合には、その設定をSQLに反映する必要がありますのでご注意ください。

アソシエーション設定との使い分け

実際には、アプリケーション内で密接に連携しているテーブル同士はモデルのアソシエーション設定をしておくのが賢明です。
一方で、イレギュラーに「このメソッドでだけJOINしたい」といった場合は、メソッド内でbindModelメソッドを利用するのが正当な方法かと思います。

今回紹介したqueryメソッドの主な使い道としては

  • bindModelに設定する前にすでにSQLが頭に浮かんじゃってる。(まずは実装!)
  • "INSERT INTO table_a ( ... ) SELECT ... FROM table_b;" のようなデータの移動をSQL一発でやっちゃいたい。
  • デバッグモードで表示されるSQLがなんだかまどろっこしい感じ。そして処理が重い(のを改善したい)。

こういったあたりの、さらにイレギュラーな場合になるかと思います。

とはいえ、従来のPHP開発で培ったスキルをqueryメソッドにうまく活かして、フレームワークに振り回されすぎないプログラミングをするのもいいのではないでしょうか。

参考情報

  • このエントリーをはてなブックマークに追加

この記事を読んだ人にオススメ