Cotonti / Open Source PHP Content Management FrameworkContent Management Framework

Тип 'custom' в переменных конфигурации

Документация / Расширяем Cotonti / Расширения / Тип 'custom' в переменных конфигурации

Подробная инструкция по использованию переменных конфигурации с типом «Custom»

Прочитать в целом про переменные конфигурации Расширений можно на странице Настройка переменных конфигурации. Здесь, в основном, пойдет речь о переменных типа 'custom'.

До версии 0.9.19 набор типов переменных был ограничен следующими вариантами: string (строка ввода), text(текстовое поле), radio (переключатель да/нет), select (список), callback (настраиваемый список), range (диапазон). Еще 2 специальных типа — hidden (скрытое значение) и separator (разделитель групп переменных).

Основной проблемой для разработчиков Расширений, являлся не только ограниченный набор типов переменных, но и не возможность полноценной фильтрации вводимых данных.

Для устранения этих пробелов в версии 0.9.19 набор стандартных типов переменных для использования в настройках Расширений был дополнен типом custom. Это сделано чтобы повысить удобство разработки Расширений для Cotonti и дать разработчику возможность работать с произвольными типами данных, создавая для них собственные поля ввода и процедуры фильтрации данных.

Новый тип custom позволяет следующее:

  1. Фильтровать данные через встроенные фильтры;
  2. Фильтровать данные через пользовательскую функцию;
  3. Создавать пользовательские поля ввода.

Общий вид определения переменной типа custom идентичен типу callback:

var_name=01:custom:custom_function_name(param1,…):Default value:Description

Рассмотрим возможности нового типа подробнее.

#1. Фильтрация данных через встроенные фильтры

Если вы уже сталкивались с разработкой под Cotonti, то возможно знаете, что для обработки данных введенных пользователем, в системе есть функция cot_import, которая фильтрует полученные значения согласно указанному фильтру (подробнее об это можно прочитать здесь). Часть из предопределенных фильтров можно использовать для автоматической фильтрации значений настроек Расширения на странице Конфигурации. Для этого надо в описании переменной (в установочном файле расширения имя_расширения.setup.php) указать тип custom, а в следующем поле имя фильтра для обработки данных:

alpha_only=05:custom:function_name_ALP()::Alphanumeric input

где ALP это указание на конкретный фильтр используемый для обработки входящих данных.

Доступные для использования таким образом фильтры: INTBOLPSWALPTXTNUM. Для чего используются те или иные фильтры и как они работают — смотри указанную выше ссылку. Разработчику также будет полезно заглянуть в код функции фильтрации.

Если мы не планируем использовать пользовательское поле ввода (см. описание ниже), то название функцииfunction_name становится необязательной частью и может быть опущено:

alpha_only=05:custom:_ALP()::Alphanumeric input

Знак подчеркивания и скобки обязательны для корректной работы. Регистр в имени фильтра значения не имеет.

#2. Фильтрация данных через пользовательскую функцию

Если набора встроенных фильтров не достаточно, можно написать собственный. Сделать это можно двумя путями:

#2.1. Пользовательский фильтр для cot_import

Создание пользовательских фильтров подробно отражено в статье «Фильтрация и проверка введенных пользователем данных, п.5». Здесь лишь отметим, что вызов такого фильтра аналогичен примеру выше:

some_var=01:custom:_MYFILTER()::User data

где MYFILTER это имя пользовательского фильтра, заранее зарегистрированного в реестре фильтров:

$cot_import_filters['MYFILTER'][] = 'myfilter_function';

А myfilter_function имя функции, которая будет использована для фильтрации.

Единственное ограничение для использования пользовательских фильтров в custom переменных — это имя (MYFILTER), которое не может содержать знака подчеркивания.

#2.2. Произвольная пользовательская функция

 

В отличие от пользовательских фильтров, этот вариант вызывает пользовательскую функцию для фильтрации на прямую (в обход cot_import), что позволяет использовать передачу дополнительных параметров.

Для автоматического вызова, имя этой функции должно быть сформировано особым образом — соответствовать имени указанном в определении переменной и иметь окончание _filter. Таким образом, если мы создали custom переменную для ввода пользователем мобильного телефона, ее определение может иметь следующий вид:

mobile_num=01:custom:mobtel_input('+7',10)::Contact phone

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

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

Входные параметры функции-фильтра

 

Общий вид определения функции фильтрации выглядит примерно следующим образом:

function myCustomCfgVar_filter($input_value, $cfg_var, ...)

Первым параметром $input_value передается значение введенное пользователем в соответствующее поле — фильтруемые данные. Вторым параметром система передает массив данных о самой переменной конфигурации$cfg_var в виде ассоциативного массива, аналогичного тому, что используется в функции cot_config_add, см. код функции). Пример:

array(
  'config_owner'    => 'plug',
  'config_cat'      => 'plug_name',
  'config_subcat'   => null,
  'config_order'    => '02',
  'config_name'     => 'mobile_num',
  'config_type'     => 8, // COT_CONFIG_TYPE_CUSTOM
  'config_value'    => '9119999999',
  'config_default'  => '',
  'config_variants' => 'mobtel_input()',
  'config_text'     => 'Contact phone',
  'config_donor'    => null
)

Далее следуют параметры указанные в определении переменной — '+7',10. Таким образом определение функции фильтрации (для нашего примера с вводом номера мобильного) может иметь вид:

function mobtel_input_filter($phone, $cfg_var, $prefix='', $length=null)

а вся функция, например, выглядеть так:

function mobtel_input_filter(&$phone, $cfg_var, $prefix='', $length=null) {
  $var_name = $cfg_var['config_name'];
  $filtered = preg_replace("/[^\d]/", '', $input_value);
  if ($length && strlen($filtered) != $length) 
  {
    $filtered = null;
    $phone = '';
  }
  return $filtered;  

По умолчанию, некорректно введенное значение не записывается в базу данных, но останется в строке ввода для возможности исправления. Если по каким-то причинам это не допустимо, фильтруемое значение может быть передано по ссылке и тогда разработчик при необходимости имеет возможность обнулить (или изменить) фильтруемое значение, которое отобразится в поле формы после неудачного ввода.

Вывод уведомлений

При использовании функции фильтрации необходимо дать пользователю обратную связь, указав допустимое ли значение он ввел для данного поля. Это можно (и нужно) сделать вызывая стандартные функции уведомленийcot_error() и cot_message() внутри функции фильтрации. При этом приняты следующие соглашения:

  • если введенное пользователем значение было изменено функцией-фильтром необходимо вызвать вывод предупреждающего сообщения (тип warning).

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

    Пример вывода предупреждающего сообщения:

    cot_message('msg', 'warning', $var_name);
  • если пользователь ввел недопустимое значение, которое не может быть скорректировано или отфильтровано, необходимо вывести сообщение с ошибкой (тип error):

    cot_error('msg', $var_name);

В обоих случаях последним параметром в функцию вывода сообщения передается имя переменной. Это необходимо для отображения ошибок рядом с конкретным полем ввода (при включенной в настройках системы опцииПоказывать сообщения отдельно для каждого источника).

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

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

mobile_num=01:custom:mobtel_input('+7')::Contact phone

тогда функция может выглядеть так:

function mobtel_input($cfg_var, $prefix=''){
    $name = $cfg_var['config_name'];
    $value = $cfg_var['config_value'];
    if ($value)
    {
        $mobile_code = substr($value, 0, 3);
        $mobile_num =  substr($value, 3, 7);
        $formatted = $prefix . ' (' .$mobile_code. ') ' . $mobile_num;
    }
    return cot_inputbox('text', $name, $formatted, array('placeholder' => $prefix.' (000) 0000000' ));
}

Первым параметром в функцию передается массив данных самой переменной конфигурации (описание см. выше). Следом будут переданы все параметры указанные в описании переменной в «setup» файле Расширения.

#4. Пример использования

#4.1. Поле ввода пароля

Попробуем применить полученные в предыдущих разделах знания.

Допустим для нашего Расширения нам надо хранить пароль от стороннего сервиса, и мы хотим реализовать «стандартное» поле для ввода пароля (с сокрытием ввода и дублирующим полем для подтверждения правильности ввода).

Первое — определим нашу переменную файла конфигурации, в которой будет храниться значение пароля (например для доступа к стороннему облачному сервису):

cloud_psw=01:custom:cfg_password(5)::Test password input

Тип переменной, естественно, customcfg_password() — функция для вывода поля ввода. В качестве переменной этой функции будем передавать минимально допустимую длину пароля (5 символов).

Для формирования элемента ввода пароля нам потребуется 2 поля типа password. Данные из полей будем получать в виде массива с ключами 0 и 1.

function cfg_password($cfg_var, $minlength = 4){
    if (!$minlength) $minlength = 4;
    $value = $cfg_var['config_value'];
    $var_name = $cfg_var['config_name'];
    $type = 'password'; // тип полей ввода
    // дополнительно установим проверку длины средствами HTML5
    $attr = array('pattern' => '[^\s]{'.$minlength.',}');
    // создаем HTML код для вывода 2-х полей
    $input_code = 
        cot_inputbox($type, $var_name.'[0]', $value, $attr) . // первое поле
        ' <br>Для смены пароля введите его повторно:<br>' .
        cot_inputbox($type, $var_name.'[1]', '', $attr); // второе поле
    return $input_code;
}

Написание своей функции вывода поля ввода, в том числе, позволяет нам гибко настраивать любые атрибуты.

Далее приступим к функции фильтрации введенного пароля (т.е. проверки на соответствие заданным условиям).

function cfg_password_filter(&$input_value, $cfg_var, $minlength = 4){
    if (!is_array($input_value)) return NULL;

    if ($input_value[0] == $input_value[1]) { 
        // если пароли в обоих полях совпали
        // проверяем соответствие минимальной длине
            if ($input_value[0] && mb_strlen($input_value[1]) < $minlength) {
            // если длина не удовлетворяет — выводим ошибку стандартными средствами
            cot_error('Минимальная длина: '.$minlength, $cfg_var['config_name']);
        }
        else
        {
            // в случае успеха возвращаем значения пароля 
            // для последующего сохранения в БД
            return $input_value[1];
        }
    } else {
        // если пользователь ошибся при вводе выводим сообщение
        if ($input_value[0]) cot_error('Введенные пароли не совпадают', $cfg_var['config_name']);
    }
    // в случае ошибки мы должны вывести в поле текущий пароль
    $input_value = $cfg_var['config_value'];
    return NULL;
}

Через ссылку на &$input_value мы получаем массив с двумя элементами, в котором содержится данные введенные пользователем в соответствующие поля. Передача параметра по ссылке здесь необходима, чтобы в случае некорректного ввода переписать входящие данне значением текущего пароля, который будет отражен в поле после перегрузки страницы и вывода ошибки.

Вот так, написав 2 небольшие функции, мы получили совершенно новый пользовательский тип для переменной страницы настроек. Сделав данные функции максимально универсальными вы сможете применять их в различных своих Расширениях без каких-либо изменений.

#4.2. Данные по умолчанию

Как вы могли заметить из раздела «Фильтрация данных через встроенные фильтры», при использовании типа custom не обязательно всегда писать свой фильтр-обработчик и функцию вывода поля. Для фильтрации может быть использован встроенный фильтр, а для вывода поля по умолчанию (если пользовательская функция не определена) будет использовано обычное «строковое» поле ввода (<input type="text">).

Таким образом, мы можем, например, использовать встроенный фильтр, но создать для него собственное поле ввода:

ui_color=01:custom:color_input_alp():Black:Select color, type name or HEX code

В этом случае, для создания поля ввода будет вызвана функция color_input_alp(), а обработка введенного значения будет произведена «встроенным» фильтром ALP (aplhanumeric — удаляет все символы, кроме символов латинского алфавита, цифр, дефиса и символа подчеркивания).



Комментарии отсутствуют
Добавление комментариев доступно только зарегистрированным пользователям