TL;DR
- DATE_FORMATで %Y を使用する場合は、以下を参考にする
- where句でコールバック関数とクロージャーを使用し、eqメソッドを使用する
$createdFormat = $query->func()->date_format([
'created' => 'identifier',
"'%Y-%m-%d'" => 'literal'
]);
$query->where(function ($exp) use ($createdFormat, $created) {
return $exp->eq($createdFormat, $created);
});
前提
- PHP
- 7.3.11
- CakePHP
- v3.6.14
事象
1.
ORM: $query->where(["DATE_FORMAT(created, '%Y-%c') = " => $date])
SQL: WHERE DATE_FORMAT(created, '%y-%c') = :c0
################
2.
ORM: $query->where(["DATE_FORMAT(created, '%Y-%c') = ${date}"])
SQL: WHERE DATE_FORMAT(created, '%Y-%c') = 2020-8)
- 上記の通り、連想配列によるデータの渡し方では、発行されるSQLのフォーマットが、Y → y になってしまう
- 変数展開による渡し方では、発行されるSQLのフォーマットは、Y のまま
原因
- 巡りめぐって
QueryExpression::_parseCondition()
を参照し、そこでstrtolowerを行ってるため - 以下対象コードの一部抜粋
protected function _parseCondition($field, $value)
{
$operator = '=';
$expression = $field;
$parts = explode(' ', trim($field), 2);
if (count($parts) > 1) {
list($expression, $operator) = $parts;
}
$type = $this->getTypeMap()->type($expression);
$operator = strtolower(trim($operator));
...
return new Comparison($expression, $value, $type, $operator);
}
対策
- date_formatで指定したいカラムを、別でフォーマット化する
- WHERE句でコールバック関数とeqメソッドを使って条件に追加する
$createdFormat = $query->func()->date_format([
'created' => 'identifier',
"'%Y-%m-%d'" => 'literal'
]);
$query->where(function ($exp) use ($createdFormat, $created) {
return $exp->eq($createdFormat, $created);
});