Symfony2 - How to customize the select option labels for the entity field type when using the query_builder? - forms

When i create an entity field in Symfony2, how i can specify the value of the select option-field generated ?
This is the snippet of my entity field:
->add('preferred_language', 'entity', array(
'mapped' => false,
'property' => 'name',
'class' => 'Common\MainBundle\Entity\Language',
'query_builder' => function(\Doctrine\ORM\EntityRepository $er) {
return $er->createQueryBuilder('u')
->orderBy('u.id', 'DESC');
}
Actually i can specify the shown value through the property and it takes automatically the id referred to the db table. Good. What can i do, instead, whether i want to change the option value?
<option value="my_value">my_property</option>

If you create an "entity" field, you create a relation form between two entities, so the default field value is the id annoted field on your entity.
You can change this behavior with a View Transformer. Check out this doc:
http://symfony.com/doc/current/cookbook/form/data_transformers.html#model-and-view-transformers

also looked for same solution and found it here: different property for entity field type in form
just set the property in the field type options and create a getter for the property that formats the string the way to output the label.

I solved it by the following way:
code in FormType must be the same:
->add('preferred_language', 'entity', array(
'mapped' => false,
'property' => 'name',
'class' => 'Common\MainBundle\Entity\Language',
'query_builder' => function(\Doctrine\ORM\EntityRepository $er) {
return $er->createQueryBuilder('u')
->orderBy('u.id', 'DESC');
}
In the controller, I get the data with DQL:
$em = $this->getDoctrine()->getManager();
$query = $em->createQuery('SELECT u FROM MyBundle:Language ORDER BY u.id DESC');
$data = $query->getResult();
I pass the data through render method:
return $this->render('MyBundle:Default:page.html.twig',
array('formulario' => $formulario->createView(),
'data' => $data));
In the twig file, I create a <select> item with id "myproject_mybundle_myformtype_preferred_language":
<select id="myproject_mybundle_myformtype_preferred_language" name="aeneagrama_adminbundle_itemcontenidotype[preferred_language]" class="form-control">
<option value="0">-- Choose an option --</option>
{% for item in data %}
<option value="{{ item.your_column }}">{{ item.name }}</option>
{% endfor %}</select>
Finally, when you get input data from the form, you can get it in the controller:
$form->get('preferred_language')->getData();

In your controller make this change,
$em = $this->getDoctrine()->getManager();
$query = $em->createQuery('SELECT u FROM MyBundle:Language u ORDER BY u.id DESC');
$data = $query->getResult();

Related

Symfony form EntityType::class - How use it to edit data in form (3.2.13)

A dropdown selection menu in a Form is available by using a EntityType form type. It is usefull if you add data. But when you try to edit data with the same FormType class, your $request data are overwritten by your EntityType.
How use the same FormType class when editing the data? (eg. editAction in controller) How pass Request $request data to FormType fields as "defaults, or selected" for element EntityType::class in FormBuilder? Is there something in $builder->add() method I can use like if(['choice_value'] !=== null ) xx : yy?
How to get something like html select selected, from Request object and pass it to xxxFormType class and bind to right EntityType::class element there.
<select>
<option value="volvo">Volvo</option>
<option value="vw">VW</option>
<option value="audi" selected>Audi</option>
</select>
I've looked at EntityType Field,
How to Dynamically Modify Forms Using Form Events and lots of StackOverflow posts, but can't find proper solution.
Controller:
public function editProdPackageAction(Request $request, ProdPackage $prodPackage)
{
$form = $this->createForm(ProdPackageFormType::class, $prodPackage);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$prodPackage = $form->getData();
$em = $this->getDoctrine()->getManager();
$em->persist($prodPackage);
$em->flush();
$this->addFlash('success', 'MSG#011E');
return $this->redirectToRoute('admin_package_list');
}
return $this->render(':admin/forms/ProdPackage:edit.html.twig',
[
'ppg' => $form->createView(),
]
);
}
Formtype:
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add(
'idCatBig',
EntityType::class,
[
'label' => '* category',
'class' => 'AppBundle\Entity\ProdCategoryBig',
'choice_value' => 'id',
'choice_label' => 'shortName',
'multiple' => false,
'expanded' => false,
]
)
->add(
'dateStart',
DateType::class,
[
'label' => '* some date',
'data' => new \DateTime('now'),
'choice_translation_domain' => true,
]
)
->add(
'dateEnd',
DateType::class,
[
'label' => '* till',
'data' => new \DateTime('now'),
]
)
->add(
'packageName',
TextType::class,
[
'label' => '* package',
'attr' => ['placeholder' => 'default Name'],
'data' => 'your default value',
]
)
This is what I do in my form, I set a "pre set data listener" to check whether or not this is an edit or a create
function buildForm(FormBuilderInterface $builder, array $options) {
$builder->add(
'dateStart',
DateType::class,
[
'label' => '* some date'
//I don't set a data field here because it is an edit
'choice_translation_domain' => true,
]
)
$builder->addEventListener(FormEvents::PRE_SET_DATA, function (FormEvent $event) {
$data = $event->getData();
$form = $event->getForm();
if (!$data || null === $data->getId()) {
//if the entity does not have an ID it means that this is a new entity not an edit. because all edits have been in the database and have an id
$builder->add(
'dateStart',
DateType::class,
['label' => '* some date',
'data' => new \DateTime('now'), //this is a create so I override my previous setting and set a default data
'choice_translation_domain' => true,]
)
}
});
}
I mainly use this trick to change form fields from required to non required between edits and creates for password fields for example,and sometimes if there is something exceedingly complicated. To change data, honestly, setting default data in constructor is cleaner as Stephan suggests
Problem
You are overriding an object by using the data option.
https://symfony.com/doc/3.2/reference/forms/types/entity.html#data:
( ! ) The data option always overrides the value taken from the domain data (object) when rendering. This means the object value is also overriden when the form edits an already persisted object, causing it to lose its persisted value when the form is submitted.
Solution 1: use the controller
So the solution is pretty simple: don't use data. Instead, set default values in your addProdPackageAction action (or whatever it is called):
public function editProdPackageAction(Request $request)
{
$prodPackage = new ProdPackage();
$prodPackage->setDateEnd(new Datetime('now'));
//example: use Request or other controller methods to modify your entity
if ($this->getUser()->hasRole('ROLE_ADMIN')) {
$prodPackage->setCreatedByAdmin(true);
}
//your form
}
Solution 2: use your entity constructor
Alternatively, you can use your entity constructor method:
class ProdPackage
{
//your attributes
private $dateEnd;
public function __construct()
{
$this->dateEnd = new Datetime('now');
}
}
Found another interesting solution
in formTypeclass at $builder
->add(
'trBegin',
DateTimeType::class,
[
'label' => 'Tourney Begins',
'required' => true,
'date_widget' => 'single_text',
'time_widget' => 'single_text',
'date_format' => 'dd.MM.yyyy',
]
)
and continuing building form add:
$builder->get('trBegin')->addModelTransformer(
new CallbackTransformer(
function ($value) {
if (!$value) {
return new \DateTime('now + 60 minutes');
}
return $value;
},
function ($value) {
return $value;
}
)
);
it sets default date at moment when form is created. This method is very usefull also for EntityType object, where you can pass id of field in form and get selected your current real choice from database (not all list from the begining) very useful when using EntityField also for editing forms
$builder->get('productCategory')
->addModelTransformer(new CallbackTransformer(
function ($id) {
if (!$id) {
return;
}
return $this->em->getRepository('AppBundle:ProductCategory')->find($id);
},
function($category) {
return $category->getId();
}
));

Trying to get property of non-object - Laravel Form

I am creating a form with a many-many relationship. I have a posts table and an activities table. There is a many to many link using pivot table. I am creating a form to add one or more activities to the posts. I am receiving an 'ErrorException' - Trying to get property of non-object. I cannot understand why this is not working.
I would be grateful for any assistance you can offer me.
My relevant code is below.
//Posts/create.blade.php
{!!Form::open(['action' => 'PostController#store','method' => 'POST', 'class'=>'form-group'])!!}
{{Form::bsText('title','',['placeholder' => 'Trip Name'])}}
{{Form::bsTextarea('body','',['placeholder' => 'Trip Description'])}}
{{Form::bsSubmit('submit')}}
{{Form::label('activities', 'Activity:') }}
<select class="form-control select2-multi" name="activities" multiple="multiple">
#foreach($activities as $activity)
<option value="{{ $activity->id }}">{{ $activity->activity_name}}
</option>
#endforeach
</select>
{!! Form::close() !!}
// PostsController
public function create()
{
$activities = Activity::all();
return view('posts.create')->withActivities($activities);
$posts = Post::all();
}
public function store(Request $request)
{
// Create a new post using the request data
// Save it to the database
$this->validate(request(), [
'title' => 'required',
'body' => 'required',
]);
$post = Post::create([
'title' =>request('title'),
'body' =>request('body'),
'user_id' => auth()->id(),
'activity_id' => id()
]);
// And then redirect to somewhere in application
return redirect()->route('posts.show', $post->id);
}
This error throw only when you have empty variable but you point in blade file to render / display for browser. Or if you retrieve records from DB then add findOrFail in query to prevent those kind of issues. Thank you.

EntityType's choice_value is removing duplicate values

Im trying to build a select html element populated with database entities. I need the labels and values in the select element to be drawn from non-default entity values, so I use the 'choice_label' and 'choice_value' options.
The problem is that any entities with duplicate 'choice_value' (territory) values are being removed (replaced?).
Here's my form builder:
$builder->add('country', EntityType::class, array(
'class' => 'AcmeCheckoutBundle:Country',
'label' => 'Country',
'query_builder' => function(EntityRepository $er) {
return $er->createQueryBuilder('c')
->orderBy('c.name', 'ASC');
},
'choice_label' => 'name',
'choice_value' => 'territory'
));
This is what I expect:
<select>
<option value="1">United Kingdom</option>
<option value="2">France</option>
<option value="2">Germany</option>
<option value="3">Brazil</option>
<option value="3">Canada</option>
</select>
This is what I'm getting:
<select>
<option value="1">United Kingdom</option>
<option value="2">Germany</option>
<option value="3">Canada</option>
</select>
If I remove 'choice_value' from the form builder I get all the records but obviously with the wrong values.
Prior symfony3 array of choices for ChoiceType has folowing structure:
$choices = [
'value1' => 'label1',
'value2' => 'label2', ...
];
So when you fill this array with your elements, elements with duplicate values are overwritten. Since symfony2.7 array of choices was reworked, now it has inversed structure:
$choices = [
'label1' => 'value1',
'label2' => 'value2', ...
];
Now you can have duplicate values, but must have unique labels. This structure was introduced in symfony2.7 but is not enabled by default and is used by default in symfony3.
To enable this structure in symfony2.7 you can use option choices_as_values (http://symfony.com/doc/2.7/reference/forms/types/choice.html#choices-as-values).
Actually this option is not mentioned in EntityType symfony documentation, but as EntityType extends ChoiceType it should work. If it is not, you can use ChoiceType instead od EntityType and provide choices manually.

Add a choice list(dropdown) from 2 different entities in a single table in Symfony 2

I am looking for a method on how to possibly create a single dropdown for my form in symfony 2 that contains the value of the field 'abbr1' and 'abbr2' from a single record in table Params.
Lets say i have a single record in my table Params.
id: 1
title: sample
abbr1: qw12
abbr2: er34
Now i want to pick abbr1 and abbr2 as the value of a single dropdown. I have created a form but i dont know how to make both of them a choice. I can only pick them as a property one at a time. Here is my code:
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add(
'desiredAbbr',
'entity',
array(
'class' => 'FooBarBundle:Params',
'property' => 'abbr1',
//'property' => 'abbr2',
)
)
->add('save','submit',array('label'=>'Submit'))
;
}
Any Suggestions are much appreciated. Thanks a lot.
Update:
The expected dropdown value would look like this in html format:
{% for par in parameters %}
<select>
<option>{{param.abbr1}}</option> {# qw12 #}
<option>{{param.abbr2}}</option> {# er34 #}
</select>
{% endfor %}
ok, I missed that you want them as value, not as label. Then you should change you form like this
$choices = $options['abbrChoices'];
$builder->add('desiredAbbr', ChoiceType::class, array(
'choices' => $choices,
));
// in configureOptions method
$resolver->setDefaults(array(
'abbrChoices' => array(),
));
In controller where you create the form
$params = $this->getDoctrine()->getRepository('AppBundle:Params')->findAll();
$choices = array();
foreach ($params as $p) {
// key will be used as option value, value as option title
$choices[$p->getAbbr1()] = $p->getAbbr1();
$choices[$p->getAbbr2()] = $p->getAbbr2();
}
$form = $this->createForm(myform::class, array(), array('abbrChoices' => $choices));
BUT. How are you going to use this choice?

Symfony Forms - entity field with query_builder, no choices_as_values?

I am trying to achieve something very simple but not sure if this is supported, possible or unexpected behaviour. I have a Symfony entity field which loads some data based on the selection of another field. The data is loaded ok but I want the option name and value to be the same. At the moment, it is populating the names ok, but I want the values to be the same as the names (the choices_as_values option in a Symfony choice field). Is that possible in an entity field.
Here is an example code:
$builder
->addEventListener(
Form\FormEvents::POST_SET_DATA,
function (Form\FormEvent $event) {
$attributeData = $event->getData();
$event->getForm()->add(
'group',
'entity',
array(
'class' => 'AppBundle:CategoryAttributeData',
'placeholder' => 'Select a data group',
'label' => 'Attribute Group',
'choice_label' => 'content',
'required' => false,
'query_builder' => function (Repository\CategoryAttributeData $repository) use ($attributeData) {
$queryBuilder = $repository->createQueryBuilder('u')
->select('u')
->where('u.type = :type')
->andWhere('u.group IS NULL')
->setParameter('type', $attributeData->getType())
;
return $queryBuilder;
}
)
);
}
)
;
The output is:
<select id="attribute_data_group" name="attribute_data[group]" class="form-control">
<option value="">Select a data group</option>
<option value="1">Cars</option>
<option value="2">Electronics</option>
<option value="3">Furniture</option>
</select>
What I am trying to achieve is:
<select id="attribute_data_group" name="attribute_data[group]" class="form-control">
<option value="">Select a data group</option>
<option value="Cars">Cars</option>
<option value="Electronics">Electronics</option>
<option value="Furniture">Furniture</option>
</select>
Since this field is populated via an event listener (because it depends on another field value) I cannot add a view transformer in here.
Any suggestions?
This is actually more complicated than it would seem on the surface. The Entity form type assumes that the "values" of the choice selector are the unique identifier for an entity, this allows the form type (and its associated transformers) to find and transform the passed values from and to the relevant entities. So the first question is - can you uniquely identify your entity by the string "Cars", or "Electronics"? If you can't, then the next question is how were you planning on converting that string into the entity?
If you can, then things are relatively easier. Effectively you need to provide a different ChoiceList implementation for the choice field type - this is effectively what the Entity type already does. I'm not familiar with the correct way to do this and I believe the method changed between Symfony 2.6 and 2.7, but I would look into classes like Symfony\Bridge\Doctrine\Form\Type\EntityType as well as the base Symfony\Component\Form\Extension\Core\Type\ChoiceType.
Short version: it's not wholly straightforward but definitely possible.
It can be done with the option 'choice_value', for example:
'choice_value' => function (?Team $team) {
return $team ? $team->getBesoccerId() : '';
}
It's 100% compatible with the 'query_builder' option. Continuing the same example:
->add('team', EntityType::class, array(
'class' => Team::class,
'label' => 'Equipo',
'query_builder' => function (EntityRepository $er) use ($lang) {
return $er->createQueryBuilder('t')
->andWhere('t.besoccerId IS NOT NULL')
->andWhere('i18n.cod_lang = :cod_lang')
->setParameter('cod_lang', $lang)
->leftJoin('t.translations', 'i18n')
->orderBy('t.sort', 'ASC');
},
'choice_label' => 'name',
'choice_value' => function (?Team $team) {
return $team ? $team->getBesoccerId() : '';
}
))
You can find more information in the documentation.