不定期ではありますが、「Pocket詳解 CakePHP辞典」をより楽しく便利に使っていただけるよう、本書にて取り上げられているクラス・メソッド等で「あまり知られていないけど便利!」なもの、あるいは説明が不十分なものについてのフォローも合わせて、Tipsとしてご紹介させていただきます。
今回は第1回目として、私自身も1度も使ったことのなかった「Timeヘルパー」内で面白いメソッドがあったので、ご紹介します。
CakePHPの組み込みヘルパーの中に「Timeヘルパー」があります。これは日付に関する便利な機能をまとめたヘルパーなのですが、strtotime()/strftime()をベースにしているため日付フォーマットを選ばずに処理してくれる素晴らしいヘルパーです。1.3からは国際化に対応できるように拡張されていますので、複数ロケールを持つサイトでも大変に役立ちます。
そんなTimeヘルパーなのですが、一部「これ、ヘルパーの役目じゃないだろ??」と言うべき面白いメソッドが存在します。それが今回ご紹介する「Time::dayAsSQL()/Time::daysAsSQL()」メソッドです。メソッド名から容易に分かると思うのですが、なんとヘルパーのくせにSQLを扱います(笑)。
この2つのメソッドは「指定した日、あるいは指定した2つの日付の範囲内であるSQLを生成してくれます。例えば2010/09/29検索条件にしたい場合があると思いますが、その場合に「’conditions’ => array(‘created’ => ‘2010-09-29’)」のように書くことはできません。何故かと言いますと、このように記述した場合は2010/09/29 00:00:00と等しい場合だけしか条件に含まれなくなってしまうからです。
本メソッドは、このような挙動を避けるために、当日(daysAsSQL()の場合は開始日)の0:00:00から23:59:59まで(daysAsSQL()の場合は終了日の23:59:59まで)の範囲をSQL文で返してくれます。これを用いれば日にちで検索することが簡単になるでしょう。
しかしお気づきかと思いますが、本来ヘルパーはViewを補助するためのものですので、Modelに関してあれこれ操作するというのはMVC的に通常ありえません。そもそもTimeヘルパーの機能は汎用的のため、ヘルパーではなくコアライブラリとして存在するほうがしっくりきます。なぜヘルパーになっているのかはわかりません。
しかしなかなか有用な機能かと思いますので、この機能を「ライブラリとして」使ってみましょう。
念を押しておきますが、この手法は裏返せば「ヘルパーをどんなところでも使えてしまう」裏技です。しかし、Cakeのヘルパーは基本的にシステムとの結びつきが大変に強いため、ほとんどがまともに動作しないと思います。たとえばコールバックメソッドで初期化を行っている場合に機能することができません。あくまでも「Timeヘルパーをライブラリ的に呼び出す」用途に限定して利用したほうがいいと思います。
たとえばコントローラ内でfindする場合に日付指定をしたい場合は次のようにします。
//hogeアクション function hoge(){ //Timeヘルパーの準備 App::import('Helper', 'Time'); $time = new TimeHelper(); //find実行 $this->data = $this->User->find('all', array( 'conditions' => array( $time->dayAsSQL('2010-09-29', 'created'), ), )); }conditionsにフィールド名を指定せず、そのまま突っ込んでいますが、この書き方は有効です。findでは、「(連想)配列内にフィールドを意味するキーを持たない条件はそのままSQLに書き出す」よう作られています。
大事なことなのでもう一度書いておきますが「この使い方はTimeヘルパーのみに限定して利用したほうがいい」です。MVCの枠を飛び出たトリッキーな使い方なので、一般的にはお勧めのできない方法です(過去に私も このような 主張をしたことがあります)。しかしそれを上回ってTimeヘルパーの日時処理機能は便利なものです。このことを十分に理解してご使用ください。
個人的に、Timeヘルパーをコアライブラリにできないか、開発者側に提案してみたいと思います。
ちなみにSessionコンポーネント・Sessionヘルパーは、CakeSessionライブラリをextendsしています。なので、同じような方法ができるのではないかと思います。なお、本メソッドの解説は「Pocket詳解 CakePHP辞典」の383~384ページに掲載されています。
ほかにも便利な機能が紹介されている「Pocket詳解 CakePHP辞典」を是非よろしくお願いします!
同じことを本家IRCでこうすればいいんじゃないと言ったら、helperはviewのために設計されたもんだ!ぷんすか!という反応が返ってきました。これに関しては使わないほうが過剰反応気味だったと思ってます。
カレンダー機能とか実装する場合、これ使えないと正直しんどいですよね。
ヘルパーを他で使う云々はhiromiさんとも議論しましたね。確かに一般的にはそうだと思うのですが、Timeヘルパーだけはちょっと別じゃないかなと思うようになってきました。じゃ、SQLなんて吐くなよみたいなw
2.0でリファクタリングされることを願いたいです。