Активация механизма фильтрации
Для инициализации фильтрационного механизма выполните следующие шаги:
-
Инициализация глобального фильтра\ Перед вызовом компонента определите глобальный массив с параметрами фильтрации:
$GLOBALS['arrFilter'] = array( 'ACTIVE' => 'Y', '!PROPERTY_DISCOUNTS' => false ); -
Конфигурация компонента\ В параметрах компонента активируйте фильтр и укажите его идентификатор:
$APPLICATION->IncludeComponent( 'bitrix:news.list', '', array( 'USE_FILTER' => 'Y', 'FILTER_NAME' => 'arrFilter', // ... другие параметры ) );
Базовые сценарии фильтрации
1. Условия по свойствам элемента
-
Наличие заполненного свойства:
$GLOBALS['arrFilter'] = array('!PROPERTY_DISCOUNTS' => false); -
Фильтрация по идентификаторам:
// Одиночный элемент $GLOBALS['arrFilter'] = array('ID' => 12); // Множество элементов $GLOBALS['arrFilter'] = array('ID' => array(10, 11, 12));
2. Временные интервалы
-
Элементы, созданные сегодня:
$GLOBALS['arrFilter'] = array('>=DATE_ACTIVE_FROM' => date('d.m.Y')); -
Элементы за последние N дней (пример для 2 дней):
$GLOBALS['arrFilter'] = array( '>=DATE_CREATE' => date('Y-m-d H:i:s', time() - 86400*2), '<=DATE_CREATE' => date('Y-m-d H:i:s') );
3. Работа со свойствами
-
Фильтр по значению списка (CODE свойства = HIT):
$GLOBALS['arrFilter'] = array('=PROPERTY_HIT_VALUE' => 'Yes'); -
Фильтр по ID свойства (ID свойства = 15):
$GLOBALS['arrFilter'] = array('PROPERTY_15_VALUE' => 'Yes');
4. Пространственная фильтрация
-
Элементы раздела:
$GLOBALS['arrFilter'] = array('SECTION_ID' => 90); -
Наличие на складе:
$GLOBALS['arrFilter'] = array( '>CATALOG_STORE_AMOUNT_1' => 0, // ID склада = 1 '>CATALOG_PRICE_5' => 0 // ID типа цены = 5 );
Расширенные условия выборки
Операторы сравнения
| Оператор | Описание | Пример |
|---|---|---|
!
|
Не равно |
'!ID' => 10
|
><
|
Между |
'><DATE_ACTIVE_FROM' => array($from, $to)
|
!><
|
Не между |
'!><PRICE' => array(100, 200)
|
false
|
без значения |
Специфика работы с датами
1. Форматы данных
-
Встроенные поля (DATE_ACTIVE_FROM):\ Используйте формат
DD.MM.YYYY HH:MM:SS$filter = array('>=DATE_ACTIVE_FROM' => '01.01.2023 00:00:00'); -
НЕ встроенные поля : При поиске по НЕ встроенным полям (НЕ «начало активности», НЕ «конец активности») обязательно конвертировать дату в формат хранения
YYYY-MM-DD HH:MI:SS(DateTime::format('Y-m-d H:i:s')), например выбор записей не старше 31 дня:$dateNow = new DateTime('now', new DateTimeZone('UTC')); $dateNow->modify('-31 day'); $arFilter['>=PROPERTY_PAY_DATE'] = $dateNow->format('Y-m-d H:i:s');Выбрать записи не старше 31 дня
$now = new DateTime(); $arFilter = array(">DATE_CREATE" => $now->modify('-31 day')->format('d.m.Y H:i:s')); -
Пользовательские свойства (тип Дата):\ Применяйте формат
YYYY-MM-DD HH:MM:SS$date = (new DateTime())->format('Y-m-d H:i:s'); $filter = array('>=PROPERTY_CUSTOM_DATE' => $date);
2. Практические кейсы
-
Новости за текущий месяц:
$from = (new DateTime('first day of this month'))->format('d.m.Y H:i:s'); $to = (new DateTime('last day of this month'))->format('d.m.Y H:i:s'); $GLOBALS['arrFilter'] = array('><DATE_ACTIVE_FROM' => array($from, $to)); -
Активные события на дату:
$targetDate = (new DateTime('2023-10-01'))->format('d.m.Y H:i:s'); $filter = array( '<=DATE_ACTIVE_FROM' => $targetDate, '>=DATE_ACTIVE_TO' => $targetDate );
Оптимизация производительности
Для сложных выборок используйте прямое обращение к БД:
$query = $DB->Query("
SELECT ID, NAME
FROM b_iblock_element
WHERE
IBLOCK_ID = 10 AND
ACTIVE_FROM BETWEEN '2023-01-01' AND '2023-12-31'
ORDER BY DATE_CREATE DESC
");
Рекомендация: При работе с прямыми SQL-запросами учитывайте структуру таблиц (b_iblock_element, b_iblock_property) и используйте подготовленные выражения для защиты от SQL-инъекций.
ЕЩЕ ФИЛЬТРЫ
Выбор новостей за день или за месяц
Если у новости ее датой является «начало активности», и нет продолжительности по времени, то есть «конец активности» несет смысл только снятия ее с публикации, то выбор новостей за день или месяц происходит так:
<?php
$BITRIX_DATETIME_FORMAT = 'd.m.Y H:i:s';
$activeYear = isset($_REQUEST['year']) ? (int)$_REQUEST['year'] : null;
$activeMonth = isset($_REQUEST['month']) ? (int)$_REQUEST['month'] : null;
$activeDay = isset($_REQUEST['day']) ? (int)$_REQUEST['day'] : null;
$activeCompany = isset($_REQUEST['company']) ? (int)$_REQUEST['company'] : null;
$arFilter = array("IBLOCK_ID"=>BlockId::_()->news);
switch(true) {
case isset($activeDay) && isset($activeMonth) && isset($activeYear): // новости за день
$dateBegin = new DateTime(sprintf('%1$04d-%2$02d-%3$02d 00:00:00', $activeYear, $activeMonth, $activeDay), new DateTimeZone('UTC'));
$dateEnd = clone $dateBegin;
$dateEnd->modify('+1 day -1 second');
break;
case isset($activeMonth) && isset($activeYear): // новости за месяц
$dateBegin = new DateTime(sprintf('%1$04d-%2$02d-%3$02d 00:00:00', $activeYear, $activeMonth, $activeDay), new DateTimeZone('UTC'));
$dateEnd = clone $dateBegin;
$dateEnd->modify('+1 month -1 second');
break;
default:
}
if (isset($dateBegin) && isset($dateEnd)) {
$arFilter['><DATE_ACTIVE_FROM'] = array($dateBegin->format($BITRIX_DATETIME_FORMAT), $dateEnd->format($BITRIX_DATETIME_FORMAT));
}
$GLOBALS['arFilter'] = $arFilter;
Выбор событий с интервалом
Допустим, событие (акция) имеет продолжительность, которую указываем в полях «начало активности» и «конец активности», без учета времени, только дата.
«Конец активности» в данном случае служит для указания конца интервала времени, а не снятия с публикации (хотя такое тоже возможно).
Тогда выбор текущего события выглядит так:
$BITRIX_DATETIME_FORMAT = 'd.m.Y H:i:s';
$arFilter = array("IBLOCK_ID" => $this->arParams['IBLOCK_ID'], "ACTIVE"=>"Y");
$arSort = array("SORT" => "DESC");
$arSelect = array("IBLOCK_ID", "ID", "CODE", "NAME", "PREVIEW_TEXT", "PREVIEW_PICTURE", "ACTIVE_FROM", "ACTIVE_TO", "TAGS");
// для архива событий на определенную дату
$dateBegin = new DateTime(sprintf('%1$04d-%2$02d-%3$02d 00:00:00', $_REQUEST['year'], $_REQUEST['month'], $_REQUEST['day']), new DateTimeZone('UTC'));
// для актуальных событий
$dateBegin = new DateTime(sprintf('%1$04d-%2$02d-%3$02d 00:00:00', date('Y'), date('m'), date('d')), new DateTimeZone('UTC'));
$arDayFilter = $arFilter;
$dateEnd = clone $dateBegin;
$dateBegin->modify('+1 day -1 second');
$arDayFilter['<=DATE_ACTIVE_FROM'] = $dateBegin->format($BITRIX_DATETIME_FORMAT);
$arDayFilter['>=DATE_ACTIVE_TO'] = $dateEnd->format($BITRIX_DATETIME_FORMAT);
$itemsListDay = CIBlockElement::GetList($arSort, $arDayFilter, false, false, $arSelect);
Быстрый выбор новостей в календарь за месяц из нескольких инфоблоков
Высокая скорость обеспечивается прямым обращением к базе данных. В качестве даты новости - поле «Начало активности».
$this-\>arParams['IBLOCK_ID'] - массив номеров инфоблоков
class BAEventsEngine {
const MYSQL_DATETIME_FORMAT = 'Y-m-d H:i:s';
public function getDates($year, $month) {
global $DB;
$dates = array();
$monthDates = array();
$this->calcStartEndDate($year, $month);
$query = "SELECT EXTRACT(DAY FROM `ACTIVE_FROM`) AS `day`, `PREVIEW_PICTURE` as `pic`, `NAME` as `name`, `ACTIVE_TO` as `act_to`
FROM `b_iblock_element`
WHERE IBLOCK_ID IN (".implode(', ', (array)$this->arParams['IBLOCK_ID']).")
AND ACTIVE = 'Y'
AND (ACTIVE_FROM BETWEEN '".$this->dateBegin->format(self::MYSQL_DATETIME_FORMAT)."' AND '".$this->dateEnd->format(self::MYSQL_DATETIME_FORMAT)."')
ORDER BY SORT";
$CDatabaseRes = $DB->Query($query, false, '');
if ($CDatabaseRes->SelectedRowsCount() > 0) {
while ($result = $CDatabaseRes->Fetch()) {
$day =& $dates[$result['day']];
if(!isset($day)) $day = array();
if(!isset($day['pic'])) {
$day['pic'] = $result['pic'];
}
if($result['act_to'] == null) {
$monthDates[100][] = $result;
} else {
$monthDates[$result['day']][] = $result;
}
}
unset($day);
ksort($monthDates);
}
return array($dates, $monthDates);
}
private $dateBegin, $dateEnd;
private function calcStartEndDate($year, $month) {
$this->dateBegin = new DateTime(sprintf('%1$04d-%2$02d-%3$02d 00:00:00', $year, $month, 1), new DateTimeZone('UTC'));
$this->dateEnd = clone($this->dateBegin);
$this->dateEnd->modify("+1 month -1 second");
}
}
Если события в таком календаре имеют продолжительность, возможно узнать, активно ли событие активность в данный день. Перед $query вставить:
$dayActivites = $this->isDaysActiveCond($this->dateBegin);
Модифицировать $query:
$query = "SELECT EXTRACT(DAY FROM `ACTIVE_FROM`) AS `day`, `PREVIEW_PICTURE` as `pic`, `NAME` as `name`, `ACTIVE_TO` as `act_to`, {$dayActivites} ..." private function isDaysActiveCond($date) {
$cond = array();
$numDaysInMonth = $date->format('t');
$year = $date->format('Y');
$month = $date->format('m');
for($i = 1; $i <= $numDaysInMonth; $i++) {
$day = sprintf('%1$02d', $i);
$cond[] = "(`ACTIVE_FROM` <= '{$year}-{$month}-{$day} 23:59:59' AND `ACTIVE_TO` >= '{$year}-{$month}-{$day} 00:00:00') AS `day_{$i}`";
}
return implode(', ', $cond);
Таким образом в выборку попадут поля day_1, day_2, ..., содержащие признак активности события в этот день (1).