Symfony 2 - how to pass data to formBuilder?
Asked Answered
B

6

36

I'm using entity choice list in my form. I want to use only specific entities (in example: only groups that user belongs to) So, in controller, I'm getting these groups, and trying to pass them into formBuider.

Controller:

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

so, what now? how to use it in formBuilder? how to change this line to use passed array of groups?

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

or in the other way:

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
    ;
  }
/.../
}

so how can i get object $user to use in form builder? ($user represent current logged user)

Broke answered 16/7, 2011 at 10:30 Comment(2)
i asked the same question: - #7807888 the solution of Bacteries is really good !!! :thumbsup:Periderm
If you need to execute queries, make api calls etc. to render a view, then you are doing it wrong. If this is a constraint that symfony places on the framework (there is no other way to supply arbitrary data to the form builder) then shame on them. This is the clearly defined job of the controller.Livvi
D
28

You can give the object you want to use in the __construct() method.

Eg :

$form = $this
    ->get('form.factory')
    ->create(new ApplyStepOneFormType($this->company, $this->ad), $applicant);

In your form type :

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

And then in your form type in buildForm method :

$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);
    },
));
Drews answered 29/7, 2011 at 8:43 Comment(1)
This answer nowadays is wrong. You should pass such arguments as options (defined in the configureOptions method), not in the __construct of the form Type. The Type is constructed once in the container, so you get weird behaviours if you pass parameters there and you use the Type more than once in the same request with different arguments in __construct: there, you should just autowire services.Socinus
V
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' =>'' 
       ));
     }
Victory answered 28/2, 2014 at 5:8 Comment(0)
O
4

Bacteries' solution IS NOT a good one. For example, if you declare your type as service, it is impossible to pass an object to constructor.

A perfect solution is options - just pass data as option to form builder.

Obstipation answered 14/3, 2014 at 8:42 Comment(1)
Also, his solution is going to break in 3.0 as types are constructed by FQCNFlavoprotein
A
2

If you want to use custom query, you have to set query_builder option as follows:

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();

You can find more info about query builder in Doctrine manual and about options for entity in Symfony2 manual.

Aviculture answered 16/7, 2011 at 16:48 Comment(3)
Yes, i know how to use custom query, but how can i use it when i want get groups of current logged user? i must declare a container in a form type class? ex: in controller im using$this->get('security.context')->getToken()->getUser()Broke
I'd recommend using ManyToOne or ManyToMany relationship here. It'd make things much easier.Trampoline
You can possibly create constructor in type class and just push security context variables there through that in controller.Trampoline
H
2

Bacteries' solution is a real good one. Just a note to save headache to other guy like me :)

In this part may I point out the use ($company) part. It was hidden by the frame and of course nothing works properly without it.

$builder->add('ad', 'entity', array(
   'class' => 
      '\Your\Bundle\Entity\Ad',
   'query_builder' => 
      function(\Your\Bundle\Repository\AdRepository $er) use ($company) {
            return $er->getActiveAdsQueryBuilder($company);
      },
    )
);
Hera answered 7/10, 2011 at 14:24 Comment(0)
L
0

Best way (my opinion) is give to your form entityManager and select all you need in it. But don't forget to declare empty key in setDefaults() otherwise data won't pass to your builder.

Something like this one

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
        ));
}

Apply EM as simple option...

Lewd answered 17/6, 2013 at 20:32 Comment(2)
Doesn't this defeat the purpose of an MVC application though? I thought the whole point of a framework was to obscure the data layer from the rendering layer. Like, as far as possible.Livvi
Symfony2 brokes all patterns you know... So dont be wondered. I showed solution that worked for me, sf2 is a bad mvc for developing if you want work with patterns. If you have more elegant - use yours...Lewd

© 2022 - 2024 — McMap. All rights reserved.