CakePHP3でDATE_FORMAT


  • Datetimeで保存されているデータをDATE_FORMATY-m-dの形式を条件として絞り込みたい。
  • 難しいことではないのですが、少しはまったので備忘録。

CakePHP2とCakePHP3での書き方の違い

CakePHP2の場合

CakePHP2まではconditionsに思ったままの事を書けばできます。

$conditions = ["DATE_FORMAT(created, '%Y-%m-%d')" => 'CURRENT_DATE()'];

これでCURRENT_DATE()で絞り込んだデータを取得することができます。

CakePHP3の場合

CakePHP3でも似たようなものだと思っていたので下記の様に記述。
(ただし=をつけないとエラーが発生するので注意)

$query->where([
    "DATE_FORMAT(created, '%Y-%m-%d') =" => $query->func()->now('date')
])

CURRENT_DATE()をCakePHP3っぽく$query->func()->now('date')と記述。

問題

一見上記で問題がないように動作していたのですが、データがうまく取れていないことが発覚。
出力されたSQLのWHEREを確認してみると、

WHERE 
  DATE_FORMAT(created, '%y-%m-%d') = (
    CURRENT_DATE()
  ) 

%Yで指定したはずが%yになっています。
……なぜ。

対策

1. func()->date_format()を使う

そのまま記述するのが原因のようなのでfunc()を使用してDATE_FORMATを記述してみます。

$created = $query->func()->date_format([
    'created' => 'identifier',
    "'%Y-%m-%d'" => 'literal'
]);

$query->where([
    $created => $query->func()->now('date')
]);

Illegal offset type……
条件に使用する想定ではないのでしょうか、怒られます。
でも$query->func()->now('date') も使いたい。(逆にしてみたけどやはり怒られる)

2. よりCakePHP3っぽい書き方にする

func()->date_format()を使用しつつ、よりCakePHP3の記述に近づけてみます。

$created = $query->func()->date_format([
    'created' => 'identifier',
    "'%Y-%m-%d'" => 'literal'
]);

$today = $query->func()->now('date');

$query->where(function ($exp) use ($created, $today) {
   return $exp->eq($created, $today);
});

発行されたSQLを確認しても%Yのまま。
無事に希望通りのデータが取得できました。