Работа с элементами инфоблоков через ORM и d7
Всё что написано ниже, применимо и к другим модулям, только названия таблиц будут другие. Многое можно узнать из файла /bitrix/modules/main/lib/orm/data/datamanager.php
Подключаем модуль:
\Bitrix\Main\Loader::includeModule('iblock');
После подключения модуля, нам становится доступен целый набор различных классов и методов для работы с данными инфоблоков. Существуют и другие методы для работы с инфоблоками, и это лишь часть из них. Наиболее часто используемые методы, это получение списков записей:
\Bitrix\Iblock\TypeTable::getList();
типы инфоблоков\Bitrix\Iblock\IblockTable::getList();
инфоблоки\Bitrix\Iblock\PropertyTable::getList();
свойства инфоблоков\Bitrix\Iblock\PropertyEnumerationTable::getList();
значения свойств, например списков\Bitrix\Iblock\SectionTable::getList();
разделы инфоблоков\Bitrix\Iblock\ElementTable::getList();
элементы инфоблоков\Bitrix\Iblock\InheritedPropertyTable::getList();
наследуемые свойства, seo шаблоны
Запрос в таблицу элементов инфоблока:
$res = \Bitrix\Iblock\ElementTable::getList(array(
// сортировка
'order' => array('SORT' => 'ASC'),
// выбираемые поля без свойств, свойства можно получать только при обращении к ORM классу, конкретного инфоблока
'select' => array('ID', 'NAME', 'IBLOCK_ID', 'SORT', 'TAGS'),
// фильтр только по полям элемента
'filter' => array('IBLOCK_ID' => 4),
// группировка по полю, order должен быть пустой
'group' => array('TAGS'),
// ограничение выбираемого кол-ва
'limit' => 1000,
// число, указывающее номер первого столбца в результате
'offset' => 0,
// дает возможность получить кол-во элементов через метод getCount()
'count_total' => 1,
// массив полей сущности, создающихся динамически
'runtime' => array(),
// разрешает получение нескольких одинаковых записей
'data_doubling' => false,
// кеш запроса
'cache' => array(
'ttl' => 3600,
'cache_joins' => true
),
));
Методы D7 для работы с данными инфоблоков
Кроме выборки данных посредством метода getList()
, мы можем выполнять и другие операции, для изменяя данных, удаления, получения id записей, количества, а так же другие операции с данными инфоблока:
add(array $data);
добавление элементаaddMulti($rows, $ignoreEvents = false);
множественное добавление элементовcheckFields(Result $result, $primary, array $data);
метод проверяет поля данных перед записью в БДdelete($primary);
удаление элемента по IDgetById($id);
получение элемента по IDgetByPrimary($primary, array $parameters = array());
метод возвращает выборку по первичному ключу сущности и по опциональным параметрам \Bitrix\Main\Entity\DataManager::getListgetConnectionName();
метод возвращает имя соединения для сущностиgetCount($filter = array(), array $cache = array());
метод выполняет COUNT запрос к сущности и возвращает результатgetEntity();
метод возвращает объект сущностиgetList(array $parameters = array());
получение элементовgetMap();
метод возвращает описание карты сущностейgetRow(array $parameters);
метод возвращает один столбец (или null) по параметрам для \Bitrix\Main\Entity\DataManager::getListgetRowById($id);
метод возвращает один столбец, или null по первичному ключу сущностиgetTableName();
метод возвращает имя таблицы БД для сущностиquery();
метод создаёт и возвращает объект запроса для сущностиupdate($primary, array $data);
обновление элемента по IDenableCrypto($field, $table = null, $mode = true);
метод устанавливает флаг поддержки шифрования для поляcryptoEnabled($field, $table = null);
метод возвращает true если шифрование разрешено для поля
Что можно сделать с $res
из примера выше:
Получение одной записи в виде массива, можно перебрать в цикле while
и получить все элементы:
while ($arItem = $res->fetch()) {
echo "<pre>";
print_r($arItem);
echo "</pre>";
}
Получение всех записей в виде массива:
echo "<pre>";
print_r($res->fetchAll());
echo "</pre>";
Получение одной записи в виде объекта:
while ($arItem = $res->fetchObject()) {
echo "<pre>";
print_r($arItem->getName());
echo "</pre>";
}
Получение всех записей в виде коллекции объектов:
foreach ($res->fetchCollection() as $element) {
echo "<pre>";
var_dump($element->getName());
echo "</pre>";
}
Количество найденных записей без учета limit
, доступно если при запросе было указано count_total = 1
:
echo "<pre>";
print_r($res->getCount());
echo "</pre>";
Количество полученных записей с учетом limit
, доступно если при запросе было указано count_total = 1
:
echo "<pre>";
print_r($res->getSelectedRowsCount());
echo "</pre>";
ORM класс для инфоблока
С выходом 20-й версии 1С Битрикс, появилась возможность работы с элементами инфоблока средствами ORM. Для начала необходимо зайти в настройки информационного блока и задать значения для поля Символьный код API
. Согласно документации, символьный код API это строка от 1 до 50 символов состоящая из букв и цифр, начинающаяся с буквы. Я взял инфоблок сврего проекта и задал код phpapi
:
Для работы с элементами инфоблока средствами ORM, необходимо использовать класс \Bitrix\Iblock\Elements\Element_символьный_код_API_инфоблока_Table
, в моём случае это класс \Bitrix\Iblock\Elements\ElementPhpapiTable
. Узнать какой класс именно отвечает за конкретный инфоблок, можно запустив скрипт из любого файла:
<?
require($_SERVER["DOCUMENT_ROOT"] . "/bitrix/modules/main/include/prolog_before.php");
// Подключим модуль «Информационные блоки»
\Bitrix\Main\Loader::includeModule('iblock');
// Генерируем имя ORM класса для работы с инфоблоком, где в моем случае IBLOCK_CATALOG_ID содержит 26 модуль «Информационные блоки»
echo \Bitrix\Iblock\Iblock::wakeUp(IBLOCK_CATALOG_ID)->getEntityDataClass();
Аналог CIBlockElement::GetById() в ORM
Для получения данных по элементу инфоблока и ID этого элемента, используется метод getByPrimary()
вашего виртуального класса:
<?
require($_SERVER["DOCUMENT_ROOT"] . "/bitrix/modules/main/include/prolog_before.php");
// Подключим модуль «Информационные блоки»
\Bitrix\Main\Loader::includeModule('iblock');
// Генерируем имя ORM класса для работы с инфоблоком, где в моем случае IBLOCK_CATALOG_ID содержит 26 модуль «Информационные блоки»
echo \Bitrix\Iblock\Iblock::wakeUp(26)->getEntityDataClass();
// Запрос в класс ORM, 99 это ID элемента инфоблока
$res = \Bitrix\Iblock\Elements\ElementPhpapiTable::getByPrimary(99, [
'select' => ['ID', 'NAME'],
])->fetch();
// Распечатываем массив
pp($res);
Обратите внимание, при выводе пользовательских свойств, ключи пользовательских свойств инфоблока указываются как есть без префикса PROPERTY_
. Вывод получается не совсем читабельный [IBLOCK_ELEMENTS_ELEMENT_PRODUCTS_MANUFACTURER_IBLOCK_ELEMENT_ID] => 10
. Чтобы сделать ключи более понятными в результирующем массиве, можно использовать псевдонимы:
<?
require($_SERVER["DOCUMENT_ROOT"] . "/bitrix/modules/main/include/prolog_before.php");
// Подключим модуль «Информационные блоки»
\Bitrix\Main\Loader::includeModule('iblock');
// Генерируем имя ORM класса для работы с инфоблоком, где в моем случае IBLOCK_CATALOG_ID содержит 26 модуль «Информационные блоки»
echo \Bitrix\Iblock\Iblock::wakeUp(26)->getEntityDataClass();
// Запрос в класс ORM, 99 это ID элемента инфоблока
$res = \Bitrix\Iblock\Elements\ElementPhpapiTable::getByPrimary(99, [
'select' => ['ID', 'NAME', 'MANUFACTURER_' => 'MANUFACTURER'],
])->fetch();
// Распечатываем массив
pp($res);
Аналог CIBlockElement::GetList() в ORM
В качестве аналога всем полюбившигося метода CIBlockElement::GetList()
используется getList()
из D7 который применялся к HL-блокам ранее:
<?
require($_SERVER["DOCUMENT_ROOT"] . "/bitrix/modules/main/include/prolog_before.php");
// Подключим модуль «Информационные блоки»
\Bitrix\Main\Loader::includeModule('iblock');
// Генерируем имя ORM класса для работы с инфоблоком, где в моем случае IBLOCK_CATALOG_ID содержит 26 модуль «Информационные блоки»
echo \Bitrix\Iblock\Iblock::wakeUp(26)->getEntityDataClass();
// Запрос в класс ORM
$res = \Bitrix\Iblock\Elements\ElementPhpapiTable::getList([
'select' => ['ID', 'NAME'],
'filter' => ['=ACTIVE' => 'Y'],
])->fetchAll();
// Перебираем ответ и что-то делаем
foreach ($res as $product) {
pp($product);
}
Элемент инфоблока как объект
С данными элемента инфоблока можно работать не только как с массивом, но и как с объектом. Для этого используйте метод fetchObject()
вместо fetch()
после вызова getByPrimary()
:
<?
require($_SERVER["DOCUMENT_ROOT"] . "/bitrix/modules/main/include/prolog_before.php");
// Подключим модуль «Информационные блоки»
\Bitrix\Main\Loader::includeModule('iblock');
// Генерируем имя ORM класса для работы с инфоблоком, где в моем случае IBLOCK_CATALOG_ID содержит 26 модуль «Информационные блоки»
echo \Bitrix\Iblock\Iblock::wakeUp(26)->getEntityDataClass();
// Запрос в класс ORM, 99 это ID элемента инфоблока
$res = \Bitrix\Iblock\Elements\ElementPhpapiTable::getByPrimary(99, [
'select' => ['ID', 'NAME'],
])->fetchObject();
// Распечатываем массив
pp($res);
В $res
будет получен объект класса Bitrix\Iblock\Elements\EO_ElementPhpapi
с множеством методов для работы с ним. Для получения значений элемента инфоблока используются так называемые геттеры, методы getXXXX
где XXX
название поля в CamelCase
:
// Получить id элемента
echo $res->getId(); //10
// Получим наименование элемента
echo $res->getName();
// Получить id детального изображения
echo $res->getDetailPicture();
Существует так же общий метод Get()
который принимает наименование поля, значение которого вам нужно получить:
// Получим id элемента
echo $res->Get('ID');
// Получим наименование элемента
echo $res->Get('NAME');
Работа со свойствами элементов
Со свойствами элементов можно работать в двух вариантах:
- Как с обьектом
- Как с массивом
Свойства элементов, когда мы работаем с ними в виде объекта, получаются при помощи геттеров, методов getXXXX
где XXX
код свойства записанный как CamelCase, или общего метода Get('XXX')
где XXX
код свойства:
// CamelCase
$res->getId();
// общий метод
$res->Get('ID');
У каждого свойства есть обязательные и доступные поля:
VALUE
значениеDESCRIPTION
описание
Соответcnвующие методы для доступа к ним getValue()
и getDescription()
или Get('VALUE')
и Get('DESCRIPTION')
:
<?
require($_SERVER["DOCUMENT_ROOT"] . "/bitrix/modules/main/include/prolog_before.php");
// Подключим модуль «Информационные блоки»
\Bitrix\Main\Loader::includeModule('iblock');
// Генерируем имя ORM класса для работы с инфоблоком, где в моем случае IBLOCK_CATALOG_ID содержит 26 модуль «Информационные блоки»
echo \Bitrix\Iblock\Iblock::wakeUp(26)->getEntityDataClass();
// Запрос в класс ORM, 99 это ID элемента инфоблока
$res = \Bitrix\Iblock\Elements\ElementPhpapiTable::getByPrimary(99, [
'select' => ['ID', 'NAME', 'MANUFACTURER'], // MANUFACTURER свойства типа «Строка»
])->fetchObject();
// Распечатываем объект и получаем строку
pp($res->getManufacturer()->getValue());
pp($res->Get('MANUFACTURER')->Get('VALUE'));
Стоит понимать, будут доступны только те обьекты, которые перечисленны в запросе, в данном случае это ID
, NAME
, MANUFACTURER
.
Получение информации
Чтобы получить информацию для некоторых типов свойств через ORM, нужно указать дополнительный ключ при выборке свойства:
FILE
свойство типа файлITEM
свойство типа список,ELEMENT
свойство типа привязка к элементу инфоблокаSECTION
свойство типа привязка к разделу инфоблока
У нашего элемента:
<?
require($_SERVER["DOCUMENT_ROOT"] . "/bitrix/modules/main/include/prolog_before.php");
// Подключим модуль «Информационные блоки»
\Bitrix\Main\Loader::includeModule('iblock');
// Генерируем имя ORM класса для работы с инфоблоком, где в моем случае IBLOCK_CATALOG_ID содержит 26
echo \Bitrix\Iblock\Iblock::wakeUp(26)->getEntityDataClass();
// Запрос в класс ORM, 99 это ID элемента инфоблока
$res = \Bitrix\Iblock\Elements\ElementPhpapiTable::getByPrimary(99, [
'select' => [
'ID',
'NAME',
'DETAIL_PICTURE',
// Свойство типа файл
'MORE_PHOTO.FILE',
// Свойство типа список
'NEWPRODUCT.ITEM',
// Свойство типа привязка к элементу инфоблока
'RECOMMEND.ELEMENT',
// Свойство типа привязка к разделу инфоблока
'NEWS_SECTION.SECTION'
],
])->fetchObject();
Есть следующие свойства требуемых типов:
MORE_PHOTO
картинки галереи (тип файл)NEWPRODUCT
новинка (тип список)RECOMMEND
с этим товаром рекомендуем (тип привязка к элементу)NEWS_SECTION
показывать в рекламном блоке в новостях (тип привязка к разделу)
Свойство типа файл в ORM
Обрашение к свойству:
getFile()
Рассмотрим следующий код:
//Выведем доп.фотографии товара
foreach ($res->getMorePhoto()->getAll() as $photo){
echo '<img src="/upload/' . $photo->getFile()->getSubdir() . '/' . $photo->getFile()->getFileName() . '" alt="'. $res->getName() .'" />';
}
Обратите внимание на метод getAll()
, свойство MORE_PHOTO
множественное, по сути оно представляет из себя коллекцию значений. Чтобы получить всю коллекцию и применяют метод getAll()
. Далее при обходе элемента коллекции свойства типа файл мы получаем в распоряжение метод getFile()
, который в свою очередь открывает нам доступ к методам getSubdir()
и getFileName()
для получения
дополнительной информации о файле.
Для просмотра всех доступных методов, достаточно распечатать обьект на экран и посмотреть что нам дает яро d7:
pp($res->Get('MORE_PHOTO')->getFile());
В моем случае доступны следующие методы:
Свойство типа множественный список в ORM
Обрашение к свойству:
getItem()
Если свойство множественное, то getItem()
вернет коллекцию. Получить значения коллекции можно с помощью метода getAll()
. Рассмотрим на примере множественного свойства типа Список
:
// свойство типа множественный список
foreach ($res->getItem()->getAll() as $value) {
pp($value->getValue());
// int(119) "ID выбранного свойства"
}
Свойство типа список в ORM
Обрашение к свойству:
getItem()
Как видите для свойств типа список при использовании специального ключа .ITEM
добавляется метод getItem()
который позволяет получить ID значения списка методом getId()
, внешний код значения getXmlId()
и само значение методом getValue()
:
// свойство типа список
pp($res->getItem()->getId());
// int(1)
pp($res->getItem()->getXmlId());
// string(1) "Y"
pp($res->getItem()->getValue());
// string(4) "да"
Свойство типа привязка к элементам инфоблока в ORM
Обрашение к свойству:
getElement()
Рекомендуемые товары являются множественным свойством, получаем коллекцию значений через getAll()
. Далее мы видим, что элементу коллекции доступен метод getElement()
через который мы можем узнать некоторую информацию об элементе, например ID getId()
и наименование getName()
:
// Получим привязанные элементы
foreach ($res->getRecommend()->getAll() as $recommendedProduct){
echo 'Рекомендуемый товар ID -' . $recommendedProduct->getElement()->getId() . ' наименование - ' . $recommendedProduct->getElement()->getName() . '<br/>';
}
Свойство типа привязка к разделу инфоблока в ORM
Обрашение к свойству:
getSection()
Как и в случае с предыдущим типом свойств нам доступен метод getSection()
через который мы можем узнать некоторую дополнительную информацию о связанном с элементом разделе другого инфоблока:
//Получим id привязанного раздела
pp($res->getNewsSection()->getSection()->getId());
//Получим наименование привязанного раздела
pp($res->getNewsSection()->getSection()->getName());
Обратите внимание, ключи пользовательских свойств инфоблока, MANUFACTURER
указываются как есть, без префикса PROPERTY_
, как раньше:
<?
require($_SERVER["DOCUMENT_ROOT"] . "/bitrix/modules/main/include/prolog_before.php");
// Подключим модуль «Информационные блоки»
\Bitrix\Main\Loader::includeModule('iblock');
// Генерируем имя ORM класса для работы с инфоблоком, где в моем случае IBLOCK_CATALOG_ID содержит 26 модуль «Информационные блоки»
echo \Bitrix\Iblock\Iblock::wakeUp(26)->getEntityDataClass();
// Запрос в класс ORM, 99 это ID элемента инфоблока
$res = \Bitrix\Iblock\Elements\ElementPhpapiTable::getByPrimary(99, [
'select' => ['ID', 'NAME', 'MANUFACTURER'], // MANUFACTURER свойства типа «Строка»
])->fetch();
// Распечатываем массив
pp($res);
Единственный момент, ключи при таком выводе получаются очень длинными IBLOCK_ELEMENTS_ELEMENT_PRODUCTS_MANUFACTURER_IBLOCK_ELEMENT_ID
, для сохранения читабильности в результирующем массиве, можно использовать псевдонимы:
<?
require($_SERVER["DOCUMENT_ROOT"] . "/bitrix/modules/main/include/prolog_before.php");
// Подключим модуль «Информационные блоки»
\Bitrix\Main\Loader::includeModule('iblock');
// Генерируем имя ORM класса для работы с инфоблоком, где в моем случае IBLOCK_CATALOG_ID содержит 26 модуль «Информационные блоки»
echo \Bitrix\Iblock\Iblock::wakeUp(26)->getEntityDataClass();
// Запрос в класс ORM, 99 это ID элемента инфоблока
$res = \Bitrix\Iblock\Elements\ElementPhpapiTable::getByPrimary(99, [
'select' => ['ID', 'NAME', 'MANUFACTURER_' => 'MANUFACTURER'], // MANUFACTURER свойства типа «Строка»
])->fetch();
// Распечатываем массив
pp($res);
Фильтр по свойствам
Можно добавить фильтр по свойству, будет работать только если свойство будет присутствовать в массиве setSelect
. В примере ниже, свойство элемента называется INT_ID_OFFERS
, обратите внимание на INT_ID_OFFERS_
и INT_ID_OFFERS_VALUE
:
<?
require($_SERVER["DOCUMENT_ROOT"] . "/bitrix/modules/main/include/prolog_before.php");
// Подключим модуль «Информационные блоки»
\Bitrix\Main\Loader::includeModule('iblock');
// Генерируем имя ORM класса для работы с инфоблоком, где в моем случае IBLOCK_CATALOG_ID содержит 26
echo \Bitrix\Iblock\Iblock::wakeUp(26)->getEntityDataClass();
// Запрос в класс ORM
$res = \Bitrix\Iblock\Elements\ElementPhpapiTable::getList( [
'select' => ['ID', 'CODE', 'NAME', 'INT_ID_OFFERS_' => 'INT_ID_OFFERS'],
'filter' => ['INT_ID_OFFERS_VALUE' => '1fbb3ef4-7b08-4bac-952e-3c0c7782ea1c'],
])->fetch();
Кеширование результата выборки данных
В Битрикс ORM несколько упростили процедуру кеширования результатов выборки из инфоблока. Для этого вам достаточно добавить в массив параметра например метода getList()
поле cache
и указать параметры кеширования:
<?
require($_SERVER["DOCUMENT_ROOT"] . "/bitrix/modules/main/include/prolog_before.php");
// Подключим модуль «Информационные блоки»
\Bitrix\Main\Loader::includeModule('iblock');
// Генерируем имя ORM класса для работы с инфоблоком, где в моем случае IBLOCK_CATALOG_ID содержит 26 модуль «Информационные блоки»
echo \Bitrix\Iblock\Iblock::wakeUp(26)->getEntityDataClass();
// Запрос в класс ORM
$res = \Bitrix\Iblock\Elements\ElementPhpapiTable::getList([
'select' => [
'ID',
'NAME',
],
'filter' => [
'=ACTIVE' => 'Y'
],
'cache' => [
'ttl' => 3600
],
])->fetchObject();
// Перебираем ответ и что-то делаем
foreach ($res as $product) {
//
}
Вывод SQL запроса на экран
Чтобы понять причину «неправильно» работающей выборки, нужно посмотреть какой sql-запрос формируетя. Рассмотрим на примере выборок из ORM ядра D7 в битриксе:
<?
require($_SERVER["DOCUMENT_ROOT"] . "/bitrix/modules/main/include/prolog_before.php");
// Подключаем класс для вывода SQL запроса
\Bitrix\Main\Application::getConnection()->startTracker();
// Подключим модуль «Информационные блоки»
\Bitrix\Main\Loader::IncludeModule("iblock");
// Запрос в класс ORM, 99 это ID элемента инфоблока
$res = \Bitrix\Iblock\Elements\ElementDvekolonkiTable::getByPrimary(99, [
'select' => ['ID', 'NAME'],
]);
// выводим на экран SQL запрос
echo '<pre>' . $res->getTrackerQuery()->getSql() . '</pre>';
// Распечатываем массив
pp($res->fetch());