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

Эта статья будет полезна разработчикам, которые занимаются настройкой Битрикс и хотят узнать больше о его возможностях. Если вы хотите пропустить вводную часть про базовую настройку, смело листайте вниз к разделу Личный опыт.

Создание пользовательских типов свойств

Информационный блок (инфоблок) — это некая сущность для хранения информации какого-либо блока на сайте. Он используется для хранения стандартной информации блоков сайта: название, id, текст для превью, картинка для превью и т.д. Инфоблоки содержат стандартные поля для записи, которые охватывают большую часть случаев применения. Для остальных случаев вам пригодится эта статья :)

Новое свойство можно создать в несколько простых шагов:

  1. Придумать название и символьный код для свойства.

  2. Выбрать необходимый тип свойства — они бывают базовыми и пользовательскими. Пользовательские помогают в решении специфических задач: сделать привязку к Яндекс Карте, или блоков на сайте к типам пользователей. 

  3. Выбрать, множественное это свойство или нет. Например, добавление нескольких изображений для карточки товара реализуется через этот параметр.

  4. Задать дополнительные параметры в расширенном редакторе при необходимости.  

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

Для создания нового тип свойства необходимо в файле init.php добавить слушатель события OnIBlockPropertyBuildList из модуля iblock и написать обработчик для данного события в виде класса с функцией GetUserTypeDescription, которая возвращает массив с информацией о типе свойств. Правилом хорошего тона считается вынесение логики слушателей в отдельный файл events.php, который потом подключается в файле init.php, чтобы не загромождать один файл огромным количеством логики.

Необходимыми элементами являются:

  1. USER_TYPE_ID – уникальный идентификатор типа свойства.

  2. USER_TYPE – cимвольный код типа свойства.

  3. CLASS_NAME – название класса, который реализует логику типа свойства (чаще всего данный метод и логика свойства располагаются в одном классе, но можно разделить их на разные).

  4. DESCRIPTION – название типа свойства, которое будет отображаться в административной панели.

  5. 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, которые могут пригодиться в работе:

  1. CheckFields – метод должен проверить корректность значения свойства и вернуть массив. Пустой, если ошибок нет, и с сообщениями об ошибках, если есть.

  2. GetUIFilterProperty – метод описывает вид поля фильтрации в компоненте main.ui.filter на административных страницах инфоблоков.

  3. GetLength – метод должен вернуть фактическую длину значения свойства. Он нужен только для свойств, значения которых представляют собой сложные структуры (например, массив).

  4. ConvertToDB – Метод должен преобразовать значение свойства в формат, пригодный для сохранения в базе данных. И вернуть массив вида array("VALUE" => "...", "DESCRIPTION" => "...").
    Если значение свойства –  массив, то разумным будет использование функции serialize. А вот Дата/время преобразуется в ODBC формат "YYYY-MM-DD HH:MI:SS". Это определит возможности сортировки и фильтрации по значениям данного свойства.

  5. ConvertFromDB – Метод должен преобразовать значение свойства из формата пригодного для сохранения в базе данных в формат обработки. И вернуть массив вида array("VALUE" => "...", "DESCRIPTION" => "..."). Дополняет ConvertToDB.

  6. GetPropertyFieldHtmlMulty – Вывод формы редактирования множественного свойства. Если отсутствует, то используется GetPropertyFieldHtml для каждого значения отдельно (у множественных свойств).

  7. GetAdminListViewHTML – Метод возвращает безопасный HTML отображения значения свойства в списке элементов административной части.

  8. GetPublicViewHTML – Метод должен вернуть безопасный HTML отображения значения свойства в публичной части сайта. Если она вернет пустое значение, то значение отображаться не будет.

  9. GetPublicEditHTML – Метод должен вернуть HTML отображения элемента управления для редактирования значений свойства в публичной части сайта.

  10. GetSettingsHTML – Метод возвращает безопасный HTML отображения настроек свойства для формы редактирования инфоблока.

  11. PrepareSettings – Метод возвращает либо массив с дополнительными настройками свойства, либо весь набор настроек, включая стандартные.

Личный опыт настройки пользовательских типов свойств

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

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

Так мы пришли к потребности создать свой пользовательский тип свойства, которое через API Bitrix будет подтягивать все сайты и выводить их в виде обычного списка. 

Первая проблема возникла при сохранении выбранных результатов. В своём кастомном типе свойства я указал:

 'PROPERTY_TYPE' => Iblock</span>PropertyTable::TYPE_LIST, так как свойство имеет вид стандартного списка, просто с автоматическими заполняемыми значениями. Это не сработало, и в базу данных выбранные значения свойства не приходили. 

Поиск по открытым источникам и работа с ядром привели меня к тому, что для свойства типа список недостаточно просто вывести весь перечень значений.  Также следовало записать их в базу данных в отдельную таблицу для всех Enum всех свойств типа список, что при обычном ручном заполнении происходит под капотом Битрикса. Оптимального способа сделать этого я не нашёл, поэтому прибегнул к альтернативе. 

Я заменил PROPERTYTYPE на Iblock</span>PropertyTable::TYPESTRING, что позволило сохранять в базе просто названия сайтов, а не их ENUM_ID из таблицы значений полей свойства типа список. 

Так как требовалось предусмотреть логику множественного выбора сайтов у 1 элемента, я выбрал «Множественное» свойство, но вместо компактного вывода моей таблицы с множественным выбором значений — как это обычно работает в стандартном свойстве типа Список — мне множество раз вывелась таблица с возможностью в каждой из них выбрать только одно значение. 

После долгих поисков в Ядре я нашёл, что искал: проверку на существование в массиве описания типа свойства поля со ссылкой на метод для уникальной вёрстки при выбранном множественном свойстве.
Чтобы сделать уникальную вёрстку для отображения множественного свойства для пользовательского типа необходимо в результат метода  GetUserTypeDescription добавить поле 'GetPropertyFieldHtmlMulty' => [CLASS, 'GetPropertyFieldHtmlMulty'], а также реализовать метод 'GetPropertyFieldHtmlMulty' с телом, в котором будет формироваться отображение для множественного свойства. 

Делюсь итоговым вариантом на скриншоте:

Вот так это выглядит в административной панели — в списке выводятся доступные сайты
Вот так это выглядит в административной панели — в списке выводятся доступные сайты

Надеюсь, эта статья была вам полезна! Буду рад, если вы поделитесь своими историями в комментариях.

Комментарии (0)