I'm facing a problem with Symfony3 and forms.
I have a Parent form with an embedded Child form. From the controller, I can send data I can use in the Parent form with the $options array ($options['varA'], ...).
$form = $this->createForm(ParentEntityType::class, $objParent, array('varA'=>$varA, 'varB'=>$varB));
But what if I want to pass the varB variable (for example) to the embedded form ? What's the proper solution ?
Any help will be appreciated, thanks.
Something like this, in the first form:
$builder->add('name', MyFormType::class, [
'data' => $options['varB']
]);
But better if you share your forms codes. The main key is to pass variables by $options['key'] in buildForm() method.
this is a proper way in 2.7
in controller use this:
$itemform = $this->createForm(new SyllabusType(), $item, array('databranchid' => $branchid));
and in form use this:
$builder
->add('studentclassid', 'entity', array(
'class' =>'Schoolerp\Bundle\DBBundle\Entity\Studentclass',
'choice_label' => 'name',
'empty_value' => 'Choose an option',
'query_builder'=>function(EntityRepository $e) use ( $options ){
return $e->createQueryBuilder('u')->where('u.isactive=1')
->andWhere('u.branchid = ?1')
->setParameter(1, $options['databranchid']);
}
))
->add('sectionid', 'entity', array(
'class' =>'Schoolerp\Bundle\DBBundle\Entity\Sections',
'choice_label' => 'name',
'empty_value' => 'Choose an option',
'query_builder'=>function(EntityRepository $e) use ( $options ){
return $e->createQueryBuilder('u')->where('u.isactive=1')
->andWhere('u.branchid = ?1')
->setParameter(1, $options['databranchid']);
}
));
/**
* #param OptionsResolver $resolver
*/
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'Schoolerp\Bundle\DBBundle\Entity\Syllabus',
'databranchid' => null
));
}
and if you use 3.0 replace input type into class type.
it's just simple pass values this way:
$builder->add('userid', 'entity', array(
'class' =>'DBBundle\Entity\AdminUser',
'choice_label' => 'name',
'query_builder'=>function(EntityRepository $e) use ( $options ){
return $e->createQueryBuilder('u')->where('u.status=1')
->andWhere('u.id = ?1')
->setParameter(1, $options['users']);
},
'attr' => array('style'=>'display:none'),
'label_attr' => array('style' =>'display:none')));
Related
I'm using Symfony <4 and I have an issue with a form using an other form in a Many-To-Many relation with parameter.
You will find below my FeatureForm:
->add('tags',CollectionType::class,
array(
'entry_type' =>TagFeatureType::class,
'allow_add' => true,
'allow_delete' => true,
'data' => $datas,
'entry_options' => array(
'label' => false,
)
)
)
Now my TagFeatureType:
->add('tag', EntityType::class,
array(
'choice_label' => 'name',
'class' => 'AppBundle:Tag',
'query_builder' => function(TagRepository $tr){
return $tr->findObjectNotMine();
}
)
)
I would like to inject a parameter into findOBjectNotMine but I cannot pass parameter from controller because the TagFeatureType is created by FeatureForm. Inside the buildForm function I cannot pass any extra parameter.
I see 2 possibilites, 1st I modify default options to allow an extra option, but it's a bit disgusting. 2nd, I could use session parameter and inject session service inside the constructor... But it looks like more a workaround than a proper way...
Do you know an elegant way to inject parameter to a form from buildForm function inside FormType?
Best regards
In case you need to pass container-known parameters to custom form type, you can go the way you attempted above (obviously via parameter injection). However, if you want to pass data from controller down to form type, you can pass it via $options (last) argument (in buildForm):
FeatureForm
public function buildForm(FormBuilderInterface $builder, array $options)
// ....
$builder->add('tags', CollectionType::class, array (
'entry_type' => TagFeatureType::class,
'allow_add' => true,
'allow_delete' => true,
'data' => $datas,
'entry_options' => array(
'label' => false,
'some_custom_param' => $options['some_custom_param']
)
)
);
// ....
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array(
'data_class' => Task::class
));
$resolver->setRequired(array(
'some_custom_param'
));
}
And then, in TagFeatureType should have configured options:
TagFeatureType
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setRequired(array(
'some_custom_param'
));
}
And then finally, include it inside of buildForm:
public function buildForm(FormBuilderInterface $builder, array $options)
// ....
$someCustomParam = $options['some_custom_param'];
// ....
$builder->add('tag', EntityType::class, array(
'choice_label' => 'name',
'class' => 'AppBundle:Tag',
'query_builder' => function(TagRepository $tr) use ($someCustomParam)
{
return $tr->findObjectNotMine($someCustomParam);
}
);
// ....
}
Obvious downside of this would be a need for all the forms in path to have setRequired or setDefault.
Hope this helps...
In your TagFeatureType you can just pass in the argument via constructor injection:
class TagFeatureType extends AbstractType
{
private $tagRepository;
public function __construct(TagRepository $tagRepository)
{
$this->tagRepository = $tagRepository;
}
public function buildForm(FormBuilderInterface $builder, array $options)
{
$tr = $this->tagRepository;
// ...
->add('tag', EntityType::class,
array(
'choice_label' => 'name',
'class' => 'AppBundle:Tag',
'query_builder' => function(TagRepository $tr){
return $tr->findObjectNotMine();
}
)
)
}
}
There is a DependencyInjectionExtension form extension that will check if the form type is registered in the service container and then inject it, instead of creating a new instance. This should make sure that the tag repository exists.
i need some help.
I have a Form where i would like to either choose an existing Entity or submit a new one. So i have a Class Dolmetscher (Interpreter for languages) with title, name, surname and language. To create the Form i have a Class InterpreterType with the function
public function buildForm(FormBuilderInterface $builder, array $options) {
$builder->add('anrede', ChoiceType::class, array(
'choices' => array(
'Herr' => 'Herr',
'Frau' => 'Frau'
)
))
->add('vorname')
->add('nachname')
->add('sprache')
->add('dolmetscher', EntityType::class, array(
'class' => 'AppBundle:Dolmetscher',
'placeholder' => 'Dolmetscher wählen',
'label' => 'Dolmetscher',
'choice_value' => 'id',
'choice_label' => function ($dolmetscher) {
return $dolmetscher->getAnrede() . ' ' .
$dolmetscher->getVorname() . ' ' .
$dolmetscher->getNachname();
},
'mapped' => false,
))
->add('select', SubmitType::class, array(
'label' => 'Übernehmen',
'attr' => array(
'class' => 'btn btn-default',
'formnovalidate' => 'formnovalidate'
)
))
->add('save', SubmitType::class, array(
'label' => 'OK',
'attr' => array(
'style' => 'float: right',
'class' => 'btn btn-default'
)
))
->add('reset', SubmitType::class, array(
'label' => 'Zurücksetzen',
'attr' => array(
'style' => 'float: right; margin-right: 10px',
'class' => 'btn btn-warning',
'formnovalidate' => 'formnovalidate'
)
));
}
So i have a selection with Entities, which is working, with a 'select' Button and Form fields for a new Dolmetscher with a 'save' Button. Also a 'reset' Button
My Controller Class looks like
/**
* #Route("/u01/5", name="u1_5")
*/
public function dolmetscherAction(Request $request) {
$session = $this->get("session");
var_dump($session->get("foo"));
if (!$session->get("dolmetscher")) {
$dolmetscher = new Dolmetscher();
} else {
$dolmetscher = $session->get("dolmetscher");
}
$dolmetscherForm = $this->createForm(DolmetscherType::class, $dolmetscher);
$dolmetscherForm->handleRequest($request);
if ($dolmetscherForm->get('select')->isClicked()) {
$dolmetscher = $dolmetscherForm->get('dolmetscher');
$session->set("dolmetscher", $dolmetscher);
return $this->redirectToRoute('u1_5');
}
if ($dolmetscherForm->get('reset')->isClicked()) {
$dolmetscher = new Dolmetscher();
$session->set("dolmetscher", $dolmetscher);
return $this->redirectToRoute('u1_5');
}
if ($dolmetscherForm->get('save')->isClicked() && $dolmetscherForm->isSubmitted() && $dolmetscherForm->isValid()) {
$dolmetscher = $dolmetscherForm->getData();
$session->set("dolmetscher", $dolmetscher);
return $this->redirectToRoute('homepage');
}
return $this->render('urkunden/u01/5.html.twig', [
'form' => $dolmetscherForm->createView(),
'page_title' => 'U01'
]);
}
I want to put the Dolmetscher from the selection into $_SET for later use ,e.g. persist in DB, which works fine for a new Dolmetscher but not for my selection. I get an Exception
Serialization of 'Closure' is not allowed
I'm not sure if I'm doing this right at all (I have some OneToMany Relations and wanted to have a view for each Entity/Form and persist everything at once at the end so that i don't have only a Dolmetscher in my DB when the user quits in mid process)
I also thought it might be possible to populate the Form fields from the selection which I couldn't get to work. Can someone please help me, i would appreciate it.
This part of code is probably the origin of your problems :
if ($dolmetscherForm->get('select')->isClicked()) {
$dolmetscher = $dolmetscherForm->get('dolmetscher'); <------ this one
$session->set("dolmetscher", $dolmetscher);
return $this->redirectToRoute('u1_5');
}
you are trying to serialize a form object which contains a closure. Closure can not be serialized ( visit this link for more insights Exception: Serialization of 'Closure' is not allowed )
If you dump $dolmetscher variable you will probably get a form object not the entity you want. try to replace the line :
$dolmetscher = $dolmetscherForm->get('dolmetscher');
with :
$dolmetscher = $dolmetscherForm->get('dolmetscher')->getData();
How to get field value in form builder in Symfony.
I have 2 Dropdowns in the form
I want to should the related option in Dropdown2 based on Dropdown1 in when the Page is Opening.
Here is My Form
use Symfony\Component\Form\FormEvents;
use Symfony\Component\Form\Event\DataEvent;
use C2Educate\ToolsBundle\Entity\Students;
public function buildForm(FormBuilder $builder, array $options) {
Field 1:
$builder->add('leadSource', 'entity', array(
'label' => 'How did you hear about C2? Source ',
'class' => 'C2EducateToolsBundle:LeadSources',
'query_builder' => function($repo) {
return $repo->createQueryBuilder('p')->orderBy('p.sort_order', 'ASC');
},
'property' => 'name',
'empty_value' => 'Select'
));
$leadSource = 1;
$leadSource = 1; - it works when I assign value statically, but I want to get the value of "leadSource" and assign it to $leadSource
I want to get the leadSource and pass it to leadSourceSub query
Field 2:
$builder->addEventListener(FormEvents::PRE_SET_DATA, function (DataEvent $event) {
$form = $event->getForm();
$entity = $event->getData();
$leadSource = $entity->getLeadSourceID();
$form->add('leadSourceSub', 'C2Educate\ToolsBundle\Entity\Students', array(
'label' => ' Source Detail ',
'required' => true,
'class' => 'C2EducateToolsBundle:LeadSourceSubs',
'query_builder' => function($repo) use ($leadSource) {
return $repo->createQueryBuilder('p')
->where('p.lead_source_id =:leadSource')
->setParameter('leadSource', $leadSource)
->orderBy('p.sort_order', 'ASC');
},
'property' => 'name',
'empty_value' => 'Select'
));
});
You cannot get form data from $builder, because... it's a form builder, not a form. It doesn't contain any data yet.
To make this work you need to make use of FormEvents. In this case, you probably will need FormEvents::PRE_SET_DATA event listener.
$builder->addEventListener(FormEvents::PRE_SET_DATA, function (FormEvent $event) {
$form = $event->getForm();
// in your case it's C2EducateToolsBundle:LeadSourceSubs
$entity = $event->getData();
$leadSource = $entity->getLeadSource();
// adding this field again will override it.
$form->add('leadSourceSub', 'entity', array(
'label' => ' Source Detail ',
'required' => true,
'class' => 'C2EducateToolsBundle:LeadSourceSubs',
'query_builder' => function($repo) use ($leadSource) {
return $repo->createQueryBuilder('p')
->where('p.lead_source_id =:leadSource')
->setParameter('leadSource', $leadSource)
->orderBy('p.sort_order', 'ASC');
},
'property' => 'name',
'empty_value' => 'Select'
));
}
});
Please note that this code is not tested and may need some validation like to check if $entity is what you expect it to be in any case.
i have a problem when I would to set a default value in a select (selected="selected") in a form generated with Symfony 2 (2.8.9).
I have this code in my controller:
$news = new News();
$news->setCategory(1);
//create form
$form = $this->createForm(NewsType::class, $news);
And this in my FormType
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('category', EntityType::class,
array(
'placeholder' => 'Choise',
'class' => 'AppBundle:NewsCat',
'choice_label' => 'name'
));
}
AppBundle:NewsCat create a list of id => name (ex: 1 => 'Sport', 2 => 'Politic', etc), and I want that when I setCategory(1) it should be seen "Sport" as selected="selected" in my select.
Now i see ever "Choise".
I have tried to search everywhere on the web, I hope you can help me :)
Thanks to all
HTML code screen
You need to use data option to set selected object. My example below.
$defaultTech = $company->getDefaultTech();
if ($company->getForceDefaultTech() && $defaultTech != null) {
$builder->add('tech', HiddenType::class, ['data' => $defaultTech->getId()]);
} else {
$builder->add('tech', EntityType::class, [
'class' => 'HelpBundle\Entity\UserAccount',
'choice_label' => 'displayName',
'data' => $defaultTech,
'query_builder' => function (EntityRepository $er) use ($company) {
$qb = $er->createQueryBuilder('ua');
return $qb
->where('ua.company = :company')
->andWhere('ua.techie = 1')
->setParameter('company', $company);
},
]);
}
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)
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);
},
));
//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' =>''
));
}
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.
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.
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);
},
)
);
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...