То, что мне очень не нравилось в Symfony 1.0, а именно - работа с формами, в следующей версии, которая сейчас находится в активной разработке, должно кардинально поменяться в лучшую сторону. Ну а пока что расскажу о работе с формами в текущей стабильной версии этого замечательного фреймворка.
Работа с формами здесь реализована на основе хелперов и валидаторов, которые напрямую друг с другом не связаны вообще никак. Поподробнее можно почитать в онлайн книге, в главе про формы.
Пример работы:
Предположим, что существует следующая модель пользователя (здесь и далее все конфигурационные файлы будут пприводится в формате YAML) :
user:
id:
login:
type: varchar(64)
required: true
index: unique
password:
type: varchar(40)
required: true
first_name:
type: varchar(64)
required: true
last_name:
type: varchar(64)
required: true
email:
type: varchar(128)
required: true
index: unique
...
Сразу хочу предупредить - в качестве ORM’а использовался Propel, для Doctrine схема будет несколько иная, но очень похожая.
Создадим для этой модели форму регистрации по адресу account/register. Для этого создадим модуль account и в его actions.class.php добавим следующий код:
public function executeRegister() {
if($this->getRequest()->getMethod() === sfRequest::POST) {
$user = new User();
$user->setLogin($this->getRequestParameter('login'));
$user->setPassword($this->getRequestParameter('password'));
$user->setFirstName($this->getRequestParameter('first_name'));
$user->setLastName($this->getRequestParameter('last_name'));
$user->setEmail($this->getRequestParameter('email'));
$user->save();
$this->redirect('main/index');
}
}
Для этого метода создадим шаблон registerSuccess.php примерно следующего содержания:
<?php use_helper('Validation') ?>
<?php echo form_tag('account/register') ?>
<fieldset>
<div>
<?php echo label_for('login', 'Логин'); ?>
<?php echo input_tag('login', $sf_params->get('login'), array('class' => 'text')); ?>
<?php echo form_error('login'); ?>
</div>
<div>
<?php echo label_for('password', 'Пароль'); ?>
<?php echo input_password_tag('password', null, array('class' => 'text')); ?>
<?php echo form_error('password'); ?>
</div>
<div>
<?php echo label_for('password_repeat', 'Подтверждение пароля'); ?>
<?php echo input_password_tag('password_repeat', null, array('class' => 'text')); ?>
<?php echo form_error('password_repeat'); ?>
</div>
<div>
<?php echo label_for('first_name', 'Фамилия'); ?>
<?php echo input_tag('first_name', $sf_params->get('first_name'), array('class' => 'text')); ?>
<?php echo form_error('first_name'); ?>
</div>
<div>
<?php echo label_for('last_name', 'Имя'); ?>
<?php echo input_tag('last_name', $sf_params->get('last_name'), array('class' => 'text')); ?>
<?php echo form_error('last_name'); ?>
</div>
<div>
<?php echo label_for('email', 'E-mail'); ?>
<?php echo input_tag('email', $sf_params->get('email'), array('class' => 'text')); ?>
<?php echo form_error('email'); ?>
</div>
</fieldset>
<div class="submit">
<?php echo submit_tag('Зарегистрироваться') ?>
</div>
</form>
Всё, регистрация уже работает и вы вполне можете заходить по адресу account/register вводить данные и нажимать кнопку “Зарегистрироваться”. Одна проблема - никаких ограничений на вводимые данные нет. Давайте это исправим.
С этого момента в дело вступают валидаторы. Создадим директорию validate в модуле и добавим туда register.yml следующего содержания:
fields:
login:
required:
msg: Логин не может быть пустым
sfPropelUniqueValidator:
class: User
column: login
unique_error: Уже существует пользователь с таким логином
password:
required:
msg: Пароль не может быть пустым
password_repeat:
required:
msg: Пароль не может быть пустым
sfCompareValidator:
check: password
compare_error: Пароли не совпадают
email:
required:
msg: E-mail не может быть пустым
sfEmailValidator:
strict: true
email_error: Неправильный формат e-mail'а
sfPropelUniqueValidator:
class: User
column: email
unique_error: Уже существует пользователь с таким e-mail
first_name:
required:
msg: Введите свою фамилию
last_name:
required:
msg: Введите своё имя
С этого момента все входные данные будут проверятся на валидность. Как можно видеть - для каждого поля формы указываются отдельные валидаторы. Перечислим используемые здесь:
- required - показывает, что поле не должно быть пустым, аттрибут msg содержит тот текст, который будет выведен при вызове в шаблоне функции form_error с переданным в качестве аргумента названием поля (см. registerSuccess.php выше)
- sfPropelUniqueValidator - проверяет, существуют ли в указанной таблице еще записи, содержащие введенное значение в указанном домене
- sfCompareValidator - сравнивает текущее поле с полем, указанным в параметре check
- sfEmailValidator - ну, тут, я думаю, всё понятно
Теперь хочется сказать, что если все входные данные не пройдут валидацию, то вместо метода executeRegister будет вызван метод handleErrorRegister из того же класса, если такой существует. В данном случае я хочу, чтобы пользователя переадресовывало на ту же страницу (чтобы пользователь мог увидеть ошибки, которые он допустил при вводе данных). Для этого я добавлю в класс простой метод handleErrorRegister следующего вида:
public function handleErrorRegister() {
return sfView::SUCCESS;
}
Теперь даже если данные не пройдут валидацию - всё равно будет отображена та же страничка.
Выводы
В плюсы можно занести следующее:
- В Symfony достаточно удобные хелперы для работы с формами
- В плюсы, на мой взгляд, однозначно стоит занести возможность выносить валидацию в YAML-файл. Таким образом мы, хоть для некоторых и неявно, но приучаемся к декларативному стилю программирования - мы не указываем, какие действия нужно сделать в валидации, мы указываем - каким законам будет подчиняться валидация.
- В Symfony много классов-валидаторов, которые покрывают большую часть того, что нужно программисту при валидации данных
К минусам можно отнести:
- Отсутствие динамически генерируемых форм (т.е. пишем класс формы, с определенными полями и навешиваем на них валидаторы, сразу же в этом классе, а потом просто создаем обьект класса и выводим его/осуществляем валидацию)
- Соответственно, нет никаких связей между моделями и формами
Плюсы хороши. Но минусы расстраивают, особенно при наличии таких замечательных моделей. Так что… читайте следующую статью, которая будет после последнего экзамена, 25-го числа, в которой я расскажу про новый Form Framework, разработанный для Symfony 1.1.
PS. Я тут так подумал… Стоит ли писать про стандартные функции Symfony подробнее? Например, для тех, кто не знаком с этим фреймворком фраза “создадим модуль account” выглядит не совсем понятно. Стоит ли расписывать, как это нужно делать, или всё же лучше писать как сейчас, т.к. ответы на такие вопросы есть в онлайн книге?..
PPS. Ну всё… Теперь я на 3 дня с головой ушел в подготовку к последнему экзамену.
2 Pings to “Symfony 1.0: работа с формами”
25 Responses to “Symfony 1.0: работа с формами”
-
1. Nikita Says:
January 22nd, 2008 at 11:30<?php echo label_for(’last_name’, ‘Имя’); ?>
Вот такого плана функции никогда не понимал. Проще писать html:
<label for=”last_name”>Имя</label> -
2. FX Poster Says:
January 22nd, 2008 at 11:46Ну с label’ом да, согласен. То же самое могу скказать и про submit_tag. А вот остальное - вполне-таки нужные вещи.
-
3. mihailt Says:
January 22nd, 2008 at 12:19Хмм…. в принципе почти как в CI - для форм хелпер(для нормальной работы хелпер урлов тоже должен быть загружен), для валидации библотека. Естественно сам процесс несколько иной, но всё же на мой взгляд сходство есть.
в CI происходит так -
делаем 2 вьюшки 1ый для формы(составлять с учётом проверки), 2ой на успешный submit.
в котроллере всё происходит примерно так://подгружаем хелперы и библиотеку
$this->load->helper(array(’form’, ‘url’));
$this->load->library(’validation’);// задаём и устанавливаем правила для формы
$rules['username'] = “trim|required|min_length[5]|max_length[12]“;
$rules['password'] = “trim|required|matches[password_repeat]|md5″;
$rules['password_repeat'] = “trim|required”;
$rules['firstname'] = “trim|required|min_length[3]|max_length[20]“;
$rules['lastname'] = “trim|required|min_length[3]|max_length[20]“;
$rules['email'] = “trim|required|valid_email”;$this->validation->set_rules($rules);
//если проходим то 2ой вью, если нет то 1ый
if ($this->validation->run() == FALSE) {
$this->load->view(’form’);
}
else {
$this->load->view(’valid’);
}Примерно так ;)
-
4. Steward Says:
January 22nd, 2008 at 12:19спасибо - написано как для тупых :)) - т.е. специально для меня
-
5. Steward Says:
January 22nd, 2008 at 12:26ым.. не согласен с Nikita… при таком подходе как в статье
во-первых - соблюдается единообразие кода - откуда вытекает простота поддерки - нет неоправданных разрывов в html и php коде
во-вторых - если интерфейс мультиязычный гораздо красивее будет выглядетьчем
это кстати в тему нашего спора по поводу пхп-библиотеки для jquery - просто так красивее выглядит код и его проще понять человеку - интерпретатору вообще пофиг :)
-
6. Steward Says:
January 22nd, 2008 at 12:31FX Poster - кстати :)
1) отличный дизайн - мне офигенно нравится
2) не хотите ли вы прикрутить фишку выделения своих собственных коментариев - где-то недавно видел пример для WordPress - думаю идею можно и сюда перенести - будет лучше
3) не хотите ли вы либо всё перевести на русский, либо всё оставить на английском - я про заголовки разделов, форму отправки коментариев и т.д. - а то как-то смотрится нехорошоэто всё моё имхо - просьба не посылать нафиг :)))
-
7. FX Poster Says:
January 22nd, 2008 at 12:442. Посмотрим. PS. Это и есть Wordpress ;)
3. Пока времени нет. Потом переведу на русский. -
8. Nikita Says:
January 22nd, 2008 at 12:46Steward, мда?
А не хочешь ли все тэги писать таким образом?
<?php opentag(”div”); ?>
……………
<?php closetag(”div”); ?>Паранойя, так паранойя!
-
9. FX Poster Says:
January 22nd, 2008 at 12:50mihailt
Мне в симфоневском подходе нравиться вынесение валидации в отдельное место и написание её в декларативной форме. Хотя сам подход к написанию форм не особо нравится. В Symfony 1.1 он лучше, но об этом потом. ;)PS. В CI не нравится вот именно такая фишка - делаем load и оно создает один обьект этого класса внутри нашего контроллера. Ну млин - зачем? Я хочу сам создавать обьекты и создавать их столько, сколько мне нужно, а не довольствоваться одним. Такой фигни в CI предостаточно. Мне вот это и не нравится. В Kohana с этим получше.
-
10. Steward Says:
January 22nd, 2008 at 13:422 Nikita нет.. вы не поняли…
как раз с div всё понятно….
вот код.. который порезался (тоже кстати надо доработать :))) чтобы код нормально можно было вставлять :).. да ещё и http://softwaremaniacs.org/soft/highlight/ прикрутить :)))так вот красиво:
<?php какой-то код ?>
<?php echo label_for(’last_name’, $name); ?>
<?php какой-то код ?>
некрасиво:
<?php какой-то код ?>
<label for=”last_name”> <?php echo $name; ?></label>
<?php какой-то код ?> -
11. FX Poster Says:
January 22nd, 2008 at 13:44Steward
Тебя глючит. highlight.js тут давно стоит и работает. -
12. mihailt Says:
January 22nd, 2008 at 13:47В CI не нравится вот именно такая фишка - делаем load и оно создает один обьект этого класса внутри нашего контроллера. Ну млин - зачем? Я хочу сам создавать обьекты и создавать их столько, сколько мне нужно, а не довольствоваться одним.
Вопрос - а зачем тебе, при условии использования CI, такое надо?? это из серии хочу доступ к методам такого-то контроллера из другого контроллера нафиг? нужны такие методы - сделай библиотеку и всё.
-
13. Nikita Says:
January 22nd, 2008 at 13:53Steward, в примере FX’а нет никаких $name.
-
14. FX Poster Says:
January 22nd, 2008 at 13:53Нет. Это из серии “сделаем все обьекты singleton’ами”. Т.е. по сути всё, что ты load’ишь через $this->load получается чем-то типа singleton’а. А оно ну вообще им быть не должно.
-
15. mihailt Says:
January 22nd, 2008 at 13:57FXposter
Хотя сам подход к написанию форм не особо нравится.
а что не нравится? опять-таки в CI примерно так-же
form_open($action, $attributes)
form_input($fieldname,$value,$attributes)
form_password($fieldname,$value,$attributes)
form_submit($fieldname,$value,$attributes)
form_close()
-
16. mihailt Says:
January 22nd, 2008 at 14:16FXPoster
Т.е. по сути всё, что ты load’ишь через $this->load получается чем-то типа singleton’а.
На самом деле не типа, а именно синглетон и есть :) если есть желание посмотри base5.php и base4.php
А оно ну вообще им быть не должно.
а почему не должно? это дело соответствует определённому представлению о реализации MVC
теоретически есть возможность это дело немного переделать(вроде даже мод есть), но скорее всего лучше будет использовать другой фреймворк что ты с успехом и делаешь ;)
-
17. FX Poster Says:
January 22nd, 2008 at 15:51а что не нравится
Скажем так, нравится подход, используемый в Symfony 1.1. На фоне него подход, описаный выше, смотрится бледновато.а почему не должно
Паттерн Singleton используется тогда, когда за всю работу программы нужен один обьект определенного класса. Почему в CI решили, что мне определенно нужна один обьект БД, по одному обьекту каждой модели и т.д.? Этот подход работает, но такие идиотские ограничения - имхо, бред. -
18. mihailt Says:
January 22nd, 2008 at 16:49FXPoster
Этот подход работает, но такие идиотские ограничения - имхо, бред.
Может ты и прав… хз…, хотя я лично не вижу нафиг оно нужно. ;)
-
19. Slaff Says:
January 24th, 2008 at 23:30Молодец! Продолжай про симфони в том же духе и не забрасывай. Это классный framework и инфы такой по нему в рунете очень мало :)
-
20. FX Poster Says:
January 24th, 2008 at 23:36Пасиб. :) Продолжать буду обязательно - благо, я на нем на работе пишу.
-
21. Zeke Fast Says:
January 30th, 2008 at 02:24Не хочется продиводействовать общему положительному настрою, но, как мне кажется, эта вся информация есть на Symfony Project & Symfony Framework. Так что нового довольно мало.
Я тут заметил в комментах, что автор упомянул что работает с ним. Очень было бы интересно обменяться опытом, возникающими проблемами и прочей информацией более конкретного содержания.
P.S. Хочется предложить идею прикреплять к каждой статье по разделу со ссылками на ресурсы. А в статьях не пересказывать мануал или переводить его на русский, а выделять проблемные моменты или предлагать решения каких-либо проблем… (Чувствую, что сейчас меня отправят на форум симфони и ирку … не надо я там уже и так сижу ;-) )
Очень понравились статьи обзорного типа, которые не пересказывают мануалы, а локанично дают обзоры возможностей и ссылки для более детального ознакомления.
Спасибо!
-
22. FX Poster Says:
January 31st, 2008 at 00:28Есть. Я просто описал это всё быстро, понятно (надеюсь), на конкретном примере из жизни.
-
23. mihailt Says:
February 11th, 2008 at 21:50Слушай, может расскажешь про компонентный подход в новой Symfony?
-
24. FX Poster Says:
February 11th, 2008 at 21:55Расскажу, как будет время.
-
25. FX Poster Says:
February 11th, 2008 at 22:02Если вкратце - там что-то типа Zend_Form. Похожесть - 90% :)






January 22nd, 2008 at 22:27
[...] 22, 2008 frameworks , php Tags: active record, codeigniter, forms, frameworks, php Fx Poster рассказывает о работе с формами в симфони на примере формы регистрации пользователей. Для [...]
March 27th, 2008 at 00:46
[...] завтра, а пока что советую вспомнить, о чем я писал в статье про формы в Symfony 1.0. Вспомнили? Теперь стало понятно название [...]