Blog

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 {}  

Share this entry