Не пропусти свежие посты, подпишись:

В дополнение к статье о создании собственного типа пользовательских полей хочу рассказать как делать аналогичные свойства для информационных блоков, т.к. эти свойства относятся к другому модулю, а именно «информационные блоки» (iblock). Из коробки инфоблоки битрикс предоставляют следующий набор типов свойств:

  • Строка
  • Число
  • Список
  • Файл
  • Привязка к элементам
  • Привязка к разделам
  • HTML\Текст
  • Видео
  • Дата
  • Дата\Время
  • Деньги
  • Привязка к Яндекс.Карте
  • Привязка к Google Maps
  • Привязка к пользователю
  • Привязка к разделам с автозаполнением
  • Привязка к теме форума
  • Привязка к товарам (SKU)
  • Привязка к файлу (на сервере)
  • Привязка к элементам в виде списка
  • Привязка к элементам по XML_ID
  • Привязка к элементам с автозаполнением
  • Справочник
  • Счётчик

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


Рассмотрим пример создания множественного свойства для реализации расписания врачей.

Подготовка и загрузка класса

Структура и способ загрузки класса будет аналогичным с первой статьёй. Так же используем папку /local/ и такую структуру:

Структура класса

Файл init.php


<?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


<?php

//Папка с пользовательскими классами
define('APP_CLASS_FOLDER', '/local/php_interface/lib/');

Тут храним константы с путями к ключевым папкам (пока одна).

Файл autoload.php


<?php

use Bitrix\Main\Loader;

//Автозагрузка наших классов
Loader::registerAutoLoadClasses(null, [
    'lib\usertype\CUserTypeTimesheet' => APP_CLASS_FOLDER . 'usertype/CUserTypeTimesheet.php',
]);


Тут подгружаем один единственный класс. У меня он будет реализован в файле CUserTypeTimesheet.php.

Файл event_handler.php


<?php

use Bitrix\Main;
$eventManager = Main\EventManager::getInstance();

//Вешаем обработчик на событие создания списка пользовательских свойств OnUserTypeBuildList
$eventManager->addEventHandler('iblock', 'OnIBlockPropertyBuildList', ['lib\usertype\CUserTypeTimesheet', 'GetUserTypeDescription']);

Тут нам необходимо повесить обработчик на событие построения списка доступных свойств в инфоблоке OnIBlockPropertyBuildList.

Стандартные классы модуля iblock

Подсмотреть реализацию близкого к вашей задаче свойства, можно подсмотреть в модуле «Информационные блоки». Для этого перейдём в папку /bitrix/modules/iblock/classes/general/, здесь вы найдёте перечень классов в отдельных файлов с префиксом prop_, например:

  • prop_date.php
  • prop_datetime.php
  • prop_html.php

Для реализации собственного класса, вам нужно реализовать в собственном классе как минимум 2 метода:

  • GetUserTypeDescription() — метод для описания свойства
  • GetPropertyFieldHtml() — метод для вывода html формы свойства

Если вы делаете составное свойство как в моём примере, вам так же потребуется 2 метода контролирующие запись и извлечение значения свойства из базы данных.

  • ConvertToDB() — обработка значения перед записью в БД
  • ConvertFromDB() — обработка значения после извлечения из БД, но до вывода в GetPropertyFieldHtml()

Создаём класс для реализации собственного свойства инфоблока

Согласно вышеописанной структуре нам остаётся создать файл самого класса.


<?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 .='&nbsp;время приёма: с&nbsp;<input type="time" name="'. $fieldName .'[TIME_FROM]" value="'. $timeFrom . '">';
        $html .='&nbsp;по&nbsp;<input type="time" name="'. $fieldName .'[TIME_TO]" value="'. $timeTo .'">';
        if($timeFrom!='' && $timeTo!=''){
            $html .= '&nbsp;&nbsp;<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(), это позволяет избежать ряд ошибок при хранении данных в БД.

Данное свойство позволит вам реализовать страницу со списком врачей или других специалистов компании с удобным редактированием времени приёма.



Не пропусти свежие посты, подпишись:
Полезная статья?
(Голосов: 22, Рейтинг: 4.41)
Курсы от партнёров
Хотите освоить востребованную профессию? Воспользуйтесь предложениями от наших партнёров. Пройдите учебный курс по одному из популярных IT направлений.

Все курсы партёнров
Вам также могут понравиться
Кем можно работать в сфере веб-разработки

Кем можно работать в сфере веб-разработки

Хотите начать работать в сфере веб-разработки, но не знаете с чего можно начать? Читайте описание самых популярных веб-профессий, с их описанием, обязанностями и ориентировочными зарплатами.

CSS курсоры

CSS курсоры

В статье рассмотрены возможности изменения курсоров пользователя при помощи CSS

Работа с регистром строк в php

Работа с регистром строк в php

В статье рассмотрены примеры работы с регистром строк в языке PHP, проверка регистра, изменение, инверсия


Комментарии
Защита от автоматических сообщений
CAPTCHA
Введите слово на картинке