表单验证

至此完成了自定义首页,接下来准备做about页面和contact页面。

About页面

首先添加路由配置:

  1. blogger_blogBundle_about:
  2. pattern: /about
  3. defaults: { _controller: BloggerBlogBundle:Page:about }
  4. requirements:
  5. _method: GET

然后在PageController中添加新的Action:

  1. /**
  2. * about page.
  3. *
  4. * @return array
  5. *
  6. * @Template()
  7. */
  8. public function aboutAction()
  9. {
  10. return array();
  11. }

这部分代码的功能与如下相同:

  1. public function aboutAction()
  2. {
  3. return $this->render('BloggerBlogBundle:Page:about.html.twig');
  4. }

@Template()注释信息在这里有作用的,它用于指定使用的模板。参数为空则使用about.html.twig

在前面说过Symfony2的配置可以使用php, xml, yml 和 annotation这四种格式。这里的@Template()就是annotation格式的配置。

对于路由配置也可以使用annotation格式:

  1. /**
  2. * @Route("/about", name="blogger_blogBundle_about")
  3. * @Template()
  4. */
  5. public function aboutAction()
  6. {
  7. return array();
  8. }

annotation的配置方式与flaskbottle框架的装饰器概念类似。不过为了便于统一管理,按照之前的约定,除了数据库的Model实体(Entity)使用annotation格式外其余的都使用yml格式。

最后再创建模板文件src/Blogger/BlogBundle/Resources/views/Page/about.html.twig

Contact页面

按照相同方法再创建Contact页面。

  1. {# src/Blogger/BlogBundle/Resources/views/Page/contact.html.twig #}
  2. {% extends 'BloggerBlogBundle::layout.html.twig' %}
  3. {% block title %}Contact{% endblock%}
  4. {% block body %}
  5. <header>
  6. <h1>Contact symblog</h1>
  7. </header>
  8. <p>Want to contact symblog?</p>
  9. {% endblock %}

最后将这些页面连接起来。最简单的方法就是直接修改连接地址:

  1. <a href="/about">About</a>
  2. <a href="/contact">Contact</a>

这样比较简单,但是如果以后这两个页面的路径改变了,那么所有引用了这两个地址的地方都需要修改。正确做法应该是在模板中使用path方法生成地址。

  1. <a href="{{ path('blogger_blogBundle_homepage') }}">Home</a>
  2. <a href="{{ path('blogger_blogBundle_about') }}">About</a>
  3. <a href="{{ path('blogger_blogBundle_contact') }}">Contact</a>

创建表单

现在我们要在Contact页面添加一个表单,以便让用户提交信息。

首先创建一个联系实体用于处理用户提交的内容,新建文件 src/Blogger/BlogBundle/Entity/Enquiry.php

  1. <?php
  2. // src/Blogger/BlogBundle/Entity/Enquiry.php
  3. namespace Blogger\BlogBundle\Entity;
  4. class Enquiry
  5. {
  6. protected $name;
  7. protected $email;
  8. protected $subject;
  9. protected $body;
  10. public function getName()
  11. {
  12. return $this->name;
  13. }
  14. public function setName($name)
  15. {
  16. $this->name = $name;
  17. }
  18. public function getEmail()
  19. {
  20. return $this->email;
  21. }
  22. public function setEmail($email)
  23. {
  24. $this->email = $email;
  25. }
  26. public function getSubject()
  27. {
  28. return $this->subject;
  29. }
  30. public function setSubject($subject)
  31. {
  32. $this->subject = $subject;
  33. }
  34. public function getBody()
  35. {
  36. return $this->body;
  37. }
  38. public function setBody($body)
  39. {
  40. $this->body = $body;
  41. }
  42. }

这个类只是定义了一些属性,并没有定义属性的验证或者是属性与表单的关联。关于这个内容下面会说到。

实例类创建完成之后再创建一个表单类,新建文件 src/Blogger/BlogBundle/Form/EnquiryType.php

  1. <?php
  2. // src/Blogger/BlogBundle/Form/EnquiryType.php
  3. namespace Blogger\BlogBundle\Form;
  4. use Symfony\Component\Form\AbstractType;
  5. use Symfony\Component\Form\FormBuilder;
  6. class EnquiryType extends AbstractType
  7. {
  8. public function buildForm(FormBuilder $builder, array $options)
  9. {
  10. $builder->add('name');
  11. $builder->add('email', 'email');
  12. $builder->add('subject');
  13. $builder->add('body', 'textarea');
  14. }
  15. public function getName()
  16. {
  17. return 'contact';
  18. }
  19. }

这里使用了FormBuilder对象来创建表单。

然后就可以在Controller中使用表单了。

  1. /**
  2. * about page.
  3. *
  4. * @return array
  5. *
  6. * @Template()
  7. */
  8. public function contactAction()
  9. {
  10. $enquiry = new Enquiry();
  11. $form = $this->createForm(new EnquiryType(), $enquiry);
  12. $request = $this->get('request');
  13. if ($request->getMethod() == 'POST') {
  14. $form->bind($request);
  15. if ($form->isValid()) {
  16. // 表单验证通过,执行一些操作,如发送邮件。
  17. // doSometing();
  18. return $this->redirect($this->generateUrl('blogger_blogBundle_contact'));
  19. }
  20. }
  21. return array('form' => $form->createView());
  22. }

这里通过createForm方法创建一个表单对象,然后再用bind方法来接收发送过来的信息并保存到$enquiry对象的对应属性上。

最后要显示表单还得修改模板。在src/Blogger/BlogBundle/Resources/views/Page/contact.html.twig模板中添加如下内容:

  1. <form action="{{ path('blogger_blogBundle_contact') }}" method="post" {{ form_enctype(form) }} class="blogger">
  2. {{ form_widget(form) }}
  3. <input type="submit" />
  4. </form>

以上是比较简便的方法,通过form_widget将整个表单进行渲染。也可以手动的渲染表单特定字段。内容如下:

  1. <form action="{{ path('blogger_blogBundle_contact') }}" method="post" {{ form_enctype(form) }} class="blogger">
  2. {{ form_errors(form) }}
  3. {{ form_row(form.name) }}
  4. {{ form_row(form.email) }}
  5. {{ form_row(form.subject) }}
  6. {{ form_row(form.body) }}
  7. {{ form_rest(form) }}
  8. <input type="submit" />
  9. </form>

为了美观我们再为表单定义一些样式,新建文件src/Blogger/BlogBundle/Resources/public/css/blog.css,内容如下:

  1. .blogger-notice { text-align: center; padding: 10px; background: #DFF2BF; border: 1px solid; color: #4F8A10; margin-bottom: 10px; }
  2. form.blogger { font-size: 16px; }
  3. form.blogger div { clear: left; margin-bottom: 10px; }
  4. form.blogger label { float: left; margin-right: 10px; text-align: right; width: 100px; font-weight: bold; vertical-align: top; padding-top: 10px; }
  5. form.blogger input[type="text"],
  6. form.blogger input[type="email"]
  7. { width: 500px; line-height: 26px; font-size: 20px; min-height: 26px; }
  8. form.blogger textarea { width: 500px; height: 150px; line-height: 26px; font-size: 20px; }
  9. form.blogger input[type="submit"] { margin-left: 110px; width: 508px; line-height: 26px; font-size: 20px; min-height: 26px; }
  10. form.blogger ul li { color: #ff0000; margin-bottom: 5px; }

同时别忘了在模板中引用该样式文件:

  1. <link href="{{ asset('bundles/bloggerblog/css/blog.css') }}" type="text/css" rel="stylesheet" />

在模板中使用 asset 引用资源文件默认是从 web 目录下查找。为了能够正常查找到资源文件,需要使用如下命令进行资源收集:

  1. $ php app/console assets:install

收集的文件存放在 web/bundles/<namespace><bundle_name>/目录下。

这个类似于Django中的 ./manager.py collectstatic

现在再用浏览器打开 http://127.0.0.1:8000/contact 页面看看效果。

第4章 表单验证  - 图1

表单验证

表单算是是正常显示了,接下来说是对用户提交的数据进行合法性检查。

首先修改路由配置,以便让/contact能够接收POST请求。

然后再编写表单验证规则。Symfony2已经为我们提供一些常用的验证器。重新编辑Enquiry实体,先导入几个类:

  1. use Symfony\Component\Validator\Mapping\ClassMetadata;
  2. use Symfony\Component\Validator\Constraints\NotBlank;
  3. use Symfony\Component\Validator\Constraints\Email;
  4. use Symfony\Component\Validator\Constraints\Length;

再为Enquiry类添加loadValidatorMetadata方法:

  1. public static function loadValidatorMetadata(ClassMetadata $metadata)
  2. {
  3. $metadata->addPropertyConstraint('name', new NotBlank());
  4. $metadata->addPropertyConstraint('email', new Email(array('message' => 'invalid email!')));
  5. $metadata->addPropertyConstraint('subject', new NotBlank());
  6. $metadata->addPropertyConstraint('subject', new Length(array('max' => 50)));
  7. $metadata->addPropertyConstraint('body', new Length(array('min' => 10)));
  8. }

现在可以试试随便提交一些不合法的内容,看看错误提示。

发送邮件

最后我们还需要在用户提交信息之后给网站站长发送一封邮件。好在Symfony2已经包含了Swift Mailer库可以用来完成该功能。

首先编辑app/config/parameters.yml文件,找到 mailer_开头的参数,设置发送邮件的帐号信息。以下是一个例子:

  1. mailer_transport="gmail"
  2. mailer_encryption="ssl"
  3. mailer_auth_mode="login"
  4. mailer_host="smtp.gmail.com"
  5. mailer_user="your_username"
  6. mailer_password="your_password"

接着再更新Controller:

  1. if ($form->isValid()) {
  2. $message = \Swift_Message::newInstance()
  3. ->setSubject('Contact enquiry from symblog')
  4. ->setFrom('send account') // 发件帐号
  5. ->setTo('receive account') // 收件帐号
  6. ->setBody($this->renderView('BloggerBlogBundle:Page:contactEmail.txt.twig', array('enquiry' => $enquiry)));
  7. $this->get('mailer')->send($message);
  8. $this->get('session')->getFlashBag()->set('blogger-notice', 'Your contact enquiry was successfully sent. Thank you!');
  9. return $this->redirect($this->generateUrl('blogger_blogBundle_contact'));
  10. }

然后创建一个邮件模板src/Blogger/BlogBundle/Resources/views/Page/contactEmail.txt.twig,内容如下:

  1. {# src/Blogger/BlogBundle/Resources/views/Page/contactEmail.txt.twig #}
  2. A contact enquiry was made by {{ enquiry.name }} at {{ "now" | date("Y-m-d H:i") }}.
  3. Reply-To: {{ enquiry.email }}
  4. Subject: {{ enquiry.subject }}
  5. Body:
  6. {{ enquiry.body }}

然后在模板中显示flash提示信息:

  1. <header>
  2. <h1>Contact symblog</h1>
  3. </header>
  4. {% if app.session.flashbag.has('blogger-notice') %}
  5. {% for flashMessage in app.session.flashbag.get('blogger-notice') %}
  6. <div class="blogger-notice">
  7. {{ flashMessage }}
  8. </div>
  9. {% endfor %}
  10. {% endif %}
  11. <p>Want to contact symblog?</p>

再次提交表单查看效果:第4章 表单验证  - 图2