Zend_Form:
Часть 1 – Основы
Часть 2 – Работа с декораторами
В этой статье мы рассмотрим использование декораторов компонента Zend_Form. В официальном руководстве они описаны довольно сложно для понимания, к тому же нужная секция не переведена на русский язык.
Принципы работы
Декораторы отвечают за формирование HTML-кода формы и её элементов. Абстрактный класс Zend_Form_Decorator_Abstract, являющийся суперклассом для всех декораторов, имеет довольно много возможностей. Пока ограничимся двумя:
- setElement($element)
- Этот метод служит для передачи в декоратор ссылки на объект Zend_Form или Zend_Form_Element
- render($content)
- Здесь происходит генерация HTML-кода на основе элемента, переданного через setElement(). $content содержит HTML-код, уже сгенерированный предыдущими декораторами. Соответственно, первый декоратор получит пустую строку.
Хорошо иллюстрирует использование декораторов код Zend_Form_Element::render()
1 2 3 4 5 6 | $content = ''; foreach ($this->getDecorators() as $decorator) { $decorator->setElement($this); $content = $decorator->render($content); } return $content; |
Приведу ростейший пример использования. В данном случае мы обрамляем нашу форму в тег ‘<div class=”loginForm”></div>’.
1 |
На выходе мы получаем следующее:
1 2 3 4 5 |
Следует уточнить ещё один момент – декораторы обрабатываются в порядке их добавления, причём возможности изменить сортировку нет.
Стандартные декораторы
Стандартных декораторов на момент написания статьи 12. Основные из них:
- FormElements
- Этот декоратор предназначен для экземпляров Zend_Form, и вызывается он обычно первым. Задача его состоит в том, чтобы по одному рендерить элементы формы.
- HtmlTag
- Этот декоратор обрамляет весь HTML-код, сгенерированный предыдущими декораторами, переданным в массиве опций тегом.
- Form
- Обрамляет весь сгенерированный ранее HTML-код в тег <form>
- ViewHelper
- Предназначен для экземпляров Zend_Form_Element, служит для вызова нужного хэлпера Zend_View. Вызванный view-хэлпер вернёт код нашего элемента формы
- Errors
- Тоже предназначен только для элементов формы. При необходимости подставляет HTML-код с сообщениями об некорректости введённых данных
- Label
- Декоратор подставляет элементу формы метку
- Callback
- Пожалуй, самый интересный из представленных декораторов. Позволяет в большинстве случаев обойтись без создания собственных декораторов, передав в Zend_Form_Decorator_Callback имя своей функции. За подробностями – в Zend Framework API
Все декораторы поражают гибкостью настройки.
Приведу пример из жизни. Неоднократно ко мне обращались программисты с вопросом, как сменить вид генерируемой формы. По умолчанию, как вы наверное уже знаете, форма генерируется в виде списка определений <dl></dl>. Этот вариант, насколько мне известно, является наиболее подходящим для HTML-формы. Однако программистам, в том числе и мне, более удобно табличное оформление. Следующий код демонстрирует перевод формы в привычный табличный вид.
1 2 3 4 5 6 7 8 9 10 11 12 13 | $form = new Zend_Form(array('disableLoadDefaultDecorators' => true)); $form->setMethod('post') ->setAction('/mypage') ->addDecorator('formElements') ->addDecorator('htmlTag', array('tag' => 'table')) ->addDecorator('form'); $form->addElement('text', 'username', array('disableLoadDefaultDecorators' => true, 'required' => true, 'label' => 'Логин')); $form->username->addDecorator('viewHelper') ->addDecorator('errors') ->addDecorator(array('tdTag' => 'htmlTag'), array('tag' => 'td')) ->addDecorator('label', array('tag' => 'td')) ->addDecorator(array('trTag' => 'htmlTag'), array('tag' => 'tr')); |
Написание собственных декораторов
Здесь тоже всё просто. Ваши декораторы должны наследовать класс Zend_Form_Decorator_Abstract.
Здесь довольно забавная ситуация – Zend_Form_Decorator_Abstract, как следует из названия, абстрактный класс. Однако он не содержит ни одного абстрактного метода – даже метод render() уже объявлен. На момент написания статьи метод Zend_Form_Decorator_Abstract::render() реализован следующим кодом:
1 2 3 4 5 | public function render($content) { require_once 'Zend/Form/Decorator/Exception.php'; throw new Zend_Form_Decorator_Exception('render() not implemented'); } |
Причина такого содержимого лично мне непонятна, но я уверен – она есть.
Таким образом, метод render() объявить всё же придётся.
Пример простейшего декоратора, не имеющего никакой практической ценности (практичнее будет использовать Zend_Form_Decorator_HtmlTag):
1 2 3 4 5 6 7 8 | class Serkys_Form_Decorator_Div extends Zend_Form_Decorator_Abstract { public function render($content) { return "<div>$content</div>"; } } |
Как видите, совершенно ничего сложного в создании собственных декораторов нет.
Недостатки использования декораторов
Говорят, что если перед курицей начертить прямую линию, она впадает в ступор, длящийся от 30 секунд до нескольких минут. К сожалению, столь интересный опыт я пока не проводил (однако я обязательно попробую), но ступор верстальщика, со смешанными чувствами смотрящего на view-скрипт, состоящий из единственной строки <?php echo $this->form ?> я уже видел.
Значит ли это, что мы снова уходим от разделения логики и представления в смешанный код? Скорее всего нет. Это выход на новый уровень, доработка концепции MVC. Впоследствии, мне кажется, Zend_Form будет в большей степени интегрирован с Zend_View, за счёт чего HTML-код формы будет настраиваться в view-хэлперах или в самих шаблонах, при выводе. Пока же могу предложить только оставлять в своих шаблонах, рядом с выводом формы, ссылку на руководство по Zend_Form_Decorator и, при желании, на эту статью
Спасибо за внимание, всего доброго
Zh0rzh says:
Сумбурная статья.
Новичку не будет понятно, как именно генерируется форма с помощью декораторов.
Нашел опечатку:
” … В данном случае мы обрамляем нашу форму в тег ‘
‘. …”
Я так понимаю, тек пропал.
10 августа 2008, 16:28serkys says:
Спасибо, поправил.
10 августа 2008, 16:42По поводу неясности статьи – подскажите, пожалуйста, с чем конкретно возникли трудности, а я распишу подробнее.
guest says:
Ребята, а что с форумом?
12 августа 2008, 12:26Сергей Митрошин says:
А что с ним не так?
12 августа 2008, 12:30Нормально работает – http://zend-framework.ru/forum/
sany_sazan says:
Статья на мой взгляд доходчиво написана
18 сентября 2008, 9:35Дмитрий Геннадьевич says:
Хорошо бы после исходного кода (там, где создаётся объект $form) показать что получается при прорисовке формы (html код).
15 октября 2008, 13:16Сергей Митрошин says:
Дмитрий, где именно? После примера написания собственного валидатора?
16 октября 2008, 22:18nik :-) says:
Можно увидеть то же описание декораторов, но в виде *.ini?
Я попытался перевести код в файл конфига, но отображение совсем не то получается.
action = “/user/login”
method = “post”
disableLoadDefaultDecorators = true
decorators.elements = “FormElements”
decorators.htmltag.decorator = “HtmlTag”
decorators.htmltag.options.tag = “table”
decorators.htmltag.options.class = “table_form”
decorators.form = “Form”
; элемент username
7 сентября 2009, 10:17elements.username.type = “text”
elements.username.options.disableLoadDefaultDecorators = true
elements.username.options.label = “Логин”
elements.username.options.required = true
elements.username.options.decorators.viewhelper.decorator = “ViewHelper”
elements.username.options.decorators.errors.decorator = “Errors”
elements.username.options.decorators.tdTag.options.tag = “td”
elements.username.options.decorators.tdTag.decorator = “HtmlTag”
elements.username.options.decorators.label.decorator = “Label”
elements.username.options.decorators.label.options.tag = “th”
elements.username.options.decorators.trTag.decorator = “HtmlTag”
elements.username.options.decorators.trTag.options.tag = “tr”
Сергей Митрошин says:
ini-конфиги не подходят для хранения такого большого количества служебной информации. Слишком велики дублирование данных и неочевидность работы. Синтаксис PHP для этой цели подходит больше, просто надо вынести это из контроллера.
7 сентября 2009, 10:22Я обычно выношу такие вещи в модели.