Jan 22

То, что мне очень не нравилось в 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 дня с головой ушел в подготовку к последнему экзамену.

written by fxposter \\ tags: , , ,

2 Pings to “Symfony 1.0: работа с формами”

  1. Работа с формами в Codeigniter « mihailt Says:

    […] 22, 2008 frameworks , php Tags: active record, codeigniter, forms, frameworks, php Fx Poster рассказывает о работе с формами в симфони на примере формы регистрации пользователей. Для […]

  2. Symfony 1.1 Form Framework: Day 1 » Блог FX'а Says:

    […] завтра, а пока что советую вспомнить, о чем я писал в статье про формы в Symfony 1.0. Вспомнили? Теперь стало понятно название […]


28 Responses to “Symfony 1.0: работа с формами”

  1. 1. Nikita Says:

    <?php echo label_for(‘last_name’, ‘Имя’); ?>
    Вот такого плана функции никогда не понимал. Проще писать html:
    <label for=”last_name”>Имя</label>

  2. 2. FX Poster Says:

    Ну с label’ом да, согласен. То же самое могу скказать и про submit_tag. А вот остальное – вполне-таки нужные вещи.

  3. 3. mihailt Says:

    Хмм…. в принципе почти как в 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. 4. Steward Says:

    спасибо – написано как для тупых :)) – т.е. специально для меня

  5. 5. Steward Says:

    ым.. не согласен с Nikita… при таком подходе как в статье
    во-первых – соблюдается единообразие кода – откуда вытекает простота поддерки – нет неоправданных разрывов в html и php коде
    во-вторых – если интерфейс мультиязычный гораздо красивее будет выглядеть

    чем

    это кстати в тему нашего спора по поводу пхп-библиотеки для jquery – просто так красивее выглядит код и его проще понять человеку – интерпретатору вообще пофиг :)

  6. 6. Steward Says:

    FX Poster – кстати :)
    1) отличный дизайн – мне офигенно нравится
    2) не хотите ли вы прикрутить фишку выделения своих собственных коментариев – где-то недавно видел пример для WordPress – думаю идею можно и сюда перенести – будет лучше
    3) не хотите ли вы либо всё перевести на русский, либо всё оставить на английском – я про заголовки разделов, форму отправки коментариев и т.д. – а то как-то смотрится нехорошо

    это всё моё имхо – просьба не посылать нафиг :)))

  7. 7. FX Poster Says:

    2. Посмотрим. PS. Это и есть WordPress ;)
    3. Пока времени нет. Потом переведу на русский.

  8. 8. Nikita Says:

    Steward, мда?
    А не хочешь ли все тэги писать таким образом?
    <?php opentag(“div”); ?>
    ……………
    <?php closetag(“div”); ?>

    Паранойя, так паранойя!

  9. 9. FX Poster Says:

    mihailt
    Мне в симфоневском подходе нравиться вынесение валидации в отдельное место и написание её в декларативной форме. Хотя сам подход к написанию форм не особо нравится. В Symfony 1.1 он лучше, но об этом потом. ;)

    PS. В CI не нравится вот именно такая фишка – делаем load и оно создает один обьект этого класса внутри нашего контроллера. Ну млин – зачем? Я хочу сам создавать обьекты и создавать их столько, сколько мне нужно, а не довольствоваться одним. Такой фигни в CI предостаточно. Мне вот это и не нравится. В Kohana с этим получше.

  10. 10. Steward Says:

    2 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. 11. FX Poster Says:

    Steward
    Тебя глючит. highlight.js тут давно стоит и работает.

  12. 12. mihailt Says:

    В CI не нравится вот именно такая фишка – делаем load и оно создает один обьект этого класса внутри нашего контроллера. Ну млин – зачем? Я хочу сам создавать обьекты и создавать их столько, сколько мне нужно, а не довольствоваться одним.

    Вопрос – а зачем тебе, при условии использования CI, такое надо?? это из серии хочу доступ к методам такого-то контроллера из другого контроллера нафиг? нужны такие методы – сделай библиотеку и всё.

  13. 13. Nikita Says:

    Steward, в примере FX’а нет никаких $name.

  14. 14. FX Poster Says:

    Нет. Это из серии “сделаем все обьекты singleton’ами”. Т.е. по сути всё, что ты load’ишь через $this->load получается чем-то типа singleton’а. А оно ну вообще им быть не должно.

  15. 15. mihailt Says:

    FXposter

    Хотя сам подход к написанию форм не особо нравится.

    а что не нравится? опять-таки в CI примерно так-же

    form_open($action, $attributes)
    form_input($fieldname,$value,$attributes)
    form_password($fieldname,$value,$attributes)
    form_submit($fieldname,$value,$attributes)
    form_close()

  16. 16. mihailt Says:

    FXPoster

    Т.е. по сути всё, что ты load’ишь через $this->load получается чем-то типа singleton’а.

    На самом деле не типа, а именно синглетон и есть :) если есть желание посмотри base5.php и base4.php

    А оно ну вообще им быть не должно.

    а почему не должно? это дело соответствует определённому представлению о реализации MVC

    теоретически есть возможность это дело немного переделать(вроде даже мод есть), но скорее всего лучше будет использовать другой фреймворк что ты с успехом и делаешь ;)

  17. 17. FX Poster Says:

    а что не нравится
    Скажем так, нравится подход, используемый в Symfony 1.1. На фоне него подход, описаный выше, смотрится бледновато.

    а почему не должно
    Паттерн Singleton используется тогда, когда за всю работу программы нужен один обьект определенного класса. Почему в CI решили, что мне определенно нужна один обьект БД, по одному обьекту каждой модели и т.д.? Этот подход работает, но такие идиотские ограничения – имхо, бред.

  18. 18. mihailt Says:

    FXPoster

    Этот подход работает, но такие идиотские ограничения – имхо, бред.

    Может ты и прав… хз…, хотя я лично не вижу нафиг оно нужно. ;)

  19. 19. Slaff Says:

    Молодец! Продолжай про симфони в том же духе и не забрасывай. Это классный framework и инфы такой по нему в рунете очень мало :)

  20. 20. FX Poster Says:

    Пасиб. :) Продолжать буду обязательно – благо, я на нем на работе пишу.

  21. 21. Zeke Fast Says:

    Не хочется продиводействовать общему положительному настрою, но, как мне кажется, эта вся информация есть на Symfony Project & Symfony Framework. Так что нового довольно мало.

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

    P.S. Хочется предложить идею прикреплять к каждой статье по разделу со ссылками на ресурсы. А в статьях не пересказывать мануал или переводить его на русский, а выделять проблемные моменты или предлагать решения каких-либо проблем… (Чувствую, что сейчас меня отправят на форум симфони и ирку … не надо я там уже и так сижу ;-) )

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

    Спасибо!

  22. 22. FX Poster Says:

    Есть. Я просто описал это всё быстро, понятно (надеюсь), на конкретном примере из жизни.

  23. 23. mihailt Says:

    Слушай, может расскажешь про компонентный подход в новой Symfony?

  24. 24. FX Poster Says:

    Расскажу, как будет время.

  25. 25. FX Poster Says:

    Если вкратце – там что-то типа Zend_Form. Похожесть – 90% :)

  26. 26. Vladimir Says:

    спасибо вам, опять кое что просветил для себя (особенно много почерпнул из комментов) полностью согласен с Nikita я тоже долгое время еще когда разбирался с шаблонизатором Smarty не понимал его смыса, особенно когда многие программеры делая шаблоны и говорят что это для дизайнеров/верстальшиков “которые не понимают язык программирования”, тем не менее различные массивы кода между {} я думаю и не каждый программер сходу разберет :) а еще когда вставляют в код {php} {/php} и пишут программы, мне кажется это просто извращение
    с симфонией постоянно переругиваясь сам с собой безвозвратно постигаю,
    для меня большие проблемы вызывает эта “распределенность” кода и куча хелперов которые все сразу не охватить и я постоянно изобретаю велосипед.
    хотя за свое программистское настоящее я написал нечто (уверен каждый кто длительное время занимается программированием – написал подобие своего фреймворка)
    и вот сложно сразу вникнуть во внутренний мир другого человека чтобы понять его фреймворк :)) (особенно когда пытливый ум требует не просто стандартные формы и проверки, а ajax, и вложенные формы)

  27. 27. FX Poster Says:

    Радует, что мои посты все еще приносят пользу людям :)

  28. 28. Vladimir Says:

    да, конечно многое в 1.3, 1.4 версиях поменялось но суть осталась.
    глядишь и через 10 лет кто-нибудь оставит след на этой табличке :)

Leave a Reply