【Concrete CMS】Express の複合検索で numeric 属性に泣かされた話
「キーワード検索を illust_kw だけでなく、illust_title や illust_no(数値)にも広げたい」
──ただそれだけの話のはずだった。
しかし、実際に手を動かしてみると、numeric 属性の扱いが想像以上に曲者だった。
そもそもの要件
このサイトで紹介している【Concrete CMS】Express で管理している1万5千を超えるイラストの検索はキーワード(エンティティ:illust_kw)でのみ管理していた。
本来は検索対象とすべきイラストを管理する Express エンティティには、こんな属性がある。
illust_no(数値):ユニークなPIXTAイラスト番号illust_title(テキスト):イラストタイトルillust_kw(テキスト):最大50個のキーワード
目指すは検索フォームに入力されたキーワードをスペース区切りで AND 検索し、各キーワードは 上記 3 属性のどれかにヒットすれば OK(OR 条件)
という、よくある複合検索だ。
最初は軽い気持ちでこう思っていた。
「ああ、LIKE 条件を増やせばいいだけね」
……甘かった。
numeric 属性は LIKE できない問題
illust_kw や illust_title は普通に LIKE で検索できる。
ところが illust_no は numeric 属性。
そのまま LIKE を書くと、当然 SQL エラーになる。
「えっ、じゃあどうやって部分一致検索するの……?」
ここでしばらく手が止まった。
Concrete CMS のドキュメントを読み返しても、Express の numeric 属性を LIKE で検索する例は見当たらない。
解決策:CAST して文字列として扱う
最終的にたどり着いたのがこれ。
CAST(ak_illust_no AS CHAR)
numeric を文字列に変換してしまえば、LIKE 検索が可能になる。
この発想に至るまでが長かった。
「もしかして検索ロジックを分けるべきか」「完全一致だけにするべきか」など、いろいろ遠回りした。
実際に動いたコード
最終的に、キーワードごとに OR 条件をまとめ、AND で積み上げる形に落ち着いた。
// AND検索条件の追加
if (!empty($keywords)) {
$query = $list->getQueryObject();
foreach ($keywords as $index => $keyword) {
// OR 条件をまとめる
$orX = $query->expr()->orX(
$query->expr()->like('ak_illust_kw', ":kw$index"),
$query->expr()->like('ak_illust_title', ":kw$index"),
$query->expr()->like('CAST(ak_illust_no AS CHAR)', ":kw$index")
);
// AND 条件として追加
$query->andWhere($orX);
// パラメータ設定
$query->setParameter("kw$index", '%' . $keyword . '%');
}
}
これでようやく、
- キーワード A
- キーワード B
- キーワード C
…と複数入力された場合でも、
「A にヒット AND B にヒット AND C にヒット」
という期待通りの動作になった。
numeric のソートは別問題
検索は CAST(... AS CHAR) で解決したが、
ソートは逆に 数値として扱わないと順番が崩れる。
そこでソートはこうした。
$list->getQueryObject()->orderBy('CAST(ak_illust_no AS UNSIGNED)', 'DESC');
検索は文字列、ソートは数値。
この二面性が、今回の混乱の原因だったのだと思う。
今回の学び
今回の苦労をまとめると、こんな教訓に落ち着く。
- Express の numeric 属性は LIKE できない
- でも CAST すれば文字列として扱える
- 検索とソートで CAST の型を変える必要がある
- AND × OR の複合検索は SQL の組み立て方が肝
特に、「numeric だからといって常に数値として扱う必要はない」
という発想の転換がポイントだった。
おわりに
Concrete CMS の Express は柔軟で便利だが、
「属性の型」と「SQL の扱い」のギャップに気づかないとハマることがある。
今回のように、
- 数値を文字列として検索
- 数値としてソート
という使い分けが必要になるケースは、実務では意外と多い。
同じように悩んでいる方の助けになれば幸いです。







