Symfony 2 - 如何向formBuilder传递数据?

36

我在表单中使用了实体选择列表。我想仅使用特定的实体(例如:只有用户所属的群组)。

因此,在控制器中,我获取这些群组,并尝试将它们传递给formBuilder

控制器:

/.../
$groups = $em->getRepository('VendorMyBundle:Group')->getUserGroups($user);
$form = $this->createForm(new Message($groups), $message);
/.../

那么,现在怎么办?如何在formBuilder中使用它? 如何更改此行以使用传递的组数组?

->add('group','entity',array('class' => 'Vendor\MyBundle\Entity\Group', 'label'=>'Group:'))

或者另一种方式:

class MessageType
{
/.../
  public function buildForm(FormBuilder $builder, array $options)
  {
    $builder
      ->add('group','entity',
        array(
          'class' => 'Vendor\MyBundle\Entity\Group',
          'property' => 'name',
          'query_builder' => function ($repository) {
            $qb = $repository->createQueryBuilder('group');
            $qb->add('where', 'group.administrator = :user');
            $qb->setParameter('user', $user->getId());
            return $qb;
          },
          'label' => 'Group'
        )
      )
      // Continue adding fields
    ;
  }
/.../
}

如何获取对象 $user 以在表单构建器中使用?($user 表示当前登录的用户)


2
我问了同样的问题:-https://dev59.com/lGsz5IYBdhLWcg3wj4va Bacteries的解决方案真的很好!!! :thumbsup: - xeon
如果您需要执行查询、进行 API 调用等操作来呈现视图,则您的方法是错误的。如果这是 Symfony 框架对框架的限制(没有其他方式可以向表单构建器提供任意数据),那么他们应该感到羞耻。这是控制器的明确定义工作。 - eggmatters
6个回答

28
你可以在 __construct() 方法中传入你想要使用的对象。
例如:
$form = $this
    ->get('form.factory')
    ->create(new ApplyStepOneFormType($this->company, $this->ad), $applicant);

在你的表单类型中:

function __construct(\Your\Bundle\Entity\Company $company, \DYB\ConnectBundle\Entity\Ad $ad) {
    $this->company = $company;
    $this->ad = $ad;
}

然后在你的表单中输入buildForm方法:

$company = $this->company;    
$builder->add('ad', 'entity', array(
    'class' => '\Your\Bundle\Entity\Ad',
    'query_builder' => function(\Your\Bundle\Repository\AdRepository $er) use ($company) {
        return $er->getActiveAdsQueryBuilder($company);
    },
));

现在这个答案是错误的。你应该将这些参数作为选项(在configureOptions方法中定义)传递,而不是在表单Type__construct中传递。Type在容器中只构造一次,所以如果你在那里传递参数并且在同一个请求中使用不同的参数来多次使用Type,你会得到奇怪的行为:在那里,你应该只自动装配服务。 - ste

12
//In controller pass the value which you want to use in builder form in array like

$object = new Question();
$form->create(new QuestionType() , $object , array('sqtname'=>2,'question_type'=>2));


//In Form type class
public function buildForm(FormBuilderInterface $builder , array $options)
    {  
     //for setting data field dynamically 
  if (array_key_exists('question_type', $options) && $options['question_type'] != '') {
    $data = $em->getReference("RecrutOnlineStandardBundle:StdQuestionType",$options['question_type']->getId());
  } else {
    $data = "";
  }


  $builder->add('StdQuestionType', 'entity', array(
        'class' => 'TestStandardBundle:StdQuestionType',
        'property' => 'name',
        'empty_value' => 'Sélectionner un question type',
        'required' => true,
        'data' => $data,
        'query_builder' => function(EntityRepository $er ) use ( $options ) {
            if (isset($options['sqtname']) && $options['sqtname'] != '') {
                return $er->createQueryBuilder('sqt')
                                ->where("sqt.name!= ".$options['sqtname']);
            } else{
               return $er->createQueryBuilder('sqt');
            }
        }
    ));
 }

 public function setDefaultOptions(OptionsResolverInterface $resolver)
     {
       $resolver->setDefaults(array(
         'data_class' => 'Test\QuestionBundle\Entity\Question',
         'required' => false,
         'sqtname' => '',
         'question_type' =>'' 
       ));
     }

4

细菌的解决方案并不好。例如,如果您将类型声明为服务,则无法将对象传递给构造函数。

完美的解决方案是选项 - 只需将数据作为选项传递给表单构建器。


1
此外,他的解决方案将在3.0中崩溃,因为类型是由FQCN构建的。 - Ryall

2

Bacteries的解决方案真的很好。只是想提醒其他像我一样的人注意一下,以免头疼 :)

在这部分中,我可以指出use ($company)部分。 它被框架隐藏了,当然没有它什么都不能正常工作。

$builder->add('ad', 'entity', array(
   'class' => 
      '\Your\Bundle\Entity\Ad',
   'query_builder' => 
      function(\Your\Bundle\Repository\AdRepository $er) use ($company) {
            return $er->getActiveAdsQueryBuilder($company);
      },
    )
);

2

如果您想使用自定义查询,您需要按照以下方式设置query_builder选项:

use Doctrine\ORM\EntityRepository;

...

$message = new Message();

$form = $this->createFormBuilder($message)
             ->add('group', 'entity', array(
                   'class' => 'Vendor\MyBundle\Entity\Group',
                   'label'=>'Group:',
                   'query_builder' => function(EntityRepository $er) {
                       return $er->createQueryBuilder('g')
                                 ->... // whatever you want to do
                       }
                    ))
             ->getForm();

你可以在Doctrine手册中找到有关查询构建器的更多信息,以及在Symfony2手册中了解有关entity选项的内容。


是的,我知道如何使用自定义查询,但是当我想要获取当前登录用户的组时,我该如何使用它呢?我必须在表单类型类中声明一个容器吗?例如:在控制器中,我使用$this->get('security.context')->getToken()->getUser() - jacobmaster
1
我建议在这里使用ManyToOne或ManyToMany关系。这将使事情变得更容易。 - Ondrej Slinták
你可以在类型类中创建构造函数,并通过它将安全上下文变量推送到控制器中。 - Ondrej Slinták

0

我个人认为最好的方法是将entityManager传递给你的表单,并在其中选择所需的所有内容。但不要忘记在setDefaults()中声明一个空键,否则数据将无法传递给你的构建器。

类似于这样的方式

public function buildForm(FormBuilderInterface $builder, array $options)
{
    $options['em']->getRepository(''); // select all you need
    $builder->add('title', 'text')
            ->add('content', 'textarea');
}

public function setDefaultOptions(OptionsResolverInterface $resolver)
{
    $resolver->setDefaults(array(
        'data_class' => 'Main\BlogBundle\Entity\Post',
        'validation_groups' => array('post'),
        'required' => false,
        'em' => null // this var is for your entityManager
        ));
}

将EM作为简单选项应用...


这难道不是违背MVC应用程序的目的吗?我认为框架的整个重点是将数据层从呈现层模糊化,尽可能地实现这一点。 - eggmatters
Symfony2打破了你所知道的所有模式...所以不要惊讶。我展示了对我有效的解决方案,如果你想使用模式进行开发,sf2是一个糟糕的MVC。如果你有更优雅的解决方案-请使用你自己的... - user1954544

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接