Кому из нормальных разработчиков нравится битрикс? Правильный ответ: никому (ну или почти никому). К великому сожалению этот прекрасный продукт маркетологов под капотом — гнилой насквозь. К еще большему сожалению этим продуктом пользуются очень и очень многие. Он невероятно популярен именно из-за прекрасной работы отдела маркетинга компании 1С. Если бы перед принятием решения о том какую CMS применить при построении нового сайта сначала спрашивали независимых технических специалистов, то битрикс был бы уже давно скорее мертв, чем жив. Однако в русскоязычном секторе обычно принято спрашивать не тех кто разбирается, а скорее соседей, которые уже клюнули на удочку красивого маркетинга.
Но что есть то есть и с этим уже ничего не поделать. Единственное что остается — каким-то образом с этим работать. Конечно «горбатого могила исправит», но пока «горбатый» в эту самую могилу не собирается, попробуем хотя бы налепить на него корсет. И корсетом этим будет попытка реализовать паттерн «Строитель» (Builder) для битриксовских инфоблоков и их разделов.
Репозиторий
Сам публичный репозиторий находится здесь. Там же на корявом английском я описал основной принцип работы и описал методы. Теперь попробую вкратце продублировать это здесь уже на русском.
Установка
Все просто:
composer require polyspirit/bitrix-builder
Те кто до сих пор не знаком с composer (в каком веке вы живете?) могут скачать код в виде архива и расположить основные классы из папки src где угодно на сайте, например в local/php_interface, откуда уже их и подключать куда угодно.
Использование
use \polyspirit\Bitrix\Builder\IBlock;
// в качестве первого параметра указываем ID инфоблока
$iBlockById = new IBlock(12);
// или можем указать его CODE
$iBlockByCode = new IBlock('news');
// в качестве второго параметра опционально можно указать ID сайта, который обычно лежит в константе SITE_ID
$iBlockByCodeAndSiteID = new IBlock('news', 's1');
Подключаем класс туда где будем его использовать и создаем инстанс. Иногда, например в почтовых шаблонах, битрикс не знает на каком сайте мы находимся, поэтому приходится ему прописывать ID сайта вручную.
Далее забираем нужный элемент или элементы:
$arResult = $iBlock->getElements();
// в этом методе просто будет возвращен первый элемент из коллекции
$arResultDetail = $iBlock->filter(['ID' => 42])->getElement();
И уже в шаблоне это все показываем:
// выводим например NAME
echo $arResultDetail['NAME'];
// для коллекции это будет как-то так
foreach ($arResult as $item) {
echo $item['NAME'];
}
Что внутри?
Внутри каждого элемента коллекции всегда будет 2 свойства: PROPS и PICTURE_SRC. PROPS содержат в себе все свойства инфоблока, а PICTURE_SRC путь до картинки, который будет по умолчанию взят из DETAIL_PICTURE, а если это поле не указано или не выбрано, то из PREVIEW_PICTURE.
Для разделов, которые точно таким же образом работают через класс ISection, унаследованный от IBlock, правила немного другие. Свойства надо выбирать самостоятельно и указывать в fields (об этом ниже), а в PICTURE_SRC будет путь по умолчанию до DETAIL_PICTURE, а если это поле не указано, то до PICTURE.
Свойства и сеттеры
Если просто выбрать элементы, то будут выбраны все и отсортированы таким образом:
['sort' => 'ASC', 'date_active_from' => 'DESC', 'created_date' => 'DESC']
Чтобы сбросить сортировку по умолчанию, применяйте метод sortReset().
Список сеттеров: filter(), sort(), fields(), navs() и sizes(). Так же их все можно указать в массиве и закинуть в метод params(). Вот пример обоих подходов:
(new IBlock('news'))->filter(['>=TIMESTAMP_X' => date('Y-m-d h:i:s', 'yesterday')])
->sort(['NAME' => 'ASC']) // добавляем к сортировке по умолчанию
->fields(['NAME', 'CODE', 'PICTURE_PREVIEW'])
->sizes(['width' => 1280, 'height' => 720]) // размеры получаемой картинки
->navs(['nPageSize' => 4, 'iNumPage' => 1])
->getElements();
// ИЛИ
$params = [
'sort' => ['NAME' => 'ASC'],
'filter' => ['>=TIMESTAMP_X' => date('Y-m-d h:i:s', 'yesterday')],
'fields' => ['NAME', 'CODE', 'PICTURE_PREVIEW'],
'sizes' => ['width' => 1280, 'height' => 720],
'navs' => ['nPageSize' => 4, 'iNumPage' => 1]
];
(new IBlock('news'))->params($params)->getElements();
Так же чтобы выбирать только активные элементы существует метод active().
$arResult = $iBlock->active()->getElements();
Функция-обработчик
Чтобы не проходить по каждому выбранному элементу после выборки можно сделать это во время нее, что позволяет немного экономить ресурсы.
Для методов getElement() и getElements() можно в качестве первого и единственного параметра передать объект типа Closure.
$handler = function (&$element) {
$element['ID_CODE'] = $element['ID'] . '|' . $element['CODE'];
};
$arResult = $iBlock->filter(['>=ID' => 42])
->fields(['CODE'])
->getElements($handler);
foreach ($arResult as $element) {
echo $element['ID_CODE']; // id_элемента|код_элемента
}
Добавление и редактирование
Так же можно добавлять элементы с помощью add(), обновлять с помощью update() и удалять через delete(). Синтаксис такой:
public IBlock::add(array $fields, array $props = []): int
public IBlock::update(string|int $id, array $fields, array $props = []): bool
// если $id = null, то будет попытка удалить последний добавленный или обновленный элемент
public IBlock::delete(string|int|null $id = null): bool
Пример:
$iBLock->add(
['NAME' => 'Some', 'PREVIEW_TEXT' => 'Some text'],
['SOME_PROPERTY_CODE' => 42]
);
$iBLock->update(
['NAME' => 'Updated some'],
['SOME_PROPERTY_CODE' => 24]
);
$iBLock->delete();
Есть и другие, уже более специфические методы, но о них лучше почитайте в readme, все таки тут не документация и я стараюсь излагать кратко.
Разделы (секции)
Класс ISection отвечает за работу с разделами, наследуется от IBlock и имеет идентичные методы, разве что внутри они реализованы с небольшими отличиями.
У элементов коллекции ISection не будет поля PROPS, вместо этого все свойства разделов надо указывать в fields() и доставать их напрямую из элемента.
Как использовать?
Вы можете подключать классы где угодно и использовать как угодно. Я обычно использую билдер вместе с 2мя простенькими компонентами, на которых и строю почти всю работу в битрикс. Их я нашел в одном из проектов, с которым я когда-то работал, немного почистил, чуть переделал и готово. К сожалению их изначальный автор неизвестен, поэтому я просто их выложил у себя на github. Вот они: blocks и controller.
Blocks — это максимально простой компонент, который просто занимается кэшированием, ну а в довесок предоставляет стандартную архитектуру битрикса, где в result_modifier.php мы получаем и обрабатываем данные, а в template.php уже выводим. Часто я пишу для него какой-нибудь универсальный шаблон вроде items.list и подключаю везде где-только можно. Если нужна какая-то особенная логика, то создаю отдельный шаблон, например news.list.
Controller — уже посложнее. Он дает возможность создавать все необходимые страницы для сущности. То есть страницы для списка, для секции, для детальной информации, редактирования и какие угодно другие. Вся логика как всегда пишется в result_modifier.php, а в качестве файлов шаблонов выступают template.php для страницы входа (обычно это список) и любые другие файлы, которые вы укажете при подключении компонента.
Подробности работы с компонентами так же читайте в readme репозиториев, ссылки я указал выше.
Заключение
Не используйте битрикс, если у вас есть такая возможность. Несмотря на все костыли вроде этого — это все еще ужасная платформа для разработки. И сообщество вокруг нее не лучше, держитесь от этих людей подальше.
Ну а если у вас, как и у меня, просто нет выхода, то надеюсь подобные надстройки над кривой системой хоть как-то помогут вам писать хороший код. Удачи!