【Concrete CMS】Express の複合検索で numeric 属性に泣かされた話

2025/12/27
Concrete CMS の Express を使ってイラスト管理システムを構築しているとき、思わぬ落とし穴にはまった。
「キーワード検索を 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_kwillust_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 の扱い」のギャップに気づかないとハマることがある。

今回のように、

  • 数値を文字列として検索
  • 数値としてソート
    という使い分けが必要になるケースは、実務では意外と多い。

同じように悩んでいる方の助けになれば幸いです。


#
2025/04/26
Concrete CMSのエクスプレスデータベースには標準でCSV入力が無いのですね。そこでJOBに登録して簡単に利用できるものを作ってみました。
#
2025/05/01
9,000件のConcrete CMSエクスプレスデータを削除しようと「エントリーをクリア」を実行したところ、タイムアウトエラーが発生。 手作業で一つずつ削除するのは現実的ではないため、一括削除プログラム を作成しました。
#
2025/05/12
Concrete CMSのExpressデータを大量に扱う中で、同一レコードの重複登録や既存データの更新が必要になることがあります。 このジョブプログラムは、最終更新日を基準に最新のレコードを残し、古い重複データを自動的に判別・整理することで、登録データの一括更新を効率化します。 これにより、管理作業の手間を減らし、常に最新かつ正確なデータを維持することができます。
#
2025/05/13
Concrete CMSの標準機能では、説明(description)がmeta descriptionに変換されない問題を解決するための「Description to Meta」Jobプログラムを開発しました。これにより、記事概要を自動でmeta descriptionへコピーし、検索結果の表示を最適化できます。SEO対策と運用効率を向上させるための便利なツールです。
#
2025/05/18
Concrete CMS の Express エントリ一覧において「最大 1000 件までしか取得できない」という制限に直面し、標準の EntryList や Express ブロックでは対応が難しかった。ORM の制約によりカスタマイズによる解決も困難だったが、Doctrine クエリビルダーを直接用いる方法へ移行。その結果、大規模データを扱う要件を満たす実装が実現できた。副次的にスペース区切りでのAND検索機能も獲得できた。
#
2025/12/27
Concrete CMS の Express を使ってイラスト管理システムを構築しているとき、思わぬ落とし穴にはまった。 「キーワード検索を illust_kw だけでなく、illust_title や illust_no(数値)にも広げたい」 ──ただそれだけの話のはずだった。 しかし、実際に手を動かしてみると、numeric 属性の扱いが想像以上に曲者だった。