表单

注册、签到、加入购物车、结账,这些等等都是在网店应用中利用HTML表单等进行的操作。构建表单是开发人员最常见的任务之一。一个经常需要花时间才能做好的工作。

Symfony 有一个表单组件,通过它我们可以用OO的方式来构建HTML表单。该组件本身也是一个独立的库,可以独立于 Symfony 使用。

我们来看看src/AppBundle/Entity/Customer.php文件的内容,我们的 Customer实体类是我们通过控制台定义时自动生成的。

class Customer {
  private $id;
  private $firstname;
  private $lastname;
  private $email;

  public function getId() {
    return $this->id;
  }

  public function setFirstname($firstname) {
    $this->firstname = $firstname;
    return $this;
  }

  public function getFirstname() {
    return $this->firstname;
  }

  public function setLastname($lastname) {
    $this->lastname = $lastname;
    return $this;
  }

  public function getLastname() {
    return $this->lastname;
  }

  public function setEmail($email) {
    $this->email = $email;
    return $this;
  }

  public function getEmail() {
    return $this->email;
  }
}

这里我们有一个普通的PHP类,它没有扩展任何东西,也没有以任何其他方式与 Symfony 链接。它代表了一个单一的客户实体,并为其设置和获取数据。有了这个实体类,我们想渲染一个表单,以获取我们的类所使用的所有相关数据。这就是表单组件的作用。

当我们之前通过控制台使用CRUD生成器时,它在src/AppBundle/Form/CustomerType.php文件中为我们的Customer实体创建了Form类,内容如下:

namespace AppBundle\Form;

use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;

class CustomerType extends AbstractType
{
  public function buildForm(FormBuilderInterface $builder, array $options) {
    $builder
    ->add('firstname')
    ->add('lastname')
    ->add('email')
    ;
  }

  public function configureOptions(OptionsResolver $resolver) {
    $resolver->setDefaults(array(
      'data_class' =>'AppBundle\Entity\Customer'
    ));
  }
}

我们可以看到表单组件背后的简单性归结为以下几点:

  • 扩展表格类型。我们从Symfony\Component\Form/AbstractType类中扩展出来。

  • 实现 buildForm 方法。这就是我们添加实际字段的地方,我们希望在表格上显示的字段。

  • 实现 configureOptions。这至少指定了指向我们客户实体的data_class配置。

表单生成器对象在这里做的是繁重的工作。它不需要太多的时间就可以创建一个表单。有了表单类之后,让我们来看看负责给模板输入表单的控制器动作。在本例中,我们将关注src/AppBundle/Controller/CustomerController.php文件中的newAction,内容如下所示:

$customer = new Customer();
$form = $this->createForm('AppBundle\Form\CustomerType', $customer);
$form->handleRequest($request);

if ($form->isSubmitted() && $form->isValid()) {
  $em = $this->getDoctrine()->getManager();
  $em->persist($customer);
  $em->flush();

  return $this->redirectToRoute('customer_show', array('id' =>$customer->getId()));
}

return $this->render('customer/new.html.twig', array(
  'customer' => $customer,
  'form' => $form->createView(),
));

前面的代码首先实例化了Customer实体类。$this->createForm(...)实际上是调用$this->container->get('form.factory')->create(...),传递给它我们的表单类名称和customer对象的实例,然后我们有isSubmittedisValid检查,看看这是否是GET或有效的POST请求。根据这个检查,代码要么返回客户列表,要么将表单和客户实例设置为使用模板customer/new.html.twig。关于实际的验证,我们会在后面再讲。

最后,让我们来看看app/Resources/views/customer/new.html.twig文件中的实际模板:

{% extends 'base.html.twig' %}

{% block body %}
<h1>Customer creation</h1>

{{ form_start(form) }}
{{ form_widget(form) }}
<input type="submit" value="Create" />
{{ form_end(form) }}

<ul>
  <li>
    <a href="{{ path('customer_index') }}">Back to the list</a>
  </li>
</ul>
{% endblock %}

在这里我们看到了extendsblock标签,以及一些相关的表单功能。Symfony 在Twig中增加了以下几个表单渲染功能:

  • form(view, variables)

  • form_start(view, variables)

  • form_end(view, variables)

  • form_label(view, label, variables)

  • form_errors(view)

  • form_widget(view, variables)

  • form_row(view, variables)

  • form_rest(view, variables)

我们的大多数申请表格都会像这样自动生成,所以我们能够得到一个功能完备的CRUD,而不需要太深入地了解表格的其他功能。

最后更新于