CMS.Fields: создание произвольного типа поля

В CMS.Fields.Types есть множество типов полей, но на всех не угодишь, поэтому может понадобиться создать свой тип.

Для этого необхидимо:

  • Создать класс, реализующий тип поля (наследуемый от CMS.Fields.AbstractField)
  • Зарегистрировать его с помощью вызова CMS::field_type('type_name', 'Class.Name')
  • при необходимости создать шаблон
  • при необходимости добавить css и js файлы
  • при необходимости реализовать контейнер

Базовый класс CMS.Fields.AbstractField

Класс, реализующий тип поля, должен наследоваться от базового CMS.Fields.AbstractField, в котором уже много чего есть.

Чаще всего переопределяются методы:

  • form_fields для задания своих элементов формы
  • assign_from_object, assign_to_object для присвоения данных из объекта в форму и наоборот
  • action для реализации ajax действий
  • preprocess для переопределения/добавления параметров шаблона
  • preprocess_layout для переопределения/добавления параметров обрамления, а так же для добавления css и js файлов.
  • view_value для переопределения отображения в списке таблицы
  • stdunset($data) при добавлении параметров в описание типа поля (таких как caption, tab, ...) не забудьте прописать их в этом методе (причины сложны и запутаны)
  protected function stdunset($data) {
    $res = parent::stdunset($data);
    return $this->punset($res, 'text-wrap', 'flat', 'level_up', 'create_tree');
  }

Если ничего не переопределять/добавлять, то получится тип input.

Пройдемся по основным методам, которые могут быть полезны.

Во всех методах $name - имя поля, $data - его описание, $form - объект формы, $object, $item - db entity.

  • is_upload() если возвращает true, то контроллер администрирования табличных данных будет корректно обрабатывать загрузку файлов. По умолчанию возвращает false
  • view($view = null) возвращает или устанавливает (если передан аргумент) текущий шаблон
  • form_fields($form,$name,$data) добавляет к форме необходимые поля, по умолчанию добавляется input с именем $name. Часто переопределяется.
  • enable_multilang() если возвращает true, то считается что поле поддерживает многоязычность. По умолчанию false.
  • data_langs($data) возвращает поддерживаемые языки
  • assign_from_object($form,$object,$name,$data) осуществляет запись данных в форму из редактируемого объекта. В простейшем случае: $form[$name] = $value. Часто переопределяется.
  • assign_to_object($form,$object,$name,$data) осуществляет запись данных из формы в редактируемый объект. В простейшем случае: $object[$name] = $form[$name]. Часто переопределяется.
  • action($name,$data,$action,$item=false,$fields = array()) вызывается контроллером администрирования табличных данных при обращении по ссылке $controller->field_action_url($name, $action, $item, $parms = array()). Чаще всего используется для реализации ajax действий. Здесь $action - имя действия (например 'rotate'), $fields - набор описаний полей.
  • action_url($name,$data,$action,$item=false,$args=false) если необходимо по-особенному формировать ссылку для действия, то в этом методе.
  • on_before_action, on_after_action вызываются соответственно до и после срабатывания действия
  • process_uploads($name,$parms,$uploads,$item,$extra) вызывается при обработке загрузки файлов. Здесь определяется куда и как сохранять файлы.
  • stdunset($data) удаляет из описания элементы, которые не должны попасть в атрибуты тега.
  • use_styles, use_scripts сокращения для $this->view->use_styles
  • template($data=array(), $name = 'template') возвращает путь к шаблону с именем $name. Сначала шаблон ищется в текущем каталоге (где находится модуль), затем в библиотечных шаблонах. Для указания произвольного места для шаблона можно переопределить метод dir.
  • layout($layout=false,$data=array()) возвращает путь к обрамлению с именем $layout
  • draw, render ($name,$data, $template = 'template', $parms = array()) отображение шаблона с именем $template и параметрами $parms
  • draw_in_layout, render_in_layout ($name,$data,$layout=false, $template = 'template', $parms = array()) отображение шаблона с именем $template внутри обрамления $layout.
  • create_template, create_layout методы для создания шаблонов, отображаемых методами описанными чуть выше
  • preprocess ($template, $name, $data) $template - не имя, а экземпляр шаблона. С помощью методов update_parm и replace_parm можно менять параметры шаблона. Рекомендуется делать это в методе preprocess, дабы не засорять шаблон.
  • layout_preprocess ($l, $name, $data) аналогично preprocess, но параметры задаются для обрамления.

Шаблоны

Как уже упоминалось путь к шаблону определяется в методе template. По умолчанию шаблон будет искаться в той же директории, где лежит файл модуля, в котором определяется тип поля.

Это сделано для удобства создания кастомных типов. Так же можно переопределить метод dir(), тогда шаблоны будут искаться в директории, которую вернет этот метод.

Т.е. в простейшем случае каталог с типом поля выглядит так:

  • FieldNameModule.php
  • template.phtml

Для обрамлений (layout) действуют все те же правила.

В шаблон поступает множество параметров (см. методы preprocess и layout_preprocess):

  • form объект формы (Forms.Form)
  • tagparms массив параметров, относящихся к тегу (напирмер style)
  • name имя поля
  • data массив с описанием поля
  • type_object объект типа поля (CMS.Fields.AbstractField)
  • item объект редактируемой записи, если имеется (ORM Entity)
  • item_id идентификатор записи, если имеется.
  • caption заголовок
  • rcaption заголовок, который обычно выводится справа от элемента формы
  • current_lang текущий установленный язык
  • ccont html элемент label с заголовком

Каждый тип поля может добавлять свои параметры. Желательно не засорять шаблоны и добавлять/переопределять переменные шаблона в методах preprocess, layout_preprocess.

В простейшем случае шаблон выглядит так (а так же если не переопределять шаблон):

<?= $this->forms->input($_name,$tagparms) ?>

Множество примеров шаблонов можно найти в tao/views/fields.

css и js для своего типа поля

Как упоминалось выше, добавлять файлы к шаблону желательно в preprocess_layout.

Для двустрочных стилей или скриптов можно пользоваться (в шаблоне):

  $this->append_to('css', ".puper-filed-txt {color:red;}\n");
  $this->append_to('js', "$(function() {alert('aaa')});\n")

Сложные скрипты и стили стоит помещать в отдельные файлы.

Далее о некоторых рекомендациях написания js скриптов для типов полей.

В случае multivalue поля блок js используется для инициализации.

Например в TreeSelect:

$code = "; $(function() { $('div.tree_select').filter('.name_{$name}').each(
  function() {
    TAO.fields.tree_select($(this));
  }
)});";
 $l->append_to('js', $code);

Здесь мы находим нужный нам элемент и применяем к нему необходимые действия, которые вынесены в TAO.fields (о чем ниже).

Т.е. выполняем инициализацию одного элемента. Это используется в поле multivalue при ajax добавлении нового элемента.

Соотвественно, если вы хотите, чтобы ваше поле было совместимо с multivalue, то следуйте этим рекомендациям.

Так же, если js скрипт представляет собой некий отдельный функционал, то стоит поместить его в TAO.fields для того, чтобы его можно было применять для динамически добавляемых элементов и т.д. Примером может служить тот же TreeSelect:

TAO = TAO || {}
TAO.fields = TAO.fields || {}
TAO.fields.tree_select = function (select) {
...
}

Может возникнуть сложность в том, что в js скрипт нужно передать какие-то параметры. Это можно решить несколькими способами.

Например, можно сформировать html элемент (например input), в котором будут присутствовать необходимые параметры. Обычно их записывают в атрибуты с именами, начинающимися с data-, например: data-field-name="$name". Тогда в скрипте можно легко считать необходимые параметры. Более сложные случаи можно решить с помощью вспомогательного метода шаблона add_scripts_settings (пример из CMS.Controller.TreeTable):

Templates_HTML::add_scripts_settings(array('tree' => array(
  'edit_icon' => '/files/_assets/images/edit.gif',
  'delete_icon' => '/files/_assets/images/del.gif',
  'fields' => $this->tree_fields()
)));

Тогда в js скрипте необходимые параметры будут доступны:

alert(TAO.settings.tree.edit_icon);
alert(TAO.settings.tree.fields.feld_name);

Сам объект TAO создается в tao/files/scripts/tao.js.

Самый банальный и непредпочтительный способ: помещаем весь js код в шаблон и вставляем непосредственно туда переменные из шаблона.

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

Готовые типы полей

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

Например:

  • Attaches: ajax action, загрузка файлов, js, шаблоны.
  • Autocomplete: ajax action, js. Используется ExtJS.
  • Image: ajax actions, js, шаблоны, загрузка файлов, контейнер.
  • Gallery: объединяет в себя attaches и image и добавляет свои возможности.
  • TreeSelect: js, preprocess, шаблоны.
  • Multivalue: переопределения всего и сразу :-). Довольно сложный пример для понимания.
  • ...
Метки: CMS
22.07.2014
Все статьи