Работа с элементами инфоблока средствами ORM в Битрикс D7 - uniqcle/Bitrix GitHub Wiki
С выходом 20-й версии 1С Битрикс, появилась возможность работы с элементами инфоблока средствами ORM. Для того, чтобы начать использовать эту возможность вам необходимо зайти в настройки информационного блока и задать значения для поля «Символьный код API
».
Согласно документации, символьный код API это строка от 1 до 50 символов состоящая из букв и цифр, начинающаяся с буквы. Я взял инфоблок «Одежда» из коробки БУС редакции «Бизнес» и задал код products
.
Для работы с элементами инфоблока средствами ORM, необходимо использовать класс \Bitrix\Iblock\Elements\Element_Символьный_код_API_инфоблока_Table
, класс \Bitrix\Iblock\Elements\ElementProductsTable
. Можно убедиться в этом вызвав следующий код:
//Подключим модуль «Информационные блоки»
\Bitrix\Main\Loader::includeModule('iblock');
//Имя ORM класса для работы с инфоблоком «Одежда»
echo \Bitrix\Iblock\Iblock::wakeUp(IBLOCK_CATALOG_ID)->getEntityDataClass(); //Где IBLOCK_CATALOG_ID - содержит ID инфоблока «Одежда»
Аналог CIBlockElement::GetById()
в ORM
Для получения данных по элементу инфоблока, по ID этого элемента, используется метод getByPrimary()
вашего «виртуального класса»:
$product = \Bitrix\Iblock\Elements\ElementProductsTable::getByPrimary(10, [ //10 - ID товара, «Платье, Красная фея»
'select' => ['ID', 'NAME', 'PREVIEW_TEXT', 'DETAIL_PICTURE', 'MANUFACTURER', 'MATERIAL'],
])->fetch();
В переменной $product
будет примерно такая информация:
Содержимое переменной: Array
(
[ID] => 10
[NAME] => Платье Красная Фея
[PREVIEW_TEXT] =>
[DETAIL_PICTURE] => 68
[IBLOCK_ELEMENTS_ELEMENT_PRODUCTS_MANUFACTURER_ID] => 2148
[IBLOCK_ELEMENTS_ELEMENT_PRODUCTS_MANUFACTURER_IBLOCK_ELEMENT_ID] => 10
[IBLOCK_ELEMENTS_ELEMENT_PRODUCTS_MANUFACTURER_IBLOCK_PROPERTY_ID] => 10
[IBLOCK_ELEMENTS_ELEMENT_PRODUCTS_MANUFACTURER_VALUE] => Россия "Модница"
[IBLOCK_ELEMENTS_ELEMENT_PRODUCTS_MATERIAL_ID] => 2156
[IBLOCK_ELEMENTS_ELEMENT_PRODUCTS_MATERIAL_IBLOCK_ELEMENT_ID] => 10
[IBLOCK_ELEMENTS_ELEMENT_PRODUCTS_MATERIAL_IBLOCK_PROPERTY_ID] => 11
[IBLOCK_ELEMENTS_ELEMENT_PRODUCTS_MATERIAL_VALUE] => трикотаж
)
Обратите внимание, что ключи пользовательских свойств инфоблока, MANUFACTURER
и MATERIAL
указываются как есть, без префикса PROPERTY_
. Чтобы избежать таких длинных ключей как IBLOCK_ELEMENTS_ELEMENT_PRODUCTS_MANUFACTURER_IBLOCK_ELEMENT_ID
в результирующем массиве, можно использовать псевдонимы, вот так:
$product = \Bitrix\Iblock\Elements\ElementProductsTable::getByPrimary(10, [ //10 - ID товара, «Платье, Красная фея»
'select' => ['ID', 'NAME', 'PREVIEW_TEXT', 'DETAIL_PICTURE', 'MANUFACTURER_' => 'MANUFACTURER', 'MATERIAL_'=>'MATERIAL'],
])->fetch();
В таком случае, данные приходят в более удобном виде:
Содержимое переменной: Array
(
[ID] => 10
[NAME] => Платье Красная Фея
[PREVIEW_TEXT] =>
[DETAIL_PICTURE] => 68
[MANUFACTURER_ID] => 2148
[MANUFACTURER_IBLOCK_ELEMENT_ID] => 10
[MANUFACTURER_IBLOCK_PROPERTY_ID] => 10
[MANUFACTURER_VALUE] => Россия "Модница"
[MATERIAL_ID] => 2156
[MATERIAL_IBLOCK_ELEMENT_ID] => 10
[MATERIAL_IBLOCK_PROPERTY_ID] => 11
[MATERIAL_VALUE] => трикотаж
)
getList
черезСимвольный код API
. Получаем массив, объект, через которого получаем свойства.
use Bitrix\Main\Application;
$value = Application::getInstance()->getContext()->getRequest()->getQuery("item");
debug($value);
//getList (array)
$doctorsArray = \Bitrix\Iblock\Elements\ElementApidoctorsTable::getByPrimary($value, [
'select' => ['ID', 'NAME', 'SPECIALIST_' => 'SPECIALIST'],
'filter' => ['ID' => $value]
])->fetch(); //или fetchAll()
//debug($doctorsArray);
//getByPrimary (array)
$doctorsArray = \Bitrix\Iblock\Elements\ElementApidoctorsTable::getByPrimary($value, [
'select' => ['ID', 'NAME', 'SPECIALIST_' => 'SPECIALIST'],
])->fetch(); //или fetchAll()
//debug($doctorsArray);
//getByPrimary (object)
$doctorsObject = \Bitrix\Iblock\Elements\ElementApidoctorsTable::getByPrimary($value, [
'select' => ['ID', 'NAME', 'SPECIALIST', 'PROCEDURE_ID.ELEMENT'],
])->fetchObject(); //или fetchAll()
debug($doctorsObject->getId());
debug($doctorsObject->getName());
debug($doctorsObject->getSpecialist()->getValue()); //строка
//Привязка к элементу
foreach($doctorsObject->getProcedureId()->getAll() as $procedure){
debug($procedure->getElement()->getId());
debug($procedure->getElement()->getName());
}
С данными элемента инфоблока можно работать не только как с массивом, но и как с объектом. Для этого используйте метод fetchObject()
вместо fetch()
после вызова getByPrimary()
.
$product = \Bitrix\Iblock\Elements\ElementProductsTable::getByPrimary(10, [ //10 - ID товара, «Платье, Красная фея»
'select' => ['ID', 'NAME', 'PREVIEW_TEXT', 'DETAIL_PICTURE', 'MANUFACTURER_' => 'MANUFACTURER', 'MATERIAL_'=>'MATERIAL'],
])->fetchObject();
В данном случае, в $product
будет получен объект класса Bitrix\Iblock\Elements\EO_ElementProducts
с множеством методов для работы с ним. Например:
//Получить id товара
echo $product->getId(); //10
//Получить наименование товара
echo $product->getName(); //"Платье Красная Фея"
//Получить id детального изображения
echo $product->getDetailPicture(); //68
Как видите для получения значений элемента инфоблока используются так называемые геттеры (методы getXXXX
где XXX
— название поля в «верблюжьей нотации» или CamelCase). Существует так же общий метод get()
который принимает наименование поля, значение которого вам нужно получить. Например:
//Получим id элемента
echo $product->Get('ID'); // 10
//Получим наименование элемента
echo $product->Get('NAME'); // "Платье Красная фея"
Свойства элементов (когда мы работаем с ними в виде объекта) так же получаются при помощи геттеров (методов getXXXX
где XXXX
— код свойства записанный как CamelCase). У каждого свойства есть поле значения VALUE
и описания DESCRIPTION
и соответcnвующие методы для доступа к ним getValue()
и getDescription()
. Рассмотрим пример:
//Получим данные товара
$product = \Bitrix\Iblock\Elements\ElementProductsTable::getByPrimary(10, [ //10 - ID товара, «Платье, Красная фея»
'select' => ['ID', 'NAME', 'PREVIEW_TEXT', 'DETAIL_PICTURE', 'MANUFACTURER', 'MATERIAL'], //MANUFACTURER и MATERIAL свойства типа «Строка»
])->fetchObject();
//Получим значение свойства MANUFACTURER
var_dump($product->getManufacturer()->getValue());
В результате получим строку:
string(29) "Россия "Модница""
Чтобы получить дополнительную информацию для некоторых типов свойств через ORM, нужно указать дополнительный ключ при выборке свойства:
- FILE — свойство типа файл
- ITEM — свойство типа список,
- ELEMENT — свойство типа привязка к элементу инфоблока
- SECTION — свойство типа привязка к разделу инфоблока
Давайте рассмотрим это детальнее. У нашего элемента есть следующие свойства требуемых типов:
- MORE_PHOTO — Картинки галереи (тип файл)
- NEWPRODUCT — Новинка (тип список)
- RECOMMEND — С этим товаром рекомендуем (тип привязка к элементу)
- NEWS_SECTION — Показывать в рекламном блоке в новостях (тип привязка к разделу), это я создал для теста, в «коробке» такого нет Давайте получим их в ORM:
//Получим данные товара
$product = \Bitrix\Iblock\Elements\ElementProductsTable::getByPrimary(10, [
'select' => [
'ID',
'NAME',
'PREVIEW_TEXT',
'DETAIL_PICTURE',
'MORE_PHOTO.FILE', //Обратите внимание на доп.ключи
'NEWPRODUCT.ITEM',
'RECOMMEND.ELEMENT',
'NEWS_SECTION.SECTION'
],
])->fetchObject();
Рассмотрим следующий код:
//Выведем доп.фотографии товара
foreach ($product->getMorePhoto()->getAll() as $photo){
echo '<img src="/upload/' . $photo->getFile()->getSubdir() . '/' . $photo->getFile()->getFileName() . '" alt="'. $product->getName() .'" />';
}
Обратите внимание во первых на метод getAll()
, т.к. свойство MORE_PHOTO
— множественное, по сути оно представляет из себя коллекцию значений. Чтобы получить всю коллекцию и применяют метод getAll()
. Далее при обходе элемента коллекции свойства типа файл мы получаем в распоряжение метод getFile()
, который в свою очередь открывает нам доступ к методам getSubdir()
и getFileName()
для получения дополнительной информации о файле.
//Свойство типа список
var_dump($product->getNewproduct()->getItem()->getId());
//int(1)
var_dump($product->getNewproduct()->getItem()->getXmlId());
//string(1) "Y"
var_dump($product->getNewproduct()->getItem()->getValue());
//string(4) "да"
Как видите для свойств типа список (при использовании специального ключа .ITEM
) добавляется метод getItem()
который позволяет получить ID значения списка методом getId()
, внешний код значения getXmlId()
и само значение методом getValue()
.
//Получим привязанные элементы
foreach ($product->getRecommend()->getAll() as $recommendedProduct){
echo 'Рекомендуемый товар ID -' . $recommendedProduct->getElement()->getId() . ' наименование - ' . $recommendedProduct->getElement()->getName() . '<br/>';
}
Т.е. рекомендуемые товары так же являются множественным свойством получаем коллекцию значений через getAll()
. Далее мы видим, что элементу коллекции доступен метод getElement()
через который мы можем узнать некоторую информацию об элементе, например ID getId()
и наименование getName()
.
//Получим id привязанного раздела
var_dump($product->getNewsSection()->getSection()->getId());
//Получим наименование привязанного раздела
var_dump($product->getNewsSection()->getSection()->getName());
Как и в случае с предыдущим типом свойств нам доступен метод getSection()
через который мы можем узнать некоторую дополнительную информацию о связанном с элементом разделе другого инфоблока.
Аналог CIBlockElement::GetList()
в ORM
В качестве аналога к всем полюбившимся методу CIBlockElement::GetList()
используется getList()
из D7 который применялся к HL-блокам ранее. Приведу пример:
$products = \Bitrix\Iblock\Elements\ElementProductsTable::getList([
'select' => ['ID', 'NAME', 'PREVIEW_TEXT', 'DETAIL_PICTURE', 'MANUFACTURER_' => 'MANUFACTURER', 'MATERIAL_'=>'MATERIAL'],
'filter' => ['=ACTIVE' => 'Y'],
])->fetchAll();
foreach ($products as $product) {
//...что-то делаем с данными продуктов...
}
OLD Ядро
//группа пользователей по фильтру:
$result = CGroup::GetList('ID', 'sort', array('ID' => '1'));
while($row = $result -> fetch()){
debug($row);;
}
//Элемент инфоблока по фильтру
CModule::IncludeModule("iblock");
$resultIB = CIBlockElement::GetList(
false,
array("ID" => '241'), false, false, array("NAME"));
while($row = $resultIB-> fetch()){
debug($row);
}
ORM D7
//группа пользователей по фильтру:
$resultUsers = \Bitrix\Main\GroupTable::getList(array(
'select' => ['NAME'],
'filter' => ['ID' => '1']
));
while($row = $resultUsers-> fetch()){
debug($row);
}
//Элемент инфоблока по фильтру
\Bitrix\Main\Loader::includeModule("iblock");
// select
$arSelect = array("ID", "NAME", "PREVIEW_TEXT", "ACTIVE_FROM","PREVIEW_PICTURE");
// filter
$arFilter = array(
"IBLOCK_ID" => 22, // Автомобили
"ACTIVE" => "Y",
);
// запрос к API D7 для получения списка элементов инфоблока
$dbItems = \Bitrix\Iblock\ElementTable::getList(array(
'select' => $arSelect,
'filter' => $arFilter,
'order' => array("ACTIVE_FROM" => 'DESC'),
//'offset' => $offset,
'limit' => 10,
'count_total' => true,
));
// ELEMENTS LIST
while ($arItem = $dbItems->fetch()){
debug($arItem);
}
Обращение к таблице через символьный код API
$doctorsObject = \Bitrix\Iblock\Elements\ElementApidoctorsTable::query()
->setSelect([
'*',
'NAME',
])
->setFilter(['ID' => $value])
->setOrder(['NAME' => 'desc'])
->fetchObject();
debug($doctorsObject->getName());
Выборка со связыванием таблиц.
use \Bitrix\Main\ObjectPropertyException,
\Bitrix\Main\ArgumentException,
\Bitrix\Main\SystemException;
use Models\Lists\CarsPropertyValuesTable as CarsTable;
try{
$cars = CarsTable::query()
->setSelect([
'*',
'NAME' => 'ELEMENT.NAME',
'MARKA_NAME' => 'CUSTOM_PROP_MARKA.ELEMENT.NAME',
'CITY_NAME' => 'CUSTOM_PROP_CITY.ELEMENT.NAME'
])
->setFilter(['IBLOCK_ELEMENT_ID' => 47])
->setOrder(['NAME' => 'desc'])
->registerRuntimeField(
null,
new \Bitrix\Main\Entity\ReferenceField(
'CUSTOM_PROP_MARKA',
\Models\Lists\CarManufacturerPropertyValuesTable::getEntity(),
['=this.MANUFACTURER_ID' => 'ref.IBLOCK_ELEMENT_ID']
)
)
->registerRuntimeField(
null,
new \Bitrix\Main\Entity\ReferenceField(
'CUSTOM_PROP_CITY',
\Models\Lists\CarCityPropertyValuesTable::getEntity(),
['=this.CITY_ID' => 'ref.IBLOCK_ELEMENT_ID']
)
)
->fetch(); //fetchAll()
} catch ( ObjectPropertyException | ArgumentException | SystemException $e){
$errorMsg = $e -> getMessage();
debug($errorMsg);
}
debug($cars);
В Битрикс ORM несколько упростили процедуру кеширования результатов выборки из инфоблока. Для этого вам достаточно добавить в массив параметра метода getList()
поле cache
и указать параметры кеширования:
$product = \Bitrix\Iblock\Elements\ElementCatalogTable::getList([
'select' => [
'ID',
'NAME',
'PREVIEW_TEXT',
'DETAIL_PICTURE'
],
'filter' => [
'ID' => 10,
],
'cache' => [
'ttl' => 3600
],
])->fetchObject();
https://mrcappuccino.ru/blog/post/iblock-elements-bitrix-d7
https://it-svalka.ru/blog/bitrix/rabota-s-elementami-infobloka-sredstvami-orm-v-bitriks-d7/
https://sreggh.ru/article/metody-orm-bitrix
https://hmarketing.ru/blog/bitrix/postroitel-zaprosov-orm/