Свой тип свойств инфоблока
Готовый код можно скачать в моем репозитории на GitFlic.
Информационный блок, это некая сущность для хранения информации какого-либо блока на сайте. Инфоблоки содержат стандартные поля для записи, которые охватывают большую часть случаев применения:
- Строка
- Число
- Список
- Файл
- Привязка к элементам
- Привязка к разделам
- HTML\Текст
- Видео
- Дата
- Дата\Время
- Деньги
- Привязка к Яндекс. Карте
- Привязка к Google Maps
- Привязка к пользователю
- Привязка к разделам с автозаполнением
- Привязка к теме форума
- Привязка к товарам (SKU)
- Привязка к файлу (на сервере)
- Привязка к элементам в виде списка
- Привязка к элементам по XML_ID
- Привязка к элементам с автозаполнением
- Справочник
- Счётчик
Бывают ситуации, когда базовых типов недостаточно для реализации определенной бизнес-логики, тогда на помощь приходят пользовательские типы свойств. Сложность в том, что простого инструмента для такой настройки нет, и реализуется это через код. Полный боевой пример можно скачать ниже после статьи.
Подсмотреть реализацию близкого к вашей задаче свойства, можно в модуле Информационные блоки
. Для этого перейдём в папку /bitrix/modules/iblock/classes/general/
, здесь вы найдёте перечень классов в отдельных файлах с префиксом prop_
. По названию фалов можно догадаться к какому типу они относятся:
prop_date.php
prop_datetime.php
prop_html.php
Обычно, кастомный тип свойства создается на обработчике события OnIBlockPropertyBuildList
модуля iblock
.
Подготовка
Структура проекта:
-
-
-
usertype
CUserTypeTimesheet.php
-
-
autoload.php
constants.php
event_handler.php
init.php
Реализация
Файл init.php
Подключаем файлы:
local/php_interface/init.php<?
//Константы
require_once dirname(__FILE__) . '/constants.php';
//Автозагрузка классов
require_once dirname(__FILE__) . '/autoload.php';
//Обработка событий
require_once dirname(__FILE__) . '/event_handler.php';
Файл constants.php
Храним константу с путем к ключевой папке:
local/php_interface/constants.php<?
// константа APP_CLASS_FOLDER, путь к папке с пользовательскими классами
define('APP_CLASS_FOLDER', '/local/php_interface/lib/');
Файл autoload.php
Подгружаем один единственный класс, у меня он будет реализован в файле CUserTypeTimesheet.php
:
local/php_interface/autoload.php<?
// автозагрузка класса
CModule::AddAutoloadClasses(
'', // не указываем имя модуля
array(
// ключ - имя класса с простанством имен, значение - путь относительно корня сайта к файлу
'lib\usertype\CUserTypeTimesheet' => APP_CLASS_FOLDER . 'usertype/CUserTypeTimesheet.php',
)
);
Файл event_handler.php
Вешаем обработчик на событие построения списка доступных свойств в инфоблоке OnIBlockPropertyBuildList
:
local/php_interface/event_handler.php<?php
// вешаем обработчик на событие создания списка пользовательских свойств OnUserTypeBuildList
addEventHandler('iblock', 'OnIBlockPropertyBuildList', ['lib\usertype\CUserTypeTimesheet', 'GetUserTypeDescription']);
Файл CUserTypeTimesheet.php
Для реализации собственного класса, вам нужно реализовать в собственном классе как минимум два метода:
GetUserTypeDescription()
метод для описания свойстваGetPropertyFieldHtml()
метод для вывода html формы свойства
Если вы делаете составное свойство как в моём примере, вам так же потребуется два метода контролирующие запись и извлечение значения свойства из базы данных:
ConvertToDB()
обработка значения перед записью в БДConvertFromDB()
обработка значения после извлечения из БД, но до вывода вGetPropertyFieldHtml()
local/php_interface/lib/usertype/CUserTypeTimesheet.php<?
namespace lib\usertype;
use Bitrix\Iblock;
/**
* Реализация свойство «Расписание врача»
* Class CUserTypeTimesheet
* @package lib\usertype
*/
class CUserTypeTimesheet
{
/**
* Метод возвращает массив описания собственного типа свойств
* @return array
*/
public static function GetUserTypeDescription()
{
return array(
// cимвольный код типа свойства
'USER_TYPE' => 'TIMESHEET',
// тип базового свойства, от которого наследуется стандартная логика работа со свойством
'PROPERTY_TYPE' => \Bitrix\Iblock\PropertyTable::TYPE_STRING,
// название типа свойства которое будет отображаться в административной панели
'DESCRIPTION' => 'Расписание специалиста',
// название класса который реализует логику типа свойства, чаще всего данный метод и логика свойства располагаются в одном классе, но можно разделить их на разные
'CLASS_NAME' => __CLASS__,
// конвертация данных перед сохранением в базу данных
'ConvertToDB' => [__CLASS__, 'ConvertToDB'],
// конвертация данных при извлечении из базы данных
'ConvertFromDB' => [__CLASS__, 'ConvertFromDB'],
// форма редактирования значения
'GetPropertyFieldHtml' => [__CLASS__, 'GetPropertyFieldHtml'],
);
}
/**
* Конвертация данных перед сохранением в базу данных, должен преобразовать значение свойства в формат пригодный для сохранения в базе данных и вернуть массив вида array("VALUE" => "...", "DESCRIPTION" => "..."), вызывается перед сохранением значения свойства в базе данных
* @param $arProperty, метаданные свойства
* @param $value, значение выбрнных свойств, массив вида array("VALUE" => значение, "DESCRIPTION" => описание)
* @return mixed
*/
public static function ConvertToDB($arProperty, $value)
{
// если $value не пустое и заполнено поле до которого часа
if ($value['VALUE'] != '' && $value['VALUE']['TIME_FROM'] != '' && $value['VALUE']['TIME_TO'] != '') {
try {
// серелизуем массив с данными которые будут записаны в базу данных
$value['VALUE'] = serialize($value['VALUE']);
} catch (Bitrix\Main\ObjectException $exception) {
echo $exception->getMessage();
}
} else {
$value['VALUE'] = '';
}
return $value;
}
/**
* Конвертируем данные при извлечении из базы данных, должен преобразовать значение свойства из формата пригодного для сохранения в базе данных в формат обработки который увидим в админке, возвращает массив вида array("VALUE" => "...", "DESCRIPTION" => "...")
* @param $arProperty, метаданные свойства
* @param $value, значение свойств прочитанное из базы данных, массив вида array("VALUE" => значение, "DESCRIPTION" => описание)
* @param string $format
* @return mixed
*/
public static function ConvertFromDB($arProperty, $value, $format = '')
{
// если $value не пустое
if ($value['VALUE'] != '') {
try {
// десерелизуем данные которые получены из базы данных в массив
$value['VALUE'] = unserialize($value['VALUE']);
} catch (Bitrix\Main\ObjectException $exception) {
echo $exception->getMessage();
}
}
return $value;
}
/**
* Представление формы редактирования значения в админке, метод должен вернуть HTML отображения элемента управления для редактирования значений свойства в административной части
* @param $arProperty, метаданные свойства
* @param $value, значение свойства, массив вида array("VALUE" => значение, "DESCRIPTION" => описание)
* @param $arHtmlControl, имена элементов управления для заполнения значения свойства и его описания, массив вида array("VALUE" => html безопасное имя для значения, "DESCRIPTION" => html безопасное имя для описания, "MODE" => может принимать зачение "FORM_FILL" при вызове из формы редактирования элемента или "iblock_element_admin" при редактировании в режиме просмотра списка элементов, а также "EDIT_FORM" при редактировании инфоблока, "FORM_NAME" => имя формы в которую будет встроен элемент управления)
*/
public static function GetPropertyFieldHtml($arProperty, $value, $arHtmlControl)
{
// дни недели
$weekDays = [
'mon' => 'Понедельник',
'tue' => 'Вторник',
'wed' => 'Среда',
'thu' => 'Четверг',
'fri' => 'Пятница',
'sat' => 'Суббота',
'sun' => 'Воскресенье',
];
// ID для js
$itemId = 'row_' . substr(md5($arHtmlControl['VALUE']), 0, 10);
// устанавливаем правильную кодировку
$fieldName = htmlspecialcharsbx($arHtmlControl['VALUE']);
// получаем данные
$arValue = $value['VALUE'];
// проверяем, если не массив
if (!is_array($arValue)) {
$arValue = false;
}
// формируем раскрывающийся список select с днями недели
$select = '<select class="week_day" name="' . $fieldName . '[WEEK_DAY]">';
foreach ($weekDays as $key => $day) {
if (is_array($arValue['WEEK_DAY']) && $arValue['WEEK_DAY'] == $key) {
$select .= '<option value="' . $key . '" selected="selected">' . $day . '</option>';
} else {
$select .= '<option value="' . $key . '">' . $day . '</option>';
}
}
$select .= '</select>';
// HTML каркас для вывода с ID для js
$html = '<div class="property_row" id="' . $itemId . '">';
// HTML каркас для вывода
$html .= '<div class="reception_time">';
// вставляем в каркас раскрывающийся список
$html .= $select;
// вставляем пустое значение для время приема с
$timeFrom = ($arValue['TIME_FROM']) ? $arValue['TIME_FROM'] : '';
// вставляем пустое значение для время приема до
$timeTo = ($arValue['TIME_TO']) ? $arValue['TIME_TO'] : '';
// формируем input поле для время приема с
$html .= ' время приёма: с <input type="time" name="' . $fieldName . '[TIME_FROM]" value="' . $timeFrom . '">';
// формируем input поле для время приема до
$html .= ' по <input type="time" name="' . $fieldName . '[TIME_TO]" value="' . $timeTo . '">';
// кнопка удаления input
if ($timeFrom != '' && $timeTo != '') {
$html .= ' <input type="button" style="height: auto;" value="x" title="Удалить" onclick="document.getElementById(\'' . $itemId . '\').parentNode.parentNode.remove()" />';
}
$html .= '</div>';
$html .= '</div>';
$html .= '<br/>';
return $html;
}
/**
* Функция отвечает за настройки свойства
* @param $arProperty, метаданные свойства
* @param $arHtmlControl, имена элементa
* @param $arPropertyFields
* @return string/
*/
public static function GetSettingsHTML($arProperty, $arHtmlControl, $arPropertyFields)
{
$arPropertyFields = [
// массив названий полей свойства которые будут скрыты для редактирования
'HIDE' => [],
// массив полей которые должны быть показаны даже если базовое свойство их не поддерживает
'SHOW' => [],
// ассоциативный массив полей для принудительного выставления значений в случае если они не отображаются в форме
'SET' => [],
// строка для отображения в качестве заголовка секции настроек
'USER_TYPE_SETTINGS_TITLE' => ''
];
return '';
}
}
Параметры для массива GetUserTypeDescription
USER_TYPE_ID
уникальный идентификатор типа свойстваUSER_TYPE
cимвольный код типа свойстваCLASS_NAME
название класса, который реализует логику типа свойства (чаще всего данный метод и логика свойства располагаются в одном классе, но можно разделить их на разные)DESCRIPTION
название типа свойства, которое будет отображаться в административной панелиPROPERTY_TYPE
тип базового свойства, от которого наследуется стандартная логика работа со свойствомE
привязка к элементам в виде спискаN
числовое значениеS
строковое значениеL
списокF
файлG
привязка к разделам инфоблокаE
привязка к элементам инфоблока
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
метод возвращает либо массив с дополнительными настройками свойства, либо весь набор настроек, включая стандартные
Параметры для массива GetSettingsHTML
HIDE
массив названий полей свойства которые будут скрыты для редактированияMULTIPLE
множественное значение (Y | N)SEARCHABLE
участвует в поиске (индексация)FILTRABLE
выводить поля для фильтрации по данному свойству на странице списка элементов в административном разделеWITH_DESCRIPTION
признак наличия у значения свойства дополнительного поля описания. Только для типовS
строка,N
число,F
файл (Y | N)MULTIPLE_CNT
количество строк в выпадающем списке для свойств типа списокROW_COUNT
количество строк в ячейке ввода значения свойстваCOL_COUNT
количество столбцов в ячейке ввода значения свойстваDEFAULT_VALUE
значение свойства по умолчанию (кроме свойства типа список L)
SHOW
массив полей которые должны быть показаны даже если базовое свойство их не поддерживаетMULTIPLE
SEARCHABLE
FILTRABLE
WITH_DESCRIPTION
MULTIPLE_CNT
ROW_COUNT
COL_COUNT
SET
ассоциативный массив полей для принудительного выставления значений в случае если они не отображаются в формеMULTIPLE
SEARCHABLE
FILTRABLE
WITH_DESCRIPTION
MULTIPLE_CNT
ROW_COUNT
COL_COUNT
USER_TYPE_SETTINGS_TITLE
строка для отображения в качестве заголовка секции настроек
Реализация простого чекбокса
local/php_interface/lib/usertype/CUserTypeTimesheet.php<?
namespace lib\usertype;
use Bitrix\Iblock;
/**
* Реализация свойство «Расписание врача»
* Class CUserTypeTimesheet
* @package lib\usertype
*/
class CUserTypeTimesheet
{
/**
* Метод возвращает массив описания собственного типа свойств
* @return array
*/
public static function GetUserTypeDescription() {
return array(
// cимвольный код типа свойства
'USER_TYPE' => 'CHECKBOXCUSTOM',
// тип базового свойства, от которого наследуется стандартная логика работа со свойством
'PROPERTY_TYPE' => \Bitrix\Iblock\PropertyTable::TYPE_STRING,
// название типа свойства которое будет отображаться в административной панели
'DESCRIPTION' => 'Флажок специалиста',
// название класса который реализует логику типа свойства, чаще всего данный метод и логика свойства располагаются в одном классе, но можно разделить их на разные
'CLASS_NAME' => __CLASS__,
// форма редактирования значения
'GetPropertyFieldHtml' => [__CLASS__, 'GetPropertyFieldHtml'],
// отвечает за настройки свойства
'GetSettingsHTML' => [__CLASS__, 'GetSettingsHTML'],
);
}
/**
* Представление формы редактирования значения в админке, метод должен вернуть HTML отображения элемента управления для редактирования значений свойства в административной части
* @param $arProperty, метаданные свойства
* @param $value, значение свойства, массив вида array("VALUE" => значение, "DESCRIPTION" => описание)
* @param $arHtmlControl, имена элементов управления для заполнения значения свойства и его описания, массив вида array("VALUE" => html безопасное имя для значения, "DESCRIPTION" => html безопасное имя для описания, "MODE" => может принимать зачение "FORM_FILL" при вызове из формы редактирования элемента или "iblock_element_admin" при редактировании в режиме просмотра списка элементов, а также "EDIT_FORM" при редактировании инфоблока, "FORM_NAME" => имя формы в которую будет встроен элемент управления)
*/
public static function GetPropertyFieldHtml($arProperty, $value, $arHtmlControl) {
// используется для сохранения пустого значения чекбокса, если не установлена галочка
$html = '<input type="hidden" value="" name="'.$arHtmlControl["VALUE"].'">';
// используется для сохранения пустого значения чекбокса, если не установлена галочка
$html .= '<input type="checkbox" size="'.$arProperty['COL_COUNT'].'" value="1" name="'.$arHtmlControl["VALUE"].'"'.((int)$value['VALUE'] ? ' checked' : '').'>';
return $html;
}
/**
* Функция отвечает за настройки свойства
* @param $arProperty, метаданные свойства
* @param $arHtmlControl, имена элементa
* @param $arPropertyFields
* @return string/
*/
public static function GetSettingsHTML($arProperty, $arHtmlControl, $arPropertyFields)
{
$arPropertyFields = [
// массив названий полей свойства которые будут скрыты для редактирования
'HIDE' => [],
// массив полей которые должны быть показаны даже если базовое свойство их не поддерживает
'SHOW' => [],
// ассоциативный массив полей для принудительного выставления значений в случае если они не отображаются в форме
'SET' => [],
// строка для отображения в качестве заголовка секции настроек
'USER_TYPE_SETTINGS_TITLE' => ''
];
return '';
}
}