Битрикс. ORM в новом ядре
27.10.2018
Теги: CMS • ORM • Web-разработка • БазаДанных • Битрикс • Запрос • Инфоблок • НовоеЯдро
Реализация ORM в ядре D7 призвана абстрагировать разработчика от механики работы с таблицами на уровне запросов к БД, введя понятие сущности и поля сущности. Сущность — это таблица, поля сущности — столбцы или «ссылки» на другие сущности, а DataManager
— система управления данными. Для каждой сущности нужно создать описание, например:
<?php /* * Файл /bitrix/modules/iblock/lib/element.php */ namespace Bitrix\Iblock; use Bitrix\Main, Bitrix\Main\Localization\Loc; Loc::loadMessages(__FILE__); /** * Class ElementTable * * Fields: * ID int mandatory * TIMESTAMP_X datetime optional * MODIFIED_BY int optional * DATE_CREATE datetime optional * CREATED_BY int optional * IBLOCK_ID int mandatory * IBLOCK_SECTION_ID int optional * ACTIVE bool optional default 'Y' * ACTIVE_FROM datetime optional * ACTIVE_TO datetime optional * SORT int optional default 500 * NAME string(255) mandatory * PREVIEW_PICTURE int optional * PREVIEW_TEXT string optional * PREVIEW_TEXT_TYPE enum ('text', 'html') optional default 'text' * DETAIL_PICTURE int optional * DETAIL_TEXT string optional * DETAIL_TEXT_TYPE enum ('text', 'html') optional default 'text' * SEARCHABLE_CONTENT string optional * WF_STATUS_ID int optional default 1 * WF_PARENT_ELEMENT_ID int optional * WF_NEW string(1) optional * WF_LOCKED_BY int optional * WF_DATE_LOCK datetime optional * WF_COMMENTS string optional * IN_SECTIONS bool optional default 'N' * XML_ID string(255) optional * CODE string(255) optional * TAGS string(255) optional * TMP_ID string(40) optional * WF_LAST_HISTORY_ID int optional * SHOW_COUNTER int optional * SHOW_COUNTER_START datetime optional * PREVIEW_PICTURE reference to {@link \Bitrix\File\FileTable} * DETAIL_PICTURE reference to {@link \Bitrix\File\FileTable} * IBLOCK reference to {@link \Bitrix\Iblock\IblockTable} * WF_PARENT_ELEMENT reference to {@link \Bitrix\Iblock\IblockElementTable} * IBLOCK_SECTION reference to {@link \Bitrix\Iblock\IblockSectionTable} * MODIFIED_BY reference to {@link \Bitrix\User\UserTable} * CREATED_BY reference to {@link \Bitrix\User\UserTable} * WF_LOCKED_BY reference to {@link \Bitrix\User\UserTable} * * @package Bitrix\Iblock **/ class ElementTable extends Main\Entity\DataManager { /** * Returns DB table name for entity. * * @return string */ public static function getTableName() { return 'b_iblock_element'; } /** * Returns entity map definition. * * @return array */ public static function getMap() { return array( 'ID' => array( // Идентификатор 'data_type' => 'integer', 'primary' => true, 'autocomplete' => true, 'title' => Loc::getMessage('ELEMENT_ENTITY_ID_FIELD'), ), 'TIMESTAMP_X' => array( // Дата изменения 'data_type' => 'datetime', 'title' => Loc::getMessage('ELEMENT_ENTITY_TIMESTAMP_X_FIELD'), ), 'MODIFIED_BY' => array( // Кто изменил 'data_type' => 'integer', 'title' => Loc::getMessage('ELEMENT_ENTITY_MODIFIED_BY_FIELD'), ), 'DATE_CREATE' => array( // Дата создания 'data_type' => 'datetime', 'title' => Loc::getMessage('ELEMENT_ENTITY_DATE_CREATE_FIELD'), ), 'CREATED_BY' => array( // Кто создал 'data_type' => 'integer', 'title' => Loc::getMessage('ELEMENT_ENTITY_CREATED_BY_FIELD'), ), 'IBLOCK_ID' => array( // Идентификатор инфоблока 'data_type' => 'integer', 'required' => true, 'title' => Loc::getMessage('ELEMENT_ENTITY_IBLOCK_ID_FIELD'), ), 'IBLOCK_SECTION_ID' => array( // Основной раздел 'data_type' => 'integer', 'title' => Loc::getMessage('ELEMENT_ENTITY_IBLOCK_SECTION_ID_FIELD'), ), 'ACTIVE' => array( // Активность 'data_type' => 'boolean', 'values' => array('N', 'Y'), 'title' => Loc::getMessage('ELEMENT_ENTITY_ACTIVE_FIELD'), ), 'ACTIVE_FROM' => array( // Дата начала активности 'data_type' => 'datetime', 'title' => Loc::getMessage('ELEMENT_ENTITY_ACTIVE_FROM_FIELD'), ), 'ACTIVE_TO' => array( // Дата окончания активности 'data_type' => 'datetime', 'title' => Loc::getMessage('ELEMENT_ENTITY_ACTIVE_TO_FIELD'), ), 'SORT' => array( // Индекс сортировки 'data_type' => 'integer', 'title' => Loc::getMessage('ELEMENT_ENTITY_SORT_FIELD'), ), 'NAME' => array( // Наименование 'data_type' => 'string', 'required' => true, 'validation' => array(__CLASS__, 'validateName'), 'title' => Loc::getMessage('ELEMENT_ENTITY_NAME_FIELD'), ), 'PREVIEW_PICTURE' => array( // Картинка анонса 'data_type' => 'integer', 'title' => Loc::getMessage('ELEMENT_ENTITY_PREVIEW_PICTURE_FIELD'), ), 'PREVIEW_TEXT' => array( // Описание для анонса 'data_type' => 'text', 'title' => Loc::getMessage('ELEMENT_ENTITY_PREVIEW_TEXT_FIELD'), ), 'PREVIEW_TEXT_TYPE' => array( // Тип описания для анонса 'data_type' => 'enum', 'values' => array('text', 'html'), 'title' => Loc::getMessage('ELEMENT_ENTITY_PREVIEW_TEXT_TYPE_FIELD'), ), 'DETAIL_PICTURE' => array( // Детальная картинка 'data_type' => 'integer', 'title' => Loc::getMessage('ELEMENT_ENTITY_DETAIL_PICTURE_FIELD'), ), 'DETAIL_TEXT' => array( // Детальное описание 'data_type' => 'text', 'title' => Loc::getMessage('ELEMENT_ENTITY_DETAIL_TEXT_FIELD'), ), 'DETAIL_TEXT_TYPE' => array( // Тип детального описания 'data_type' => 'enum', 'values' => array('text', 'html'), 'title' => Loc::getMessage('ELEMENT_ENTITY_DETAIL_TEXT_TYPE_FIELD'), ), 'SEARCHABLE_CONTENT' => array( // Поисковый индекс 'data_type' => 'text', 'title' => Loc::getMessage('ELEMENT_ENTITY_SEARCHABLE_CONTENT_FIELD'), ), 'WF_STATUS_ID' => array( // Статус в документообороте 'data_type' => 'integer', 'title' => Loc::getMessage('ELEMENT_ENTITY_WF_STATUS_ID_FIELD'), ), 'WF_PARENT_ELEMENT_ID' => array( // Элемент-родитель 'data_type' => 'integer', 'title' => Loc::getMessage('ELEMENT_ENTITY_WF_PARENT_ELEMENT_ID_FIELD'), ), 'WF_NEW' => array( // Флаг публикации черновика 'data_type' => 'string', 'validation' => array(__CLASS__, 'validateWfNew'), 'title' => Loc::getMessage('ELEMENT_ENTITY_WF_NEW_FIELD'), ), 'WF_LOCKED_BY' => array( // Кто заблокировал 'data_type' => 'integer', 'title' => Loc::getMessage('ELEMENT_ENTITY_WF_LOCKED_BY_FIELD'), ), 'WF_DATE_LOCK' => array( // Дата блокировки 'data_type' => 'datetime', 'title' => Loc::getMessage('ELEMENT_ENTITY_WF_DATE_LOCK_FIELD'), ), 'WF_COMMENTS' => array( // Комментарий документооборота 'data_type' => 'text', 'title' => Loc::getMessage('ELEMENT_ENTITY_WF_COMMENTS_FIELD'), ), 'IN_SECTIONS' => array( // Входит в разделы инфоблока 'data_type' => 'boolean', 'values' => array('N', 'Y'), 'title' => Loc::getMessage('ELEMENT_ENTITY_IN_SECTIONS_FIELD'), ), 'XML_ID' => array( // Внешний код 'data_type' => 'string', 'validation' => array(__CLASS__, 'validateXmlId'), 'title' => Loc::getMessage('ELEMENT_ENTITY_XML_ID_FIELD'), ), 'CODE' => array( // Символьный код 'data_type' => 'string', 'validation' => array(__CLASS__, 'validateCode'), 'title' => Loc::getMessage('ELEMENT_ENTITY_CODE_FIELD'), ), 'TAGS' => array( // Теги 'data_type' => 'string', 'validation' => array(__CLASS__, 'validateTags'), 'title' => Loc::getMessage('ELEMENT_ENTITY_TAGS_FIELD'), ), 'TMP_ID' => array( // Временный код 'data_type' => 'string', 'validation' => array(__CLASS__, 'validateTmpId'), 'title' => Loc::getMessage('ELEMENT_ENTITY_TMP_ID_FIELD'), ), 'WF_LAST_HISTORY_ID' => array( 'data_type' => 'integer', 'title' => Loc::getMessage('ELEMENT_ENTITY_WF_LAST_HISTORY_ID_FIELD'), ), 'SHOW_COUNTER' => array( // Количество показов 'data_type' => 'integer', 'title' => Loc::getMessage('ELEMENT_ENTITY_SHOW_COUNTER_FIELD'), ), 'SHOW_COUNTER_START' => array( // Дата первого показа 'data_type' => 'datetime', 'title' => Loc::getMessage('ELEMENT_ENTITY_SHOW_COUNTER_START_FIELD'), ), 'PREVIEW_PICTURE' => array( 'data_type' => 'Bitrix\File\File', 'reference' => array('=this.PREVIEW_PICTURE' => 'ref.ID'), ), 'DETAIL_PICTURE' => array( 'data_type' => 'Bitrix\File\File', 'reference' => array('=this.DETAIL_PICTURE' => 'ref.ID'), ), 'IBLOCK' => array( 'data_type' => 'Bitrix\Iblock\Iblock', 'reference' => array('=this.IBLOCK_ID' => 'ref.ID'), ), 'WF_PARENT_ELEMENT' => array( 'data_type' => 'Bitrix\Iblock\IblockElement', 'reference' => array('=this.WF_PARENT_ELEMENT_ID' => 'ref.ID'), ), 'IBLOCK_SECTION' => array( 'data_type' => 'Bitrix\Iblock\IblockSection', 'reference' => array('=this.IBLOCK_SECTION_ID' => 'ref.ID'), ), 'MODIFIED_BY' => array( 'data_type' => 'Bitrix\User\User', 'reference' => array('=this.MODIFIED_BY' => 'ref.ID'), ), 'CREATED_BY' => array( 'data_type' => 'Bitrix\User\User', 'reference' => array('=this.CREATED_BY' => 'ref.ID'), ), 'WF_LOCKED_BY' => array( 'data_type' => 'Bitrix\User\User', 'reference' => array('=this.WF_LOCKED_BY' => 'ref.ID'), ), ); } /** * Returns validators for NAME field. * * @return array */ public static function validateName() { return array( new Main\Entity\Validator\Length(null, 255), ); } /** * Returns validators for WF_NEW field. * * @return array */ public static function validateWfNew() { return array( new Main\Entity\Validator\Length(null, 1), ); } /** * Returns validators for XML_ID field. * * @return array */ public static function validateXmlId() { return array( new Main\Entity\Validator\Length(null, 255), ); } /** * Returns validators for CODE field. * * @return array */ public static function validateCode() { return array( new Main\Entity\Validator\Length(null, 255), ); } /** * Returns validators for TAGS field. * * @return array */ public static function validateTags() { return array( new Main\Entity\Validator\Length(null, 255), ); } /** * Returns validators for TMP_ID field. * * @return array */ public static function validateTmpId() { return array( new Main\Entity\Validator\Length(null, 40), ); } }
Класс описывает таблицу БД b_iblock_element
, которая хранит элементы инфоблоков:
-- -- Структура таблицы `b_iblock_element` -- CREATE TABLE `b_iblock_element` ( `ID` int(11) NOT NULL, `TIMESTAMP_X` datetime DEFAULT NULL, `MODIFIED_BY` int(18) DEFAULT NULL, `DATE_CREATE` datetime DEFAULT NULL, `CREATED_BY` int(18) DEFAULT NULL, `IBLOCK_ID` int(11) NOT NULL DEFAULT '0', `IBLOCK_SECTION_ID` int(11) DEFAULT NULL, `ACTIVE` char(1) COLLATE utf8_unicode_ci NOT NULL DEFAULT 'Y', `ACTIVE_FROM` datetime DEFAULT NULL, `ACTIVE_TO` datetime DEFAULT NULL, `SORT` int(11) NOT NULL DEFAULT '500', `NAME` varchar(255) COLLATE utf8_unicode_ci NOT NULL, `PREVIEW_PICTURE` int(18) DEFAULT NULL, `PREVIEW_TEXT` text COLLATE utf8_unicode_ci, `PREVIEW_TEXT_TYPE` varchar(4) COLLATE utf8_unicode_ci NOT NULL DEFAULT 'text', `DETAIL_PICTURE` int(18) DEFAULT NULL, `DETAIL_TEXT` longtext COLLATE utf8_unicode_ci, `DETAIL_TEXT_TYPE` varchar(4) COLLATE utf8_unicode_ci NOT NULL DEFAULT 'text', `SEARCHABLE_CONTENT` text COLLATE utf8_unicode_ci, `WF_STATUS_ID` int(18) DEFAULT '1', `WF_PARENT_ELEMENT_ID` int(11) DEFAULT NULL, `WF_NEW` char(1) COLLATE utf8_unicode_ci DEFAULT NULL, `WF_LOCKED_BY` int(18) DEFAULT NULL, `WF_DATE_LOCK` datetime DEFAULT NULL, `WF_COMMENTS` text COLLATE utf8_unicode_ci, `IN_SECTIONS` char(1) COLLATE utf8_unicode_ci NOT NULL DEFAULT 'N', `XML_ID` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL, `CODE` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL, `TAGS` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL, `TMP_ID` varchar(40) COLLATE utf8_unicode_ci DEFAULT NULL, `WF_LAST_HISTORY_ID` int(11) DEFAULT NULL, `SHOW_COUNTER` int(18) DEFAULT NULL, `SHOW_COUNTER_START` datetime DEFAULT NULL ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; -- -- Индексы таблицы `b_iblock_element` -- ALTER TABLE `b_iblock_element` ADD PRIMARY KEY (`ID`), ADD KEY `ix_iblock_element_1` (`IBLOCK_ID`,`IBLOCK_SECTION_ID`), ADD KEY `ix_iblock_element_4` (`IBLOCK_ID`,`XML_ID`,`WF_PARENT_ELEMENT_ID`), ADD KEY `ix_iblock_element_3` (`WF_PARENT_ELEMENT_ID`), ADD KEY `ix_iblock_element_code` (`IBLOCK_ID`,`CODE`); -- -- AUTO_INCREMENT для таблицы `b_iblock_element` -- ALTER TABLE `b_iblock_element` MODIFY `ID` int(11) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=357; COMMIT;
В методе getMap()
перечислены все поля таблицы, включая описание связей с другими сущностями. Таким образом указано отношение столбца IBLOCK_ID
текущей таблицы и столбца ID
сущности Iblock
. В дальнейшем по reference-полям возможно выбирать поля связанных сущностей и использовать их в фильтрах.
'IBLOCK' => array( 'data_type' => 'Bitrix\Iblock\Iblock', 'reference' => array('=this.IBLOCK_ID' => 'ref.ID'), )
orm=y
в адрес:
/bitrix/admin/perfmon_tables.php?lang=ru&orm=y
Выполнение запросов
Тренироваться будем на таблицах типов инфоблока, самих инфоблоков, элементов и разделов. Для них описаны сущности TypeTable
, IblockTable
, ElementTable
и SectionTable
, их можно посмотреть в исходниках модуля iblock
.
Пример № 1
Выбираем элементы инфоблока с идентификатором 5:
Bitrix\Main\Loader::includeModule('iblock'); // создаем объект Query, в качестве параметра передаем объект сущности (элемент инфоблока) $query = new Bitrix\Main\Entity\Query( Bitrix\Iblock\ElementTable::getEntity() ); // выбираем идентификатор элемента, символьный код и наименование $query->setSelect(array('ID', 'CODE', 'NAME')) // идентификатор инфоблока равен 5 ->setFilter(array('IBLOCK_ID' => 5)) // сортируем элементы по идентификатору, по возрастанию ->setOrder(array('ID' => 'ASC')) // выбираем только три элемента ->setLimit(3); // посмотрим, какой запрос был сформирован echo $query->getQuery(); // выполняем запрос $result = $query->exec(); // выводим результат while ($row = $result->fetch()) { debug($row); }
SELECT `iblock_element`.`ID` AS `ID`, `iblock_element`.`CODE` AS `CODE`, `iblock_element`.`NAME` AS `NAME` FROM `b_iblock_element` `iblock_element` WHERE `iblock_element`.`IBLOCK_ID` = 5 ORDER BY `ID` ASC LIMIT 0, 3
Array ( [ID] => 347 [CODE] => angliyskiy-buldog [NAME] => Английский бульдог ) Array ( [ID] => 348 [CODE] => dalmatin [NAME] => Далматин ) Array ( [ID] => 349 [CODE] => afganskaya-borzaya [NAME] => Афганская борзая )
Список методов Bitrix\Main\Entity\Query
:
setSelect()
,setGroup()
— устанавливает массив с именами полейaddSelect()
,addGroup()
— добавляет имя поляgetSelect()
,getGroup()
— возвращает массив с именами полей
setFilter()
— устанавливает одно- или многомерный массив с описанием фильтраaddFilter()
— добавляет один параметр фильтра со значениемgetFilter()
— возвращает текущее описание фильтра
setOrder()
— устанавливает массив с именами полей и порядком сортировкиaddOrder()
— добавляет одно поле с порядком сортировкиgetOrder()
— возвращает текущее описание сортировки
setLimit()
,setOffset()
— устанавливает значениеgetLimit()
,getOffset()
— возвращает текущее значение
registerRuntimeField()
— регистрирует новое временное поле для исходной сущности
Пример № 2
Через сущность «элемент» можно выбирать или ставить условия на поля связанной сущности «инфоблок». Связанная таблица по умолчанию присоединяется с помощью LEFT JOIN
. Вспомним reference-поле IBLOCK
в описании ElementTable
и выберем данные самого инфоблока вместе с элементами инфоблока:
Bitrix\Main\Loader::includeModule('iblock'); // создаем объект Query, в качестве параметра передаем объект сущности (элемент инфоблока) $query = new Bitrix\Main\Entity\Query( Bitrix\Iblock\ElementTable::getEntity() ); $query->setSelect(array('ID', 'CODE', 'NAME', 'IBLOCK.ID', 'IBLOCK.CODE', 'IBLOCK.NAME')) ->setFilter(array('IBLOCK.ID' => 5)) // так тоже можно // ->setFilter(array('IBLOCK_ID' => 5)) ->setOrder(array('ID' => 'ASC')) ->setLimit(3); // посмотрим, какой запрос был сформирован echo $query->getQuery(); // выполняем запрос $result = $query->exec(); // выводим результат while ($row = $result->fetch()) { debug($row); }
SELECT `iblock_element`.`ID` AS `ID`, `iblock_element`.`CODE` AS `CODE`, `iblock_element`.`NAME` AS `NAME`, `iblock_element_iblock`.`ID` AS `IBLOCK_ELEMENT_IBLOCK_ID`, `iblock_element_iblock`.`CODE` AS `IBLOCK_ELEMENT_IBLOCK_CODE`, `iblock_element_iblock`.`NAME` AS `IBLOCK_ELEMENT_IBLOCK_NAME` FROM `b_iblock_element` `iblock_element` LEFT JOIN `b_iblock` `iblock_element_iblock` ON `iblock_element`.`IBLOCK_ID` = `iblock_element_iblock`.`ID` WHERE `iblock_element_iblock`.`ID` = 5 ORDER BY `ID` ASC LIMIT 0, 3
Array ( [ID] => 347 [CODE] => angliyskiy-buldog [NAME] => Английский бульдог [IBLOCK_ELEMENT_IBLOCK_ID] => 5 [IBLOCK_ELEMENT_IBLOCK_CODE] => articles [IBLOCK_ELEMENT_IBLOCK_NAME] => Статьи о домашних животных ) Array ( [ID] => 348 [CODE] => dalmatin [NAME] => Далматин [IBLOCK_ELEMENT_IBLOCK_ID] => 5 [IBLOCK_ELEMENT_IBLOCK_CODE] => articles [IBLOCK_ELEMENT_IBLOCK_NAME] => Статьи о домашних животных ) Array ( [ID] => 349 [CODE] => afganskaya-borzaya [NAME] => Афганская борзая [IBLOCK_ELEMENT_IBLOCK_ID] => 5 [IBLOCK_ELEMENT_IBLOCK_CODE] => articles [IBLOCK_ELEMENT_IBLOCK_NAME] => Статьи о домашних животных )
Пример № 3
В запросах можно использовать агрегатные функции MySQL. Для это служит метод registerRuntimeField()
, регистрирующий новое поле на время выполнения запроса. Посмотрим, сколько активных элементов в инфоблоке:
Bitrix\Main\Loader::includeModule('iblock'); // создаем объект Query, в качестве параметра передаем объект сущности (элемент инфоблока) $query = new Bitrix\Main\Entity\Query( Bitrix\Iblock\ElementTable::getEntity() ); $query->registerRuntimeField( 'ACTIVE_ELEMENTS', array( // тип вычисляемого поля 'data_type' => 'string', // агрегатная функция (COUNT, MAX, MIN, SUM, AVG) и поле для подстановки 'expression' => array('GROUP_CONCAT(%s)', 'NAME') ) ); $query->setSelect(array('IBLOCK.NAME', 'ACTIVE_ELEMENTS')); $query->setFilter(array('IBLOCK.ID' => 5, '=ACTIVE' => 'Y')); // посмотрим, какой запрос был сформирован echo $query->getQuery(); // выполняем запрос $result = $query->exec(); // выводим результат while ($row = $result->fetch()) { debug($row); }
SELECT `iblock_element_iblock`.`NAME` AS `IBLOCK_ELEMENT_IBLOCK_NAME`, GROUP_CONCAT(`iblock_element`.`NAME`) AS `ACTIVE_ELEMENTS` FROM `b_iblock_element` `iblock_element` LEFT JOIN `b_iblock` `iblock_element_iblock` ON `iblock_element`.`IBLOCK_ID` = `iblock_element_iblock`.`ID` WHERE `iblock_element_iblock`.`ID` = 5 AND `iblock_element`.`ACTIVE` = 'Y' GROUP BY `iblock_element_iblock`.`NAME`
Array ( [IBLOCK_ELEMENT_IBLOCK_NAME] => Статьи о домашних животных [ACTIVE_ELEMENTS] => Английский бульдог,Далматин,Афганская борзая,Абиссинская кошка,Сиамская кошка,Американский бобтейл,Британская короткошерстная,Лабрадор,Лайка )
Пример № 4
Выбираем разделы инфоблока с идентифкатором 5 и подсчитываем количество элементов в каждом; учитываем только активные разделы и элементы:
Bitrix\Main\Loader::includeModule('iblock'); // создаем объект Query, в качестве параметра передаем объект сущности (элемент инфоблока) $query = new Bitrix\Main\Entity\Query( Bitrix\Iblock\ElementTable::getEntity() ); $query->registerRuntimeField( 'ELEMENT_COUNT', array( // тип вычисляемого поля 'data_type' => 'integer', // агрегатная функция (COUNT, MAX, MIN, SUM, AVG) и поле для подстановки 'expression' => array('COUNT(%s)', 'NAME') ) ); $query->registerRuntimeField( 'ELEMENT_LIST', array( // тип вычисляемого поля 'data_type' => 'string', // агрегатная функция (COUNT, MAX, MIN, SUM, AVG) и поле для подстановки 'expression' => array('GROUP_CONCAT(%s)', 'NAME') ) ); $query->setSelect(array('IBLOCK_SECTION.NAME', 'ELEMENT_COUNT', 'ELEMENT_LIST')); // учитываем только активные разделы и активные элементы $query->setFilter(array('=ACTIVE' => 'Y', '=IBLOCK_SECTION.ACTIVE' => 'Y')); // выбираем только разделы инфоблока с идентификатором 5 $query->addFilter('IBLOCK.ID', 5); // посмотрим, какой запрос был сформирован echo $query->getQuery(); // выполняем запрос $result = $query->exec(); // выводим результат while ($row = $result->fetch()) { debug($row); }
SELECT `iblock_element_iblock_section`.`NAME` AS `IBLOCK_ELEMENT_IBLOCK_SECTION_NAME`, COUNT(`iblock_element`.`NAME`) AS `ELEMENT_COUNT`, GROUP_CONCAT(`iblock_element`.`NAME`) AS `ELEMENT_LIST` FROM `b_iblock_element` `iblock_element` LEFT JOIN `b_iblock_section` `iblock_element_iblock_section` ON `iblock_element`.`IBLOCK_SECTION_ID` = `iblock_element_iblock_section`.`ID` LEFT JOIN `b_iblock` `iblock_element_iblock` ON `iblock_element`.`IBLOCK_ID` = `iblock_element_iblock`.`ID` WHERE `iblock_element`.`ACTIVE` = 'Y' AND `iblock_element_iblock_section`.`ACTIVE` = 'Y' AND `iblock_element_iblock`.`ID` = 5 GROUP BY `iblock_element_iblock_section`.`NAME`
Array ( [IBLOCK_ELEMENT_IBLOCK_SECTION_NAME] => Породы кошек [ELEMENT_COUNT] => 4 [ELEMENT_LIST] => Абиссинская кошка,Сиамская кошка,Американский бобтейл,Британская короткошерстная ) Array ( [IBLOCK_ELEMENT_IBLOCK_SECTION_NAME] => Породы собак [ELEMENT_COUNT] => 3 [ELEMENT_LIST] => Английский бульдог,Далматин,Афганская борзая ) Array ( [IBLOCK_ELEMENT_IBLOCK_SECTION_NAME] => Служебные породы [ELEMENT_COUNT] => 2 [ELEMENT_LIST] => Лабрадор,Лайка )
Добавим еще одно условие, чтобы выбирать только разделы, содержащие более трех элементов:
$query->addFilter('>ELEMENT_COUNT', 3);
SELECT `iblock_element_iblock_section`.`NAME` AS `IBLOCK_ELEMENT_IBLOCK_SECTION_NAME`, COUNT(`iblock_element`.`NAME`) AS `ELEMENT_COUNT`, GROUP_CONCAT(`iblock_element`.`NAME`) AS `ELEMENT_LIST` FROM `b_iblock_element` `iblock_element` LEFT JOIN `b_iblock_section` `iblock_element_iblock_section` ON `iblock_element`.`IBLOCK_SECTION_ID` = `iblock_element_iblock_section`.`ID` LEFT JOIN `b_iblock` `iblock_element_iblock` ON `iblock_element`.`IBLOCK_ID` = `iblock_element_iblock`.`ID` WHERE `iblock_element`.`ACTIVE` = 'Y' AND `iblock_element_iblock_section`.`ACTIVE` = 'Y' AND `iblock_element_iblock`.`ID` = 5 GROUP BY `iblock_element_iblock_section`.`NAME` HAVING COUNT(`iblock_element`.`NAME`) > 3
Array ( [IBLOCK_ELEMENT_IBLOCK_SECTION_NAME] => Породы кошек [ELEMENT_COUNT] => 4 [ELEMENT_LIST] => Абиссинская кошка,Сиамская кошка,Американский бобтейл,Британская короткошерстная )
Пример № 5
Runtime-поле может быть не только вычисляемым значением, но и ссылкой на другую сущность. Т.е. в методе getMap()
можно не описывать связь, а сформировать ее прямо в запросе. Например, создадим объект Query
для сущности IblockTable
, свяжем ее с ElementTable
и выберем элемент с ID=349
:
Bitrix\Main\Loader::includeModule('iblock'); // создаем объект Query, в качестве параметра передаем объект сущности (инфоблок) $query = new Bitrix\Main\Entity\Query( Bitrix\Iblock\IblockTable::getEntity() ); $query->registerRuntimeField( // поле element как ссылка на таблицу b_iblock_element 'element', array( // тип — сущность ElementTable 'data_type' => 'Bitrix\Iblock\ElementTable', // this.ID относится к таблице, относительно которой строится // запрос, т.е. b_iblock.ID = b_iblock_element.IBLOCK_ID 'reference' => array('=this.ID' => 'ref.IBLOCK_ID'), ) ); // выбираем название элемента, символьный код, краткое описание, кол-во просмотров и название инфоблока $query->setSelect(array('element.NAME', 'element.CODE', 'element.PREVIEW_TEXT', 'element.SHOW_COUNTER', 'NAME')); // выбираем только элемент с идентификатором 349 $query->setFilter(array('element.ID' => 349)); // посмотрим, какой запрос был сформирован echo $query->getQuery(); // выполняем запрос $result = $query->exec(); // выводим результат while ($row = $result->fetch()) { debug($row); }
SELECT `iblock_iblock_element`.`NAME` AS `IBLOCK_IBLOCK_element_NAME`, `iblock_iblock_element`.`CODE` AS `IBLOCK_IBLOCK_element_CODE`, `iblock_iblock_element`.`PREVIEW_TEXT` AS `IBLOCK_IBLOCK_element_PREVIEW_TEXT`, `iblock_iblock_element`.`SHOW_COUNTER` AS `IBLOCK_IBLOCK_element_SHOW_COUNTER`, `iblock_iblock`.`NAME` AS `NAME` FROM `b_iblock` `iblock_iblock` LEFT JOIN `b_iblock_element` `iblock_iblock_element` ON `iblock_iblock`.`ID` = `iblock_iblock_element`.`IBLOCK_ID` WHERE `iblock_iblock_element`.`ID` = 349
Array ( [IBLOCK_IBLOCK_element_NAME] => Афганская борзая [IBLOCK_IBLOCK_element_CODE] => afganskaya-borzaya [IBLOCK_IBLOCK_element_PREVIEW_TEXT] => Изящная красавица с длинной развевающейся на бегу шелковистой шерстью... [IBLOCK_IBLOCK_element_SHOW_COUNTER] => 10 [NAME] => Статьи о домашних животных )
Пример № 6
В определении runtime-reference-поля можно указывать тип соединения (LEFT
, RIGHT
, INNER
), а в фильтре использовать сложную логику, как в CIblockElement::GetList()
:
Bitrix\Main\Loader::includeModule('iblock'); // создаем объект Query, в качестве параметра передаем объект сущности (инфоблок) $query = new Bitrix\Main\Entity\Query( Bitrix\Iblock\IblockTable::getEntity() ); // поле element как ссылка на таблицу b_iblock_element $query->registerRuntimeField( 'element', array( // тип — сущность ElementTable 'data_type' => 'Bitrix\Iblock\ElementTable', // this.ID относится к таблице, относительно которой строится // запрос, т.е. b_iblock.ID = b_iblock_element.IBLOCK_ID 'reference' => array('=this.ID' => 'ref.IBLOCK_ID'), // тип соединения INNER JOIN 'join_type' => 'INNER' ) ); // поле type как ссылка на таблицу b_iblock_type $query->registerRuntimeField( 'type', array( 'data_type' => 'Bitrix\Iblock\TypeTable', 'reference' => array('=this.IBLOCK_TYPE_ID' => 'ref.ID'), 'join_type' => 'INNER' ) ); // выбираем название инфоблока, символьный код инфоблока, название элемента, // символьный код элемента и идентификатор типа инфоблока $query->setSelect(array('NAME', 'CODE', 'element.NAME', 'element.CODE', 'type.ID')); // выбираем элементы с идентификаторами 348 или 349 $query->setFilter( array( 'LOGIC' => 'OR', array('element.ID' => 348), array('element.ID' => 349), ) ); // посмотрим, какой запрос был сформирован echo $query->getQuery(); // выполняем запрос $result = $query->exec(); // выводим результат while ($row = $result->fetch()) { debug($row); }
SELECT `iblock_iblock`.`NAME` AS `NAME`, `iblock_iblock`.`CODE` AS `CODE`, `iblock_iblock_element`.`NAME` AS `IBLOCK_IBLOCK_element_NAME`, `iblock_iblock_element`.`CODE` AS `IBLOCK_IBLOCK_element_CODE`, `iblock_iblock_type`.`ID` AS `IBLOCK_IBLOCK_type_ID` FROM `b_iblock` `iblock_iblock` INNER JOIN `b_iblock_element` `iblock_iblock_element` ON `iblock_iblock`.`ID` = `iblock_iblock_element`.`IBLOCK_ID` INNER JOIN `b_iblock_type` `iblock_iblock_type` ON `iblock_iblock`.`IBLOCK_TYPE_ID` = `iblock_iblock_type`.`ID` WHERE (`iblock_iblock_element`.`ID` = 348) OR (`iblock_iblock_element`.`ID` = 349)
Array ( [NAME] => Статьи о домашних животных [CODE] => articles [IBLOCK_IBLOCK_element_NAME] => Далматин [IBLOCK_IBLOCK_element_CODE] => dalmatin [IBLOCK_IBLOCK_type_ID] => content ) Array ( [NAME] => Статьи о домашних животных [CODE] => articles [IBLOCK_IBLOCK_element_NAME] => Афганская борзая [IBLOCK_IBLOCK_element_CODE] => afganskaya-borzaya [IBLOCK_IBLOCK_type_ID] => content )
Пример № 7
Получаем пользовательские свойства элементов инфоблока с идентификатором 5:
Bitrix\Main\Loader::includeModule('iblock'); // создаем объект Query, в качестве параметра передаем объект сущности (свойства) $query = new Bitrix\Main\Entity\Query( Bitrix\Iblock\PropertyTable::getEntity() ); $query->setSelect(array('ID', 'NAME', 'CODE', 'PROPERTY_TYPE')); $query->setFilter(array('IBLOCK_ID' => 5)); // посмотрим, какой запрос был сформирован echo $query->getQuery(); // выполняем запрос $result = $query->exec(); // выводим результат while ($row = $result->fetch()) { debug($row); }
SELECT `iblock_property`.`ID` AS `ID`, `iblock_property`.`NAME` AS `NAME`, `iblock_property`.`CODE` AS `CODE`, `iblock_property`.`PROPERTY_TYPE` AS `PROPERTY_TYPE` FROM `b_iblock_property` `iblock_property` WHERE `iblock_property`.`IBLOCK_ID` = 5
Array ( [ID] => 47 [NAME] => Автор [CODE] => AUTHOR [PROPERTY_TYPE] => S ) Array ( [ID] => 48 [NAME] => Оценка [CODE] => RATING [PROPERTY_TYPE] => L ) Array ( [ID] => 49 [NAME] => Галерея [CODE] => GALLERY [PROPERTY_TYPE] => F ) Array ( [ID] => 51 [NAME] => Примечание [CODE] => NOTE [PROPERTY_TYPE] => S )
Поиск: CMS • DataManager • ElementTable • IblockTable • JOIN • ORM • SQL • SectionTable • Web-разработка • getEntity • query • registerRuntimeField • setFilter • setGroup • setLimit • setOrder • setSelect • table • База данных • Битрикс • Запрос • Инфоблок • Новое ядро • Сущность • Таблица