Zend Framework: стандартные декораторы формы

Zend Framework: стандартные декораторы формы
Я не раз замечал, как декораторы форм вызывают трудности у начинающих разработчиков. И дело не столько в их сложности, сколько в отсутствии качественной документации к ним. Да, даже в официальной документации к Zend Framework написано не густо. И так, в этой статье речь пойдет о стандартных декораторах формы.

Для чего нужны декораторы?

Декораторы используются для визуализации и кастомизации форм, а также их элементов. Декораторы позволяют задавать вид выводимого контента для элемента или формы. В данном случае следует помнить, что в понятие «элемент формы» в Zend Framework входит сразу несколько составляющих. Рассмотрим на примере Zend_Form_Element_Text. объект этого класса позволяет сгенерировать следующий контент:

  • Тег input, являющийся элементом ввода
  • Тег label, который выступает в роли заголовка
  • Блок описания, в котором можно вывести подсказку к полю либо образец заполнения
  • Блок ошибок, который используется для вывода ошибок валидатора формы

Стиль каждого из этих объектов можно изменить при помощи декоратора.

Стандартные декораторы

Давайте посмотрим как работают декораторы на примере. Создадим простую форму и посмотрим какой контент она генерирует.

class Default_Form_TestForm extends Zend_Form
{

    public function init()
    {
        $text = new Zend_Form_Element_Text('text_element');
        $text->setRequired('true')
                ->setLabel('Text');

        $textarea = new Zend_Form_Element_Textarea('textarea_element');
        $textarea->setOptions(array(
            'class' => 'form-textarea',
            'rows' => 7
        ));

        $submit = new Zend_Form_Element_Submit('submit_element');
        $submit->setLabel('Do it!')
                ->setOptions(array('class' => 'btn btn-default'));

        $this->addElements(array($text, $textarea, $submit));
    }

}
<form enctype="application/x-www-form-urlencoded" action="" method="post">
<dl class="zend_form">
<dt id="text_element-label">
            <label for="text_element" class="required">Text</label>
        </dt>
<dd id="text_element-element">
            <input type="text" name="text_element" id="text_element" value="">
        </dd>
<dt id="textarea_element-label"> </dt>
<dd id="textarea_element-element">
            <textarea name="textarea_element" id="textarea_element" class="form-textarea" rows="7" cols="80"></textarea>
        </dd>
<dt id="submit-label"> </dt>
<dd id="submit-element">
            <input type="submit" name="submit_element" id="submit_element" value="Do it!" class="btn btn-default">
        </dd>
</dl>
</form>

Как мы видим, контент формы оборачивается в тег dl, а каждый ее элемент в dd, метка же (label) заключается в тег dt. Обратите внимание, что метка оборачивается в тег независимо от того была она задана, или нет. Все этого достигается благодаря стандартным декораторам, которые применяются к элементам в процессе создания объекта. Ниже я приведу список стандартных декораторов элементов формы:

  • ViewHelper — декоратор, отвечающий за отображение контента элемента.
  • Errors — декоратор, отвечающий за отображение ошибок валидации формы.
  • Description — декоратор, позволяющий задать вид описания элемента.
  • HtmlTag — декоратор, отвечающий за оборачивание контента элемента.
  • Label — декоратор, позволяющий настроить отображение метки элемента.

Благодаря этой пятерке, Вы можете кардинально изменить внешний вид ваших элементов форм.

У формы также есть стандартные декораторы:

  • FormElements — декоратор, отвечающий за отображение элементов формы.
  • HtmlTag — декоратор, который отвечает за обертку.
  • Form — декоратор, влияющий на отображение тега формы.

Манипуляции с декораторами

Для манипуляции с декораторами у каждого элемента, унаследовавшего класс Zend_Form_Element (или Zend_Form), имеются методы:

  • addDecorator($decorator) ( addDecorators(array $decorators) ) — добавляет декоратор объекту, в качестве аргумента принимает строку (массив) — имя (имена) декоратора (-ов).
  • removeDecorator($decorator) — удаляет декоратор. Аргументом выступает строка — имя декоратора.
  • clearDecorators() — очищает список декораторов.
  • setDecorators(array $decorators) — принимает в качестве аргумента массив с декораторами. Последовательно вызывает метод clearDecorators(), затем addDecorators(array $decorators).
  • setDisableLoadDefaultDecorators($flag) — отключить загрузку стандартных декораторов.

Давайте начнем с того, что заменит тег dl, в который оборачивается контент формы на div. Для этого воспользуемся декоратором HtmlTag:

$this->setDecorators(array(
                'FormElements',
                array('HtmlTag', array('tag' => 'div', 'class' => 'form-inline', 'id' => 'test_form')),
                'Form'
            ));

Элемент массива декораторов, может быть как строкой (пример выше декораторы FormElements и Form), так и массивом (пример — HtmlTag). В первом случае задается использование декоратора со стандартными опциями. Во втором — опции задаются в массиве.
В нашем случае мы указали следующие опции: tag — задает тег, который будет использовать декоратор, class — добавляет атрибут class к тегу декоратора, id — задает атрибут id для тега декоратора.

В результате контент формы будет обернут в тег

<form enctype="application/x-www-form-urlencoded" action="" method="post">
<div class="form-inline" id="test_form">
...
</div>
</form>

А теперь приступим к декорированию элементов формы. Первое, что Вы наверняка захотите сделать — это заменить теги dd, dt на div‘ы. Для этого необходимо воспользоваться декоратором HtmlTag.

class Default_Form_TestForm extends Zend_Form
{

    public function init()
    {
        $this->setDecorators(array(
                'FormElements',
                array('HtmlTag', array('tag' => 'div', 'class' => 'form-inline', 'id' => 'test_form')),
                'Form'
            ));

        $text = new Zend_Form_Element_Text('text_element');
        $text->setRequired('true')
                ->setLabel('Text')
                ->setDecorators(array(
                    'ViewHelper',
                    'Label',
                    array('HtmlTag', array('tag' => 'div', 'class' => 'form-element')),
                ));

        $textarea = new Zend_Form_Element_Textarea('textarea_element');
        $textarea->setOptions(array(
            'class' => 'form-textarea',
            'rows' => 7
        ))->setDecorators(array(
                    'ViewHelper',
                    'Label',
                    array('HtmlTag', array('tag' => 'div', 'class' => 'form-element')),
                ));

        $submit = new Zend_Form_Element_Submit('submit_element');
        $submit->setLabel('Do it!')
                ->setOptions(array('class' => 'btn btn-default'))
                ->setDecorators(array(
                    'ViewHelper',
                    array('HtmlTag', array('tag' => 'div', 'class' => 'form-element')),
                ));

        $this->addElements(array($text, $textarea, $submit));
    }

}
<form enctype="application/x-www-form-urlencoded" action="" method="post">
<div class="form-inline" id="test_form">
<div class="form-element">
            <label for="text_element" class="required">Text</label>
            <input type="text" name="text_element" id="text_element" value="">
        </div>
<div class="form-element">
            <textarea name="textarea_element" id="textarea_element" class="form-textarea" rows="7" cols="80"></textarea>
        </div>
<div class="form-element">
            <input type="submit" name="submit_element" id="submit_element" value="Do it!" class="btn btn-default">
        </div>

</div>
</form>

Я также добавил декоратор Label для отображения тега заголовка элемента, если он был задан. У него, кстати, есть свои особенности. Можно задавать его местоположение, при помощи опции placement у которой может быть два значения: prepend и append. Хочу отметить, что по умолчанию placement = prepend. Т.е. label будет находиться перед элементом. Попробуем установить его за ним.

$text = new Zend_Form_Element_Text('text_element');
        $text->setRequired('true')
                ->setLabel('Text')
                ->setDecorators(array(
                    'ViewHelper',
                    array('Label', array('placement' => 'append')),
                    array('HtmlTag', array('tag' => 'div', 'class' => 'form-element')),
                ));
<div class="form-element">
    <input type="text" name="text_element" id="text_element" value="">
    <label for="text_element" class="required">Text</label>
</div>

Также, декоратор Label имеет опцию tag, но работает она не так, как в декораторе HtmlTag. Он не заменяет тег label на указанный, а лишь оборачивает его в этот тег. Зато опции class и id работают также.

Вы можете применить несколько декораторов типа HtmlTag, которые как и HtmlTag обернут Ваш контент в еще один элемент. Вы также можете указать ключ (например, row), чтобы знать для чего он был применен.

array(array('row' => 'HtmlTag'), array('tag' => 'div', 'id' => 'drag_drop_area', 'class' => 'drag'))

К элементам формы можно задавать описание. Делается это при помощи метода setDescription(). С использовании декоратора Description выглядит это так.

$textarea = new Zend_Form_Element_Textarea('textarea_element');
        $textarea->setOptions(array(
            'class' => 'form-textarea',
            'rows' => 7
        ))->setDescription('Введите текст сообщения')
                ->setDecorators(array(
                    'ViewHelper',
                    'Description',
                    array('HtmlTag', array('tag' => 'div', 'class' => 'form-element')),
                ));
<div class="form-element">
    <textarea name="textarea_element" id="textarea_element" class="form-textarea" rows="7" cols="80"></textarea>

<p class="hint">Введите текст сообщения

</div>

Как видите, по умолчанию описание заключается в тег p с классом hint. Давайте поместим описание в тег span, причем в описании будут присутствовать html теги.

$textarea = new Zend_Form_Element_Textarea('textarea_element');
        $textarea->setOptions(array(
            'class' => 'form-textarea',
            'rows' => 7
        ))->setDescription('Введите текст сообщения (не более <b>2000</b> символов)')
                ->setDecorators(array(
                    'ViewHelper',
                    array('Description', array('tag' => 'span', 'escape' => false)),
                    array('HtmlTag', array('tag' => 'div', 'class' => 'form-element')),
                ));
<div class="form-element">
    <textarea name="textarea_element" id="textarea_element" class="form-textarea" rows="7" cols="80"></textarea>
    <span class="hint">Введите текст сообщения (не более <b>2000</b> символов)</span>
</div>

Для того, чтобы изменить тег в котором находится текст описания, мы воспользуемся опцией tag, а вот для того, чтобы отобразить html теги в описании, необходимо задать опции escape значение false. Опция escape отвечает за то, будет ли текст описания обработан функцией htmlentities, которая преобразует все возможные символы в соответствующие HTML-сущности.

За отображение ошибок, возникающих при валидации формы отвечает декоратор Errors. О нем мы поговорим в другой раз, когда будем разбирать работу валидаторов формы.

Stas Kuryan

Web developer. Перфекционист в написании кода.

3 комментария

  1. Дмитрий     

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

    Спасибо за статью, жду от тебя ещё новые статьи о привязки апих социальных сетей! 🙂

    • Stafox        Автор

      Да-да, все будет 🙂

  2. Pingback:Zend Framework форма с использованием Bootstrap

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *