На одном из проектов — сайте агентства недвижимости — возникла необходимость сделать фильтрацию каталога по стоимости дома. Вроде бы ничего сложного, но при этом надо учесть было, что пользователь сайта мог выбрать валюту для диапазона цен и что позиции потом должны фильтроваться с учетом валюты.
Я сделал инфоблок, для заказчики могли бы хранить курс валют нехитрым образом, написал такой скриптик в компоненте catalog.section для выгрузки валюты из инфоблока и использования ее:
// считываем обменный курс из инфоблока
$arSelect = Array();
$arFilter = Array(«IBLOCK_ID»=>4, «ACTIVE_DATE»=>»Y», «ACTIVE»=>»Y»);
$res = CIBlockElement::GetList(Array(), $arFilter, false, Array(), $arSelect);
while($ob = $res->GetNextElement())
{
$arProps = $ob->GetProperties();
$exchange[$arProps[«id_valuta»][«VALUE»]] = $arProps[«rate»][«VALUE»];
}
Потом привел цену приходящую из фильтра к рублю, потому что весь обменный курс в инфоблоке записывается в пересчете на рубль.
// Сохраняем старый фильтр
// и приводим цены к рублевым эквивалентам
$arrFilter_price = $arrFilter;
$arrFilter_price[«PROPERTY»][«>=price»] = $arrFilter_price[«PROPERTY»][«>=price»] * $exchange[$arrFilter_price[«PROPERTY»][«valuta»]];
$arrFilter_price[«PROPERTY»][«<=price»] = $arrFilter_price[«PROPERTY»][«<=price»] * $exchange[$arrFilter_price[«PROPERTY»][«valuta»]];
Затем я перешел к фильтрации. Когда я только открывал код, я подумал, что напишу какое-то, пусть сложное условие здесь:
$arFilter = array(
«IBLOCK_ID» => $arParams[«IBLOCK_ID»],
«IBLOCK_LID» => SITE_ID,
«IBLOCK_ACTIVE» => «Y»,
«ACTIVE_DATE» => «Y»,
«ACTIVE» => «Y»,
«CHECK_PERMISSIONS» => «Y»,
«INCLUDE_SUBSECTIONS» => $arParams[«INCLUDE_SUBSECTIONS»],
);
и на этом все благополучно закончится.
Но посидев приличное время над кодом компонента, я осознал, что просто не представляю как это сделать при помощи API Битрикс и поэтому пришлось лепить безумные костыли в компоненте catalog.section дабы эта штукуевина заработала этот функционал заработал.
Сначала, перед запросом кеша, пришлось все поубирать из фильтра, связанное с ценами, потому что фильтрация по ценам не будет средствами API Битрикс.
// Удаляем из фильтра все связанное с ценами
$arDiff = Array(«>=price»=>NULL, «<=price»=>NULL, «valuta»=>NULL);
$arrFilter[«PROPERTY»] = array_diff_key($arrFilter[«PROPERTY»], $arDiff);
Затем, там где идет собственно выборка элементов, пришлось дописать свою фильтрацию по ценам:
// цену элемента приводим к рублевому эквиваленту
if (isset($arrFilter_price[«PROPERTY»][«valuta»])) {
$price_rub = $arItem[«PROPERTIES»][«price»][«VALUE»] * $exchange[$arItem[«PROPERTIES»][«valuta»][«VALUE_ENUM_ID»]];
}
// проверяем цену на вхождение в диапазон
$invalid_price = false;
if ($arrFilter_price[«PROPERTY»][«>=price»]!=0 && $arrFilter_price[«PROPERTY»][«<=price»]==0) {
if (! ($price_rub >= $arrFilter_price[«PROPERTY»][«>=price»])) {
$invalid_price = true;
}
}
if ($arrFilter_price[«PROPERTY»][«<=price»]!=0 && $arrFilter_price[«PROPERTY»][«>=price»]==0) {
if (! ($price_rub <= $arrFilter_price[«PROPERTY»][«<=price»])) {
$invalid_price = true;
}
}
if ($arrFilter_price[«PROPERTY»][«<=price»]!=0 && $arrFilter_price[«PROPERTY»][«>=price»]!=0) {
if (! (($price_rub >= $arrFilter_price[«PROPERTY»][«>=price»]) && ($price_rub <= $arrFilter_price[«PROPERTY»][«<=price»]))) {
$invalid_price = true;
}
}
Выглядит не блестяще, но работает… Но.. стоп. А как же постраничная навигация? В ней же мы никак не учитываем, что элементов меньше, чем в выборке через API Битрикс.
Ну что ж, на этот случай тоже можно сделать костыль. Дописываем код в обработку выборки элементов:
if (! $invalid_price)
$quant_all++;
// если цена не входит, то выкидываем элемент из выборки
if (! $invalid_price && ( $start_elem <= $quant_all && $end_elem >= $quant_all ))
$arResult[«ITEMS»][]=$arItem;
И после выборки, перед вызовом метода $rsElements->GetPageNavStringEx пишем:
$rsElements->NavNum = 2;
$rsElements->bNavStart = true;
$rsElements->bShowAll = $arParams[«PAGER_SHOW_ALL»];
if (floor($quant_all / $arParams[«PAGE_ELEMENT_COUNT»]) != $quant_all / $arParams[«PAGE_ELEMENT_COUNT»])
$rsElements->NavPageCount = floor($quant_all / $arParams[«PAGE_ELEMENT_COUNT»]) + 1;
else
$rsElements->NavPageCount = floor($quant_all / $arParams[«PAGE_ELEMENT_COUNT»]);
if (isset($_REQUEST[«PAGEN_2»]))
$rsElements->NavPageNomer = $_REQUEST[«PAGEN_2»];
else
$rsElements->NavPageNomer = 1;
$rsElements->NavRecordCount = $quant_all;
Вот такими костылями удалось заставить работать Битрикс с фильтрацией по ценам с учетом валюты.
Я просто не верю, что это нельзя сделать через Битрикс API…
Наверняка есть какой-то обходной путь, но не такими костылями же.
Закинул этот пост на форум Битрикс — посмотрим. Может что и можно сделать.
ROBO — Вы слишком хорошо думаете о битрихе :-)
Почему не подходит такой вариант:
$arrFilter[] = array(
«LOGIC» => «OR»,
array(«>=CATALOG_PRICE_1» => «10», «CATALOG_CURRENCY_1» => «RUB»),
array(«>=CATALOG_PRICE_1» => «30», «CATALOG_CURRENCY_1» => «USD»)
);