Битрикс. 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 • База данных • Битрикс • Запрос • Инфоблок • Новое ядро • Сущность • Таблица