Полный цикл в digital

Работа с элементами инфоблоков через ORM и d7

Всё что написано ниже, применимо и к другим модулям, только названия таблиц будут другие. Многое можно узнать из файла /bitrix/modules/main/lib/orm/data/datamanager.php

Подключаем модуль:

\Bitrix\Main\Loader::includeModule('iblock');

После подключения модуля, нам становится доступен целый набор различных классов и методов для работы с данными инфоблоков. Существуют и другие методы для работы с инфоблоками, и это лишь часть из них. Наиболее часто используемые методы, это получение списков записей:

  1. \Bitrix\Iblock\TypeTable::getList(); типы инфоблоков
  2. \Bitrix\Iblock\IblockTable::getList(); инфоблоки
  3. \Bitrix\Iblock\PropertyTable::getList(); свойства инфоблоков
  4. \Bitrix\Iblock\PropertyEnumerationTable::getList(); значения свойств, например списков
  5. \Bitrix\Iblock\SectionTable::getList(); разделы инфоблоков
  6. \Bitrix\Iblock\ElementTable::getList(); элементы инфоблоков
  7. \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 записей, количества, а так же другие операции с данными инфоблока:

  1. add(array $data); добавление элемента
  2. addMulti($rows, $ignoreEvents = false); множественное добавление элементов
  3. checkFields(Result $result, $primary, array $data); метод проверяет поля данных перед записью в БД
  4. delete($primary); удаление элемента по ID
  5. getById($id); получение элемента по ID
  6. getByPrimary($primary, array $parameters = array()); метод возвращает выборку по первичному ключу сущности и по опциональным параметрам \Bitrix\Main\Entity\DataManager::getList
  7. getConnectionName(); метод возвращает имя соединения для сущности
  8. getCount($filter = array(), array $cache = array()); метод выполняет COUNT запрос к сущности и возвращает результат
  9. getEntity(); метод возвращает объект сущности
  10. getList(array $parameters = array()); получение элементов
  11. getMap(); метод возвращает описание карты сущностей
  12. getRow(array $parameters); метод возвращает один столбец (или null) по параметрам для \Bitrix\Main\Entity\DataManager::getList
  13. getRowById($id); метод возвращает один столбец, или null по первичному ключу сущности
  14. getTableName(); метод возвращает имя таблицы БД для сущности
  15. query(); метод создаёт и возвращает объект запроса для сущности
  16. update($primary, array $data); обновление элемента по ID
  17. enableCrypto($field, $table = null, $mode = true); метод устанавливает флаг поддержки шифрования для поля
  18. cryptoEnabled($field, $table = null); метод возвращает true если шифрование разрешено для поля

Что можно сделать с $res из примера выше:

$res->fetch()

Получение одной записи в виде массива, можно перебрать в цикле while и получить все элементы:

while ($arItem = $res->fetch()) {
echo "<pre>";
print_r($arItem);
echo "</pre>";
}
$res->fetchAll()

Получение всех записей в виде массива:

echo "<pre>";
print_r($res->fetchAll());
echo "</pre>";
$res->fetchObject()

Получение одной записи в виде объекта:

while ($arItem = $res->fetchObject()) {
echo "<pre>";
print_r($arItem->getName());
echo "</pre>";
}
$res->fetchCollection()

Получение всех записей в виде коллекции объектов:

foreach ($res->fetchCollection() as $element) {
echo "<pre>";
var_dump($element->getName());
echo "</pre>";
}
$res->getCount()

Количество найденных записей без учета limit, доступно если при запросе было указано count_total = 1:

echo "<pre>";
print_r($res->getCount());
echo "</pre>";
$res->getSelectedRowsCount()

Количество полученных записей с учетом 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');

Работа со свойствами элементов

Со свойствами элементов можно работать в двух вариантах:

  1. Как с обьектом
  2. Как с массивом
Как с обьектом

Свойства элементов, когда мы работаем с ними в виде объекта, получаются при помощи геттеров, методов 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());
Заполните форму уже сегодня!
Для начала сотрудничества необходимо заполнить заявку или заказать обратный звонок. В ответ получите коммерческое предложение, которое будет содержать индивидуальную стратегию с учетом требований и поставленных задач
Работаем по будням с 9:00 до 18:00. Заявки, отправленные в выходные, обрабатываем в первый рабочий день до 12:00.
Спасибо, ваш запрос принят и будет обработан!
Эйч Маркетинг