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

Эта статья будет полезна разработчикам, которые занимаются настройкой Битрикс и хотят узнать больше о его возможностях. Если вы хотите пропустить вводную часть про базовую настройку, смело листайте вниз к разделу Личный опыт.
Создание пользовательских типов свойств
Информационный блок (инфоблок) — это некая сущность для хранения информации какого-либо блока на сайте. Он используется для хранения стандартной информации блоков сайта: название, id, текст для превью, картинка для превью и т.д. Инфоблоки содержат стандартные поля для записи, которые охватывают большую часть случаев применения. Для остальных случаев вам пригодится эта статья 🙂
Новое свойство можно создать в несколько простых шагов:
-
Придумать название и символьный код для свойства.
-
Выбрать необходимый тип свойства — они бывают базовыми и пользовательскими. Пользовательские помогают в решении специфических задач: сделать привязку к Яндекс Карте, или блоков на сайте к типам пользователей.
-
Выбрать, множественное это свойство или нет. Например, добавление нескольких изображений для карточки товара реализуется через этот параметр.
-
Задать дополнительные параметры в расширенном редакторе при необходимости.

Бывают ситуации, когда базовых типов недостаточно для реализации определенной бизнес-логики: расписание занятий у тренера, время приема у врачей. Тогда на помощь приходят пользовательские типы свойств. Сложность в том, что простого инструмента для такой настройки нет, и реализуется это через код.
Для создания нового тип свойства необходимо в файле init.php добавить слушатель события OnIBlockPropertyBuildList из модуля iblock и написать обработчик для данного события в виде класса с функцией GetUserTypeDescription, которая возвращает массив с информацией о типе свойств. Правилом хорошего тона считается вынесение логики слушателей в отдельный файл events.php, который потом подключается в файле init.php, чтобы не загромождать один файл огромным количеством логики.
Необходимыми элементами являются:
-
USER_TYPE_ID– уникальный идентификатор типа свойства. -
USER_TYPE– cимвольный код типа свойства. -
CLASS_NAME– название класса, который реализует логику типа свойства (чаще всего данный метод и логика свойства располагаются в одном классе, но можно разделить их на разные). -
DESCRIPTION– название типа свойства, которое будет отображаться в административной панели. -
PROPERTY_TYPE– тип базового свойства, от которого наследуется стандартная логика работа со свойством.
Пример такой функции:
public function GetUserTypeDescription(): array { return [ 'USER_TYPE_ID' => 'schedule', //Уникальный идентификатор типа свойств 'USER_TYPE' => 'SCHEDULE', // Символьный код типа свойств 'CLASS_NAME' => __CLASS__, // Название класса, который реализует логику типа свойств 'DESCRIPTION' => 'Расписание', // Название свойства, которое будет отображаться в административной панели 'PROPERTY_TYPE' => Bitrix\Iblock\PropertyTable::TYPE_STRING, // Тип базового свойства, от которого будет браться стандартная логика работы с данным свойством ]; }
Созданный тип свойства появится в административной панели, но будет отображаться пустым — так как нет реализованного метода отображения свойства с пользовательским типом.
Переходим к созданию метода:
-
Реализуем метод
GetPropertyFieldHtmlв классе, название которого указанно в полеCLASS_NAME.Он должен находиться в массиве, который возвращается методомGetUserTypeDescription. -
Добавим в массив поле вида:
'GetPropertyFieldHtml' => [CLASS, 'GetPropertyFieldHtml']. -
В созданном методе сформируем отображение свойств с описываемым типом свойства и вернем его результатом работы функции (в виде строки).
Дополнительные параметры для массива GetUserTypeDescription
Рассмотрим другие параметры для массива GetUserTypeDescription, которые могут пригодиться в работе:
-
CheckFields– метод должен проверить корректность значения свойства и вернуть массив. Пустой, если ошибок нет, и с сообщениями об ошибках, если есть. -
GetUIFilterProperty– метод описывает вид поля фильтрации в компоненте main.ui.filter на административных страницах инфоблоков. -
GetLength– метод должен вернуть фактическую длину значения свойства. Он нужен только для свойств, значения которых представляют собой сложные структуры (например, массив). -
ConvertToDB– Метод должен преобразовать значение свойства в формат, пригодный для сохранения в базе данных. И вернуть массив видаarray("VALUE" => "...", "DESCRIPTION" => "...").
Если значение свойства – массив, то разумным будет использование функцииserialize. А вот Дата/время преобразуется в ODBC формат «YYYY-MM-DD HH:MI:SS». Это определит возможности сортировки и фильтрации по значениям данного свойства. -
ConvertFromDB– Метод должен преобразовать значение свойства из формата пригодного для сохранения в базе данных в формат обработки. И вернуть массив видаarray("VALUE" => "...", "DESCRIPTION" => "..."). Дополняет ConvertToDB. -
GetPropertyFieldHtmlMulty– Вывод формы редактирования множественного свойства. Если отсутствует, то используется GetPropertyFieldHtml для каждого значения отдельно (у множественных свойств). -
GetAdminListViewHTML– Метод возвращает безопасный HTML отображения значения свойства в списке элементов административной части. -
GetPublicViewHTML– Метод должен вернуть безопасный HTML отображения значения свойства в публичной части сайта. Если она вернет пустое значение, то значение отображаться не будет. -
GetPublicEditHTML– Метод должен вернуть HTML отображения элемента управления для редактирования значений свойства в публичной части сайта. -
GetSettingsHTML– Метод возвращает безопасный HTML отображения настроек свойства для формы редактирования инфоблока. -
PrepareSettings– Метод возвращает либо массив с дополнительными настройками свойства, либо весь набор настроек, включая стандартные.
Личный опыт настройки пользовательских типов свойств
На проекте для интернет-магазина строительных материалов задумана реализация многогородности с помощью битриксовой многосайтовости: один город – один физический сайт.
Перед нашей командой стояла задача — реализовать разделение контента между сайтами, чтобы создавать уникальный контент для разных городов, а также использовать на нескольких сайтах уже созданный.
Мы решили сделать это с помощью свойства в инфоблоках, которое позволило бы выбирать несколько сайтов для одной записи. При этом у нас было несколько ограничений: отсутствие свойства для вывода списка сайтов в инфоблоке, и запрет на добавление сайтов вручную через свойство «Список».
Так мы пришли к потребности создать свой пользовательский тип свойства, которое через API Bitrix будет подтягивать все сайты и выводить их в виде обычного списка.
Первая проблема возникла при сохранении выбранных результатов. В своём кастомном типе свойства я указал:
'PROPERTY_TYPE' => Iblock</span>PropertyTable::TYPE_LIST, так как свойство имеет вид стандартного списка, просто с автоматическими заполняемыми значениями. Это не сработало, и в базу данных выбранные значения свойства не приходили.
Поиск по открытым источникам и работа с ядром привели меня к тому, что для свойства типа список недостаточно просто вывести весь перечень значений. Также следовало записать их в базу данных в отдельную таблицу для всех Enum всех свойств типа список, что при обычном ручном заполнении происходит под капотом Битрикса. Оптимального способа сделать этого я не нашёл, поэтому прибегнул к альтернативе.
Я заменил PROPERTYTYPE на Iblock</span>PropertyTable::TYPESTRING, что позволило сохранять в базе просто названия сайтов, а не их ENUM_ID из таблицы значений полей свойства типа список.
Так как требовалось предусмотреть логику множественного выбора сайтов у 1 элемента, я выбрал «Множественное» свойство, но вместо компактного вывода моей таблицы с множественным выбором значений — как это обычно работает в стандартном свойстве типа Список — мне множество раз вывелась таблица с возможностью в каждой из них выбрать только одно значение.
После долгих поисков в Ядре я нашёл, что искал: проверку на существование в массиве описания типа свойства поля со ссылкой на метод для уникальной вёрстки при выбранном множественном свойстве.
Чтобы сделать уникальную вёрстку для отображения множественного свойства для пользовательского типа необходимо в результат метода GetUserTypeDescription добавить поле 'GetPropertyFieldHtmlMulty' => [CLASS, 'GetPropertyFieldHtmlMulty'], а также реализовать метод 'GetPropertyFieldHtmlMulty' с телом, в котором будет формироваться отображение для множественного свойства.
Делюсь итоговым вариантом на скриншоте:

Надеюсь, эта статья была вам полезна! Буду рад, если вы поделитесь своими историями в комментариях
ссылка на оригинал статьи https://habr.com/ru/post/697050/
Добавить комментарий