5 окт. 2009 г.

Полезные мелочи symfony forms

Здравствуйте.

Ещё четыре года, работая в одной из студий по разработке сайтов, меня напрягало построение и обработка форм, встречающихся практически в каждом проекте. Основная часть форм, которые мы тогда делали, — это формы добавления и редактирования записей в базе данных. В случае, когда таблицы содержали несколько столбцов, это ещё можно было вынести. Но при увеличении элементов вставало несколько проблем:
  • похожий html-код, получающийся методом copy-paste
  • идентичная валидация полей
  • сложность поддержки (масштабирования, изменения дизайна)
Простейшая идея, которая мне пришла тогда в голову, заключалась в автоматизации построения форм через получение информации о них из базы данных. Впоследствии, познав дао framework'ов, меня заинтересовали подобные возможности в существующих проектах. Начав изучение framework'а symfony, через некоторое время я с удовольствием узнал о symfony form framework, вышедшем вместе версией 1.1.

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




Прежде всего, на мой взгляд, лень — двигатель прогресса. Например, меня напрягает в шаблоне делать рендеринг напрямую всех элементов формы:


<?= $form['name']->renderRow() ?>

* This source code was highlighted with Source Code Highlighter.



Для меня гораздо удобнее написать один раз:
<?= $form ?>

* This source code was highlighted with Source Code Highlighter.



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


Пример

Часть полей формы обязательна для заполнения. Рядом с названиями нужно поставить *


Для реализации используем встроенный механизм в symfony forms — подсказки (helps). Прежде всего, создадим декоратор для формы


<?php
/*
* Form decorator with required fields
* lib/sfStandartFormDecorator.php
*/

class sfStandartFormDecorator extends sfWidgetFormSchemaFormatter
{
 protected
  $rowFormat = "
   %hidden_fields%
   <tr>
    <th>%label% <span style=\"color: red\">%help%</span></th>
    <td> %error% %field%</td>
   </tr>
   \n"
,
  $helpFormat = '%help%',
  $errorListFormatInARow    = " <div class=\"error_list\">\n%errors% </div>\n",
  $errorRowFormatInARow    = " %error%<br/>\n",
  $namedErrorRowFormatInARow  = " %name%: %error%<br/>\n",
  $decoratorFormat = "";
}

?>


* This source code was highlighted with Source Code Highlighter.



Теперь, добавим подсказки в нужные нам элементы формы в классе lib/form/%model%Form.class.php:
  $my_decorator = new sfStandartFormDecorator($this->getWidgetSchema());
  $this->getWidgetSchema()->addFormFormatter('custom', $my_decorator);
  $this->getWidgetSchema()->setFormFormatterName('custom');

* This source code was highlighted with Source Code Highlighter.



И указываем подсказки у тех полей, которые обязательны (например, login и password):
  $this->widgetSchema->setHelps(array(
   'login'  => '*',
   'password' => '*',
  ));

* This source code was highlighted with Source Code Highlighter.



Вуаля! Теперь рядом с обязательными полями добавились звёздочки


Примечание: в нашем декораторе мы использовали табличную вёрстку. Разумеется, в нём может быть любой html-код


Идея: у валидаторов есть свойство required. Было бы замечательно, если бы по умолчанию symfony давала всем обязательным элементам формы специальный css-класс, например, «form_required». Тогда было бы очень просто, с помощью css, добавить другие эффекты, например, красненькую рамочку вокруг обязательного поля формы. Более того, было бы очень просто «навесить сверху» javascript-библиотеку валидации на стороне клиента


Проверка на уникальность

При регистрации пользователей или в подобной ситуации часто требуется проверить определённое поле на уникальность. И здесь symfony forms позволяют это сделать легко и непринуждённо. Пусть, например, в модели User необходимо иметь уникальное поле login, по которому будет происходить авторизация. Для проверки существуют Post Validator'ы (кстати, о них появилась информация и в symfony forms in action):


  $this->validatorSchema->setPostValidator(
   new sfValidatorPropelUnique(array(
    'model' => 'User',
    'column' => array('login')), array('invalid' => 'Такой login уже есть.')
  ));

* This source code was highlighted with Source Code Highlighter.



Убираем лишние поля

Предположим, что у нас есть регистрация пользователей. При регистрации человека не стоит перегружать большими формами — достаточно ввести только необходимые данные. В профиле же хочется, чтобы пользователь ввёл побольше информации о себе. С точки зрения логики приложения, форма регистрации и форма профиля — одинаковые. Но как убрать лишние поля при регистрации? Для этого нужно в классе формы создать дополнительный метод:
/**
* Метод убирает "лишние" поля при регистрации
*/
public function cutForRegister()
{
 unset($this['first_name'], $this['last_name']);
}


* This source code was highlighted with Source Code Highlighter.

Затем, при создании формы регистрации, вызвать его, и форма «обрежется»


Эпилог и благодарности

Symfony forms предоставляют ряд замечательных возможностей, способных облегчить жизнь как программисту, так и верстальщику с дизайнером. Данная статья не претендует на уникальность. Я уверен, что в ряде проектов сложный дизайн не позволит легко и изящно в одну строчку в шаблоне решить вопрос с отображением формы. Но при решении типовых задач подобные механизмы позволяют экономить не только время, но и нервы на последующей поддержке.


При составлении статьи использовались:



Спасибо!


Обновление:
По этой ссылке и этой представлено решение с добавлением к обязательным полям css-класса и более корректное.

Обновление 2:
Ещё один метод через helper'ы. Спасибо автору.