The virtual form field option can be very useful when you have some duplicated fields in different entities.
当您在不同的实体中拥有一些重复的表单域时,虚拟表单域选项就显得非常有用。

For example, imagine you have two entities, a Company and a Customer:
举个例子,想象您有两个实体,Company和Customer:

Company实体:

  1. // src/Acme/HelloBundle/Entity/Company.php 
  2. namespace Acme\HelloBundle\Entity; 
  3.  
  4. class Company 
  5.     private $name
  6.     private $website
  7.  
  8.     private $address
  9.     private $zipcode
  10.     private $city
  11.     private $country

 Customer实体:

  1. // src/Acme/HelloBundle/Entity/Customer.php 
  2. namespace Acme\HelloBundle\Entity; 
  3.  
  4. class Customer 
  5.     private $firstName
  6.     private $lastName
  7.  
  8.     private $address
  9.     private $zipcode
  10.     private $city
  11.     private $country

Like you can see, each entity shares a few of the same fields: address, zipcode, city, country.
正如您所见,每个实体都有着一些相同的表单域:address、zipcode、city和country。

Now, you want to build two forms: one for a Company and the second for a Customer.
现在,您要创建两个表单:一个对应Company,第二个对应Customer。

Start by creating a very simple CompanyType and CustomerType:
首先创建一个非常简单的CompanyType和CustomerType:

CompanyType类:

  1. // src/Acme/HelloBundle/Form/Type/CompanyType.php 
  2. namespace Acme\HelloBundle\Form\Type; 
  3.  
  4. use Symfony\Component\Form\FormBuilderInterface; 
  5.  
  6. class CompanyType extends AbstractType 
  7.     public function buildForm(FormBuilderInterface $builderarray $options
  8.     { 
  9.         $builder 
  10.             ->add('name''text'
  11.             ->add('website''text'); 
  12.     } 

 CustomerType类:

  1. // src/Acme/HelloBundle/Form/Type/CustomerType.php 
  2. namespace Acme\HelloBundle\Form\Type; 
  3.  
  4. use Symfony\Component\Form\FormBuilderInterface; 
  5.  
  6. class CustomerType extends AbstractType 
  7.     public function buildForm(FormBuilderInterface $builderarray $options
  8.     { 
  9.         $builder 
  10.             ->add('firstName''text'
  11.             ->add('lastName''text'); 
  12.     } 

Now, we have to deal with the four duplicated fields. Here is a (simple) location form type:
现在我们需要处理那四个重复的表单域。下面是个(简单)的位置表单类型:

  1. // src/Acme/HelloBundle/Form/Type/LocationType.php 
  2. namespace Acme\HelloBundle\Form\Type; 
  3.  
  4. use Symfony\Component\Form\FormBuilderInterface; 
  5. use Symfony\Component\OptionsResolver\OptionsResolverInterface; 
  6.  
  7. class LocationType extends AbstractType 
  8.     public function buildForm(FormBuilderInterface $builderarray $options
  9.     { 
  10.         $builder 
  11.             ->add('address''textarea'
  12.             ->add('zipcode''text'
  13.             ->add('city''text'
  14.             ->add('country''text'); 
  15.     } 
  16.  
  17.     public function setDefaultOptions(OptionsResolverInterface $resolver
  18.     { 
  19.         $resolver->setDefaults(array
  20.             'virtual' => true 
  21.         )); 
  22.     } 
  23.  
  24.     public function getName() 
  25.     { 
  26.         return 'location'
  27.     } 

We don't actually have a location field in each of our entities, so we can't directly link our LocationType to our CompanyType or CustomerType. But we absolutely want to have a dedicated form type to deal with location (remember, DRY!).
实际上在每个实体中我们并没有location表单域,因此我们不能直接将LocationType链入我们的CompanyType或CustomerType中。但我们又绝对想要一个专门处理位置的表单类型(记住,DRY!)

The virtual form field option is the solution.
解决这个问题就需要用到虚拟表单域选项了。

We can set the option 'virtual' => true in the setDefaultOptions() method of LocationType and directly start using it in the two original form types.
我们可以在LocationType类中的setDefaultOptions()方法中将选项'virtual'设置为true,并且在两个原始域类型中直接使用它。

Look at the result:
所下所示:

CompanyType类:

  1. // CompanyType 
  2. public function buildForm(FormBuilderInterface $builderarray $options
  3.     $builder->add('foo'new LocationType(), array
  4.         'data_class' => 'Acme\HelloBundle\Entity\Company' 
  5.     )); 

 CustomerType类:

  1. // CustomerType 
  2. public function buildForm(FormBuilderInterface $builderarray $options
  3.     $builder->add('bar'new LocationType(), array
  4.         'data_class' => 'Acme\HelloBundle\Entity\Customer' 
  5.     )); 

With the virtual option set to false (default behavior), the Form Component expects each underlying object to have a foo (or bar) property that is either some object or array which contains the four location fields. Of course, we don't have this object/array in our entities and we don't want it!
当virtual选项设为false时(缺省值),表单组件期望每个相关的对象都有一个foo(或bar)属性,要么是一些对象,要么是包含四个位置表单域的数组。当然,在我们的实体中没有这样的对象或数组,而且我们也不想那样做!

With the virtual option set to true, the Form component skips the foo (or bar) property, and instead "gets" and "sets" the 4 location fields directly on the underlying object!
当virtual选项设为true时,表单组件忽略foo(或bar)属性,取而代之的是在相关对象中直接"gets"和"sets"这4个位置表单域!

Instead of setting the virtual option inside LocationType, you can (just like with any options) also pass it in as an array option to the third argument of $builder->add().
如果不使用在LocationType中设置virtual选项,您也可以(如其它选项那样)将其作为一个数组选项发送到$builder->add()的第三个参数。