concrete5の選択属性(Select Attribute)の検索をANDに変更する
Posted by admin at 17:31 日時 2013/11/19
仕事で困ったなぁ〜と思ったけどすぐに解決したのでメモ。concrete5のページ属性には様々なタイプがありますが、その中でも「選択」属性の検索は「OR検索」(いずれかに合致するアイテムを取得)になっています。これを「AND検索」(すべてに合致するアイテムを取得)に変更する方法です。
concrete5ではこんな感じで、ページ属性で絞り込んでページの一覧を表示できます。
$pl = new PageList(); if (is_array($_REQUEST['akID'])) { Loader::model('attribute/categories/collection'); foreach($_REQUEST['akID'] as $akID => $req) { $ak = CollectionAttributeKey::getByID($akID); if (is_object($ak)) { $type = $ak->getAttributeType(); $cnt = $type->getController(); $cnt->setAttributeKey($ak); $cnt->searchForm($pl); } } } $pages = $pl->getPage();
本題ではないのでこの部分の解説は省きますが、「検索」ブロックのcontroller.phpの中でもこのように書いてあります。属性で検索するコードは複数のクラスが関係しあっていて、ちょっと分かりにくいのですが、ざっくりと言うと属性タイプコントローラーがページリストモデルを受け取り、ページリストモデルにフィルタリングのSQLを追加して返すという処理になっています。モデル側ではあくまで汎用的な検索処理だけが書いてあり、それをコントローラーから操作すると言う意味では、まあオブジェクト指向的な考え方に忠実ではあるのですが…。
で、属性タイプコントローラーの searchForm() メソッドが、属性タイプごとに適した検索SQLをくっつけてくれることで、上記のような抽象的なコードが可能になるのですが、「選択」属性タイプの searchForm() メソッドの中身はがっつり「OR」と書いてありますので、OR検索になります。これをAND検索に変更したい場合ですが、メソッドごとオーバーライドしてやりましょう。
「選択」属性タイプのコントローラーは下記のファイルが読み込まれています。
concrete / models / attribute / types / select / controller.php
ただし、このファイルはコアクラスを継承しているため、クラス宣言のみです。
<?php defined('C5_EXECUTE') or die("Access Denied."); class SelectAttributeTypeController extends Concrete5_Controller_AttributeType_Select {} class SelectAttributeTypeOption extends Concrete5_Model_SelectAttributeTypeOption {} class SelectAttributeTypeOptionList extends Concrete5_Model_SelectAttributeTypeOptionList {}
実際の処理が書いてあるのはコアディレクトリにある Concrete5_Controller_AttributeType_Select クラスです。
concrete / core / models / attribute / types / select.php
当ブログでも何度も紹介していますが、concrete5のカスタマイズはオーバーライドで行ないます。今回カスタマイズしたいファイルは
concrete / models / attribute / types / select / controller.php
ですので、このファイルを1階層上に複製します。
models / attribute / types / select / controller.php
そして中身を下記のように書き換えます。こうして searchForm() メソッドのみの挙動を変更することができました。
<?php defined('C5_EXECUTE') or die("Access Denied."); class SelectAttributeTypeController extends Concrete5_Controller_AttributeType_Select { public function searchForm($list) { $options = $this->request('atSelectOptionID'); $optionText = array(); $db = Loader::db(); $tbl = $this->attributeKey->getIndexedSearchTable(); if (!is_array($options)) { return $list; } foreach($options as $id) { if ($id > 0) { $opt = SelectAttributeTypeOption::getByID($id); if (is_object($opt)) { $optionText[] = $opt->getSelectAttributeOptionValue(true); $optionQuery[] = $opt->getSelectAttributeOptionValue(false); } } } if (count($optionText) == 0) { return false; } $i = 0; foreach($optionQuery as $val) { $val = $db->quote('%||' . $val . '||%'); $multiString .= 'REPLACE(' . $tbl . '.ak_' . $this->attributeKey->getAttributeKeyHandle() . ', "\n", "||") like ' . $val . ' '; if (($i + 1) < count($optionQuery)) { // $multiString .= 'OR '; // 変更前 $multiString .= 'AND '; // 変更後 } $i++; } $list->filter(false, '(' . $multiString . ')'); return $list; } } class SelectAttributeTypeOption extends Concrete5_Model_SelectAttributeTypeOption {} class SelectAttributeTypeOptionList extends Concrete5_Model_SelectAttributeTypeOptionList {}