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)

Rixius
  • 2,223
  • 3
  • 24
  • 33
jacobmaster
  • 740
  • 2
  • 7
  • 14
  • 2
    i asked the same question: - http://stackoverflow.com/questions/7807388/passing-data-from-controller-to-type-symfony2 the solution of Bacteries is really good !!! :thumbsup: – xeon Oct 19 '11 at 14:39
  • 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. – eggmatters Sep 20 '16 at 18:36

6 Answers6

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);
    },
));
Czechnology
  • 14,832
  • 10
  • 62
  • 88
Bacteries
  • 593
  • 4
  • 13
  • 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. – ste Jul 18 '19 at 21:02
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' =>'' 
       ));
     }
user3335780
  • 121
  • 1
  • 5
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.

Bohdan Yurov
  • 365
  • 5
  • 9
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.

Ondrej Slinták
  • 31,386
  • 20
  • 94
  • 126
  • 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()` – jacobmaster Jul 17 '11 at 20:50
  • 1
    I'd recommend using ManyToOne or ManyToMany relationship here. It'd make things much easier. – Ondrej Slinták Jul 18 '11 at 07:18
  • You can possibly create constructor in type class and just push security context variables there through that in controller. – Ondrej Slinták Jul 20 '11 at 09:10
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);
      },
    )
);
Dan D.
  • 73,243
  • 15
  • 104
  • 123
FGREZE
  • 31
  • 1
  • 4
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...

user1954544
  • 1,619
  • 5
  • 26
  • 53
  • 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. – eggmatters Sep 20 '16 at 18:32
  • 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... – user1954544 Sep 27 '16 at 14:39