1С-Битрикс. Следующий/предыдущий элемент инфоблока с помощью ORM D7
Очередной пост в копилку ORM D7 в Битриксе. На этот раз будем получать соседей нужного элемента инфоблока. Под катом много кода.
Того же самого можно добиться методом CIBlockElement::GetList() с параметрами nElementID и nPageSize для постраничной навигации. SQL-запросы для определения соседей я честно от туда и взял.
//<?php \Bitrix\Main\Loader::includeModule('iblock'); // Сюда мы и запишем массивы соседних элементов $nextElement = null; $prevElement = null; // Id элемента, соседей которого надо выбрать $elementId = 104; $element = \Bitrix\Iblock\ElementTable::getRowById($elementId); $sectionId = $element['IBLOCK_SECTION_ID']; // Количество соседей (в примере моего кода поддерживается 1) $nPageSize = 1; // Устанавливаем нужный фильтр $filter = array( '=IBLOCK_ID' => $element['IBLOCK_ID'], '=ACTIVE' => 'Y', ); // Составляем запрос для фильтрации по секции элемента (поддерживает множественную привязку к разделам) $sectionElementSubQuery = new Bitrix\Main\Entity\Query('\Bitrix\Iblock\SectionElementTable'); $sectionElementSubQuery ->addSelect('IBLOCK_ELEMENT_ID') ->setFilter(array('=IBLOCK_SECTION_ID' => $sectionId)) ->registerRuntimeField('SECTION', array( 'data_type' => '\Bitrix\Iblock\SectionTable', 'reference' => array( '=this.IBLOCK_SECTION_ID' => 'ref.ID', ), 'join_type' => 'inner' )); // Сохраняем полученный sql-запрос, не выполняя его $sectionElementSubQuerySql = $sectionElementSubQuery->getQuery(); $sectionElementEntity = Bitrix\Main\Entity\Base::compileEntity('OlegproSectionElementEntity', array('IBLOCK_ELEMENT_ID' => array('data_type' => 'integer')), array('table_name' => sprintf('(%s)', $sectionElementSubQuerySql)) ); // Составляем sql-запрос для получение элементов с нужными фильтрами $querySiblingsElement = new Bitrix\Main\Entity\Query(Bitrix\Iblock\ElementTable::getEntity()); $querySiblingsElement ->setSelect(array( 'ID', 'NAME', 'CODE', 'DETAIL_PICTURE', 'IBLOCK_SECTION_ID', )) ->registerRuntimeField('SECTION_ELEMENT', array( 'data_type' => $sectionElementEntity->getDataClass(), 'reference' => array( '=this.ID' => 'ref.IBLOCK_ELEMENT_ID' ), 'join_type' => 'inner' )) ->setFilter($filter) ->addOrder('ID', 'DESC'); // Сохраняем полученный sql-запрос, не выполняя его $sqlQuerySiblingsElement = $querySiblingsElement->getQuery(); $connection = Bitrix\Main\Application::getConnection(); $connection->query('SET @rank=0'); $connection->query( sprintf(" SELECT @rank:=el1.rank FROM ( SELECT @rank:=@rank+1 AS rank, el0.* FROM ( %s ) el0 ) el1 WHERE el1.ID = %d ", $sqlQuerySiblingsElement, $elementId) ); $connection->query('SET @rank2=0'); $siblingsElementIterator = $connection->query( sprintf(" SELECT * FROM ( SELECT @rank2:=@rank2+1 AS RANK, el0.* FROM ( %s ) el0 ) el1 WHERE el1.RANK between @rank-%d and @rank+%d ", $sqlQuerySiblingsElement, $nPageSize, $nPageSize) ); $siblingsElements = array(); while ($siblingsElement = $siblingsElementIterator->fetch()) { $siblingsElements[] = $siblingsElement; } if (sizeof($siblingsElements) == 3) { list($prevElement, , $nextElement) = $siblingsElements; } elseif (sizeof($siblingsElements) == 2) { if ($siblingsElements[0]['ID'] != $elementId) { $prevElement = $siblingsElements[0]; } else { $nextElement = $siblingsElements[1]; } } echo '<pre>';print_r($prevElement);echo '</pre>'; echo '<pre>';print_r($nextElement);echo '</pre>';
Ну вот и всё. В переменных $prevElement и $nextElement будут массивы (или NULL, если таковых не найдётся) сдедующего и предыдущего соседа элемента с id = 104.
Это лишь простой пример составления запроса для получения соседей. В реале: у меня через runtime поля подключается кастомная таблица, в которой хранится индекс сортировки элемента, для конкретной категории (нужно для возможности независимой сортировки элемента в любой из категорий при множественной привязке к категориям). Как вы понимаете, CIBlockElement::GetList() тут не обойтись.