CakePHP:3.6
MySQL:5.7
CakePHP3でfriendsofcake/searchを使って文字列結合(concat)の検索を実装します。
usersテーブルにlast_name、first_nameというカラムがあり、検索項目はname(last_name + first_name)を例にしましょう。
usersテーブルはこのようになっています。
id:3のfirst_nameがNULLのレコードが今回のポイントです。
id | last_name | first_name |
---|---|---|
1 | 田中 | 一郎 |
2 | 山田 | 太郎 |
3 | 田中 | NULL |
nameに「田中一郎」と入力してid:1が取得できれば成功です。
実装はcallbackでconcatを利用することで実現できます。
/src/Template/Users/index.ctp
<?= $this->Form->create(null); ?>
<?= $this->Form->control('name') ?>
<?= $this->Form->submit('検索') ?>
<?= $this->Form->end(); ?>
/src/Model/Table/UsersTable.php
$searchManager
->add('name', 'Search.Callback', [
'callback' => function ($query, $args, $manager) {
return $query->where(function ($exp, $query) use ($args) {
$name = $query->func()->concat([
'last_name' => 'identifier',
'first_name' => 'identifier'
]);
return $exp->like($name, '%' . $args['name'] . '%');
});
},
]);
しかしこの方法では「田中」と入力したときにid:3のデータは検索に引っかかりません。
理由はMySQLではconcatしたときに片方のフィールドがNULLだと、もう一方の値にかかわらずNULLが返ってくる仕様のためです。
これを回避するにはIFNULL()が使えます。
[MySQL]nullを含むフィールドのconcat
CakePHP3のfriendsofcake/searchではこのように書けばOKです。
id:3のデータもちゃんと拾ってくれます。
/src/Model/Table/UsersTable.php
$searchManager
->add('name', 'Search.Callback', [
'callback' => function ($query, $args, $manager) {
return $query->where(function ($exp, $query) use ($args) {
$name = $query->func()->concat([
'IFNULL(last_name, "")' => 'identifier',
'IFNULL(first_name, "")' => 'identifier'
]);
return $exp->like($name, '%' . $args['name'] . '%');
});
},
]);