当你映射表单到一个对象是,所有的字段都被映射。 表单的任何字段如果在映射的对象上不存在那么就会造成抛出异常。在这种情况下,你需要在表单中获取字段(比如,一个“你同意这些说法吗?”复选框)将不能映射到底层对象,那么你需要设置property_path为false以避免抛出异常。
public function buildForm(FormBuilder $builder, array $options) { $builder->add('task'); $builder->add('dueDate', null, array('property_path' => false)); }
另外,如果有任何的表单字段没有被包含着提交的数据中,那么这些字段需要显式的设置为null。
在controller类中我们可以访问字段数据:
$form->get('dueDate')->getData();
Forms和Doctrine
表单的目的是把数据从一个底层对象传递给一个HTML表单然后把用户提交的数据传回到原先的底层对象。因此,底层对象把数据持久化到数据库就跟表单没有任何的关系了。但是,如果你已经配置了底层类是通过Doctrine来持久化,(你已经定义了映射元数据在底层类),接下来当表单提交数据后,当表单合法后就可以持久化它了。
if ($form->isValid()) { $em = $this->getDoctrine()->getEntityManager(); $em->persist($task); $em->flush(); return $this->redirect($this->generateUrl('task_success')); }
如果处于某种原因,你不想访问原有的$task对象,你可以从表单中直接获取数据:
$task = $form->getData();
在这里,关键要理解当表单跟底层对象绑定后,用户提交的数据会立刻传递给底层对象。如果你想持久化这些数据,你只需要持久化对象本身即可。
嵌入式表单:(Embedded Forms)
通常,你可能想生成一个表单,它包含来自不同对象的字段。比如,一个注册表单可能包含属于User对象和Address对象的字段。幸运的是,这些对于form组件来说都是很容易很自然的事。嵌入一个单独对象:假设每个Task属于一个Category对象,首先创建这个Category对象:
// src/Acme/TaskBundle/Entity/Category.php namespace Acme\TaskBundle\Entity; use Symfony\Component\Validator\Constraints as Assert; class Category { /** * @Assert\NotBlank() */ public $name; }
接下来,添加一个新的category属性到Task类:
// ... class Task { // ... /** * @Assert\Type(type="Acme\TaskBundle\Entity\Category") */ protected $category; // ... public function getCategory() { return $this->category; } public function setCategory(Category $category = null) { $this->category = $category; } }
现在我们来相应我们应用程序的一个新需求,需要创建一个 表单可以让用户修改Category对象。
// src/Acme/TaskBundle/Form/Type/CategoryType.php namespace Acme\TaskBundle\Form\Type; use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\FormBuilder; class CategoryType extends AbstractType { public function buildForm(FormBuilder $builder, array $options) { $builder->add('name'); } public function getDefaultOptions(array $options) { return array( 'data_class' => 'Acme\TaskBundle\Entity\Category', ); } public function getName() { return 'category'; } }
我们的最终目的是能够让用户在Task表单中修改Category对象,所以,我们需要添加一个类型为CategoryType表单类的category字段到TaskType 表单类。
public function buildForm(FormBuilder $builder, array $options) { // ... $builder->add('category', new CategoryType()); }
这时我们可以在TaskType类字段渲染的旁边渲染CategoryType类的字段了:
Twig格式:
{# ... #} <h3>Category</h3> <div> {{ form_row(form.category.name) }} </div> {{ form_rest(form) }} {# ... #}
PHP代码格式:
<!-- ... --> <h3>Category</h3> <div> <?php echo $view['form']->row($form['category']['name']) ?> </div> <?php echo $view['form']->rest($form) ?> <!-- ... -->
当用户提交表单时,提交的Category字段数据被用于创建一个Category实例,然后被设置到Task实例的category字段。该Category实例可以通过Task实例来访问,同时也能被持久化到数据或者用作它用。
$task->getCategory()
嵌入一个表单集合
你也可以将一个表单集合嵌入到一个表单(想象一个Category 表单和许多Product子表单)。它是通过一个字段类型集合类实现的。
表单主题化