В дополнение к статье о создании собственного типа пользовательских полей хочу рассказать как делать аналогичные свойства для информационных блоков, т.к. эти свойства относятся к другому модулю, а именно «информационные блоки» (iblock). Из коробки инфоблоки битрикс предоставляют следующий набор типов свойств:
- Строка
- Число
- Список
- Файл
- Привязка к элементам
- Привязка к разделам
- HTML\Текст
- Видео
- Дата
- Дата\Время
- Деньги
- Привязка к Яндекс.Карте
- Привязка к Google Maps
- Привязка к пользователю
- Привязка к разделам с автозаполнением
- Привязка к теме форума
- Привязка к товарам (SKU)
- Привязка к файлу (на сервере)
- Привязка к элементам в виде списка
- Привязка к элементам по XML_ID
- Привязка к элементам с автозаполнением
- Справочник
- Счётчик
Достаточно внушительный список, однако иногда заказчику нужны какие-то очень специфические решения, которые не удаётся реализовать в полном объёме. Тут битрикс предоставляет возможность расширить доступный перечень свойств.
Рассмотрим пример создания множественного свойства для реализации расписания врачей.
Подготовка и загрузка класса
Структура и способ загрузки класса будет аналогичным с первой статьёй. Так же используем папку /local/ и такую структуру:
Файл init.php
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
<?php //Константы require dirname(__FILE__) . '/constants.php'; //Автозагрузка классов require dirname(__FILE__) . '/autoload.php'; //Обработка событий require dirname(__FILE__) . '/event_handler.php'; /** * обёртка для print_r() и var_dump() * @param $val - значение * @param string $name - заголовок * @param bool $mode - использовать var_dump() или print_r() * @param bool $die - использовать die() после вывода */ function print_p($val, $name = 'Содержимое переменной', $mode = false, $die = false){ global $USER; if($USER->IsAdmin()){ echo '<pre>'.(!empty($name) ? $name.': ' : ''); if($mode) { var_dump($val); } else { print_r($val); } echo '</pre>'; if($die) die; } } |
Тут дополнительная функция print_p()
служит для удобства вывода содержимого переменных и отладки.
Файл constants.php
1 2 3 4 |
<?php //Папка с пользовательскими классами define('APP_CLASS_FOLDER', '/local/php_interface/lib/'); |
Тут храним константы с путями к ключевым папкам (пока одна).
Файл autoload.php
1 2 3 4 5 6 7 8 |
<?php use Bitrix\Main\Loader; //Автозагрузка наших классов Loader::registerAutoLoadClasses(null, [ 'lib\usertype\CUserTypeTimesheet' => APP_CLASS_FOLDER . 'usertype/CUserTypeTimesheet.php', ]); |
Тут подгружаем один единственный класс. У меня он будет реализован в файле CUserTypeTimesheet.php
.
Стандартные классы модуля iblock
Подсмотреть реализацию близкого к вашей задаче свойства, можно подсмотреть в модуле «Информационные блоки». Для этого перейдём в папку /bitrix/modules/iblock/classes/general/, здесь вы найдёте перечень классов в отдельных файлов с префиксом prop_, например:
- prop_date.php
- prop_datetime.php
- prop_html.php
Для реализации собственного класса, вам нужно реализовать в собственном классе как минимум 2 метода:
GetUserTypeDescription()
— метод для описания свойстваGetPropertyFieldHtml()
— метод для вывода html формы свойства
Если вы делаете составное свойство как в моём примере, вам так же потребуется 2 метода контролирующие запись и извлечение значения свойства из базы данных.
ConvertToDB()
— обработка значения перед записью в БДConvertFromDB()
— обработка значения после извлечения из БД, но до вывода в GetPropertyFieldHtml()
Создаём класс для реализации собственного свойства инфоблока
Согласно вышеописанной структуре нам остаётся создать файл самого класса.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 |
<?php namespace lib\usertype; use Bitrix\Main\Loader, Bitrix\Main\Localization\Loc, Bitrix\Iblock; /** * Реализация свойство «Расписание врача» * Class CUserTypeTimesheet * @package lib\usertype */ class CUserTypeTimesheet { /** * Метод возвращает массив описания собственного типа свойств * @return array */ public function GetUserTypeDescription() { return array( 'USER_TYPE_ID' => 'user_timesheet', //Уникальный идентификатор типа свойств 'USER_TYPE' => 'TIMESHEET', 'CLASS_NAME' => __CLASS__, 'DESCRIPTION' => 'Расписание специалиста', 'PROPERTY_TYPE' => Iblock\PropertyTable::TYPE_STRING, 'ConvertToDB' => [__CLASS__, 'ConvertToDB'], 'ConvertFromDB' => [__CLASS__, 'ConvertFromDB'], 'GetPropertyFieldHtml' => [__CLASS__, 'GetPropertyFieldHtml'], ); } /** * Конвертация данных перед сохранением в БД * @param $arProperty * @param $value * @return mixed */ public static function ConvertToDB($arProperty, $value) { if ($value['VALUE']['TIME_FROM'] != '' && $value['VALUE']['TIME_TO']!='') { try { $value['VALUE'] = base64_encode(serialize($value['VALUE'])); } catch(Bitrix\Main\ObjectException $exception) { echo $exception->getMessage(); } } else { $value['VALUE'] = ''; } return $value; } /** * Конвертируем данные при извлечении из БД * @param $arProperty * @param $value * @param string $format * @return mixed */ public static function ConvertFromDB($arProperty, $value, $format = '') { if ($value['VALUE'] != '') { try { $value['VALUE'] = base64_decode($value['VALUE']); } catch(Bitrix\Main\ObjectException $exception) { echo $exception->getMessage(); } } return $value; } /** * Представление формы редактирования значения * @param $arUserField * @param $arHtmlControl */ public static function GetPropertyFieldHtml($arProperty, $value, $arHtmlControl) { $weekDays = [ 'mon' => 'Понедельник', 'tue' => 'Вторник', 'wed' => 'Среда', 'thu' => 'Четверг', 'fri' => 'Пятница', 'sat' => 'Суббота', 'sun' => 'Воскресенье', ]; $itemId = 'row_' . substr(md5($arHtmlControl['VALUE']), 0, 10); //ID для js $fieldName = htmlspecialcharsbx($arHtmlControl['VALUE']); //htmlspecialcharsback нужен для того, чтобы избавиться от многобайтовых символов из-за которых не работает unserialize() $arValue = unserialize(htmlspecialcharsback($value['VALUE']), [stdClass::class]); $select = '<select class="week_day" name="'. $fieldName .'[WEEK_DAY]">'; foreach ($weekDays as $key => $day){ if($arValue['WEEK_DAY'] == $key){ $select .= '<option value="'. $key .'" selected="selected">'. $day .'</option>'; } else { $select .= '<option value="'. $key .'">'. $day .'</option>'; } } $select .= '</select>'; $html = '<div class="property_row" id="'. $itemId .'">'; $html .= '<div class="reception_time">'; $html .= $select; $timeFrom = ($arValue['TIME_FROM']) ? $arValue['TIME_FROM'] : ''; $timeTo = ($arValue['TIME_TO']) ? $arValue['TIME_TO'] : ''; $html .=' время приёма: с <input type="time" name="'. $fieldName .'[TIME_FROM]" value="'. $timeFrom . '">'; $html .=' по <input type="time" name="'. $fieldName .'[TIME_TO]" value="'. $timeTo .'">'; if($timeFrom!='' && $timeTo!=''){ $html .= ' <input type="button" style="height: auto;" value="x" title="Удалить" onclick="document.getElementById(\''. $itemId .'\').parentNode.parentNode.remove()" />'; } $html .= '</div>'; $html .= '</div><br/>'; return $html; } } |
Подключаемый класс реализует вот такое свойство:
Через инфоблок свойство естественно создаётся как множественное. Как видите для одного и того же дня недели можно создавать неограниченное количество временных промежутков приёма врача и всё это будет корректно сохраняться.
Обратите внимание что для хранения составных данных я использую сериализацию массива + функцию base64_encode()
, это позволяет избежать ряд ошибок при хранении данных в БД.
Данное свойство позволит вам реализовать страницу со списком врачей или других специалистов компании с удобным редактированием времени приёма.
Оставьте первый комментарий!