Недавно при разработке очередного сайта столкнулся с проблемой фильтрации. Проблема заключается в том что битрикс даже для тех свойств у которых тип множественное позволяет выбрать значения, но фильтрация происходит по условии ИЛИ, иногда необходимо что бы фильтрация осуществлялась по И. Для тех кто не понял если я на примере luch.by часы могут иметь несколько характеристик, например водонепроницаемость и календарь, так вот при работе стандартного фильтра он выбирает в каталоге если я выберу эти два параметра одновременно, то поиск будет выдавать результаты у которых в свойствах есть либо календарь, либо водонепроницаемость, либо одно и другое свойство, а необходимо что у часов жостко было задано водонепроницаемость и календарь одновременно. Для тех кто столкнулся с данной проблемой предлагаю свой вариант решения.
Допустим в инфоблоке есть свойство "Дополнительные опции" в котором организован список множественного выбора, который мы хотим использовать в фильтре и имя данного свойства "DOP", нам нужно создать еще одно дополнительное поле "Контрольную строку" тип строка с именем допустим "DOP_CONTROL"
Далее в свойстве инфоблока указываем файл "Файл для редактирования элемента, позволяющий модифицировать поля перед сохранением" (Предварительно данный файл необходимо создать, допустим назовем данный файл "dop.php"). После этого оставляем в покое свойства инфоблока.
В файл "dop.php" поместим текст:
<?
//12 - код свойства Дополнительные опции
//39 - код свойства контрольная строка
if (count($PROP["12"])){ //проверяем было ли заполнено данное свойство
$str="";//в эту будет формироваться текст для контрольной строки
$dop=$PROP["12"];
sort($dop);// сортирую массив (можно и не фильтровать, для меня это более эстэтичнее)
foreach ($dop as $key=>$value)
{$str.="_{$value}_";}//далее формируется строка выбранных ID элементов списка
// на выходе получим строку типа "_42_50_30" в зависимости от выбранных параметров
foreach ($PROP["39"] as $key=>$value) $PROP["39"][$key]=$str;
// заполняем свойство для чего сделал это через цикл не помню возможно будет //достаточно $PROP["39"][0]=$str;
}
else foreach ($PROP["39"] as $key=>$value) $PROP["39"][$key]="";//обнуляем если ранее было заполнено
?>
Таким образом при каждом изменении либо добавлении элемента свойство "DOP_CONTROL" будет обновляться.
Далее работаем с публичной частью:
добавляем стандартный фильтр на станицу, копируем его, затем выбираем в настройках что будем фильтровать по свойству "DOP" и что имя фильтра - "filter".
Далее создаем и правим result_modifier.php, данного фильтра. Для множественного поля я думаю больше подойдут флажки, чем список где при помощи контрола и мышки нужно выбирать свойства ("Помните то что не высе такие умные как мы") . Для этого смодулируем флажки, также в коде модифицируем массив фильтра.
<?
// код приблизителен выдерал из кучи кода необходимого для работы других свойств
foreach($arResult["ITEMS"] as $key=>$item)
{
foreach($arResult["arrProp"] as $kk=>$prop)
if (($prop["NAME"]==$item["NAME"]) && ($prop["MULTIPLE"]=="Y") ) // я думаю любой программист разберется для чего это нужно, для лучшего понимания вывидите $arResult
{ $chek="";
$ID=$kk;//ID в массиве сгенерированного битриксом мы его заменим на чекбоксы
foreach ($prop["VALUE_LIST"] as $k=>$value )//здесь $k id в списке $value название свойства
{
if (in_array($k,$_GET["filter_pf"][$prop["CODE"]])) $dop=" CHECKED "; else $dop="";// проверяем было ли выбранно данное свойство, т.е фильтр по данному свойству установлен
$chek.="<input $dop name=\"filter_pf[{$prop["CODE"]}][]\" value=\"$k\" type=\"checkbox\"/>".GetMessage($k)."<br>";}
}
$arResult["ITEMS"][$key]["INPUT"]= $chek;// устанвливаем новое свойство
}
}
if (count($GLOBALS["filter"]["PROPERTY"]["DOP"])) // проверяем был ли установлен фильтр
{
$dop=$GLOBALS["filter"]["PROPERTY"]["DOP"]; // сохраняем в переменной
unset($GLOBALS["filter"]["PROPERTY"]["DOP"]);// уничтожаем старые значения, для того что бы не мешали
$str="";//строка будет формировать условия
sort($dop);//опять же я сортирую массив
foreach($dop as $val){
if (strlen($str)) $str.="&(%_{$val}_%)"; else $str.="(%_{$val}_%)"; //формирую строку для сложного поиска
}
//в итоге получается строка приблизительно такая (%_42_%)&(%_43_%).....
$GLOBALS["filter"]["?PROPERTY_DOP_CONTROL"]=$str;// устанвливаем новое значение фильтра уже для поля Контрольной строки
}
//?PROPERTY_DOP_CONTROL - значит что будет сложное условие про это можно почитать в двух слова здесь проверяется вхождение в контрольную строку сразу 42 и 43, посколько значения обрамлены "_" лишних элементов не выбирется % - любое количестов символов () - для условия & - оператор И
?>
Теперь нам осталось добавить список новостей, либо элементов каталога и указать там имя фильтра - "filter"
Вот и все проблема решена. Я думаю это лучше что мне предложила техподдрежка (сделать один запрос который достанет ID элементов по данному свойству, потом второй по другому..... т.д, а затем найти пересечение этих массивов и в результате массив пересечений вставить в еще один запрос, который сделает выборку по полученным ID - что и будет результатом), я думаю что предложенный вариант не эффективен, увеличивается количество запросов к базе и возможно если большая база можно и выйти за пределы памяти да и представьте какой длинны будет данный запрос.
Мою идею можно доработать, до компонента я думаю разработчики это могут сделать, для этого достаточно заполнять допустим поле "Описания", которое допустим используется для файлов, в это описание записывать контрольную строку. И обновить компонент для фильтра.
Группы на сайте создаются не только сотрудниками «1С-Битрикс», но и партнерами компании. Поэтому мнения участников групп могут не совпадать с позицией компании «1С-Битрикс».