EntityType's choice_value is removing duplicate values - forms

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.

Related

Empty option in a form query symfony 3.4

I must display an entity in a query_builder form
here is my code in the form type:
$builder->add('dispositif', EntityType::class, array(
'class' => 'LeaPrestaBundle:EgwDispositif',
'label' => 'nomDispositif',
'required' => true,
'empty_data' => null,
'query_builder' => function( $er)
{
return $er->createQueryBuilder('d')
->where('d.isActive = :isActive')
->setParameter('isActive', 1 )
->orderBy('d.nomDispositif','ASC');
},
));
The problem is that the option is empty :
<select id="egw_presta_dispositif" name="egw_presta[dispositif]">
<option value="52"></option>
<option value="55"></option>
<option value="62"></option>
<option value="58"></option>
</select>
For example, aside the value 52, there should have a label for "dispositif" (name of dispositif).
Does it coming from the entity ?
Thanks in advance for your help!
Try adding a 'choice_label' property with the EgwDispositif field containing what you want to display:
$builder->add('dispositif', EntityType::class, array(
'class' => 'LeaPrestaBundle:EgwDispositif',
/** label will be displayed next to your form field unless it's a translation key or else **/
'label' => 'Nom du dispositif',
'required' => true,
'empty_data' => null,
/** any field containing what you want to display as option label **/
'choice_label' => 'nomDispositif',
'query_builder' => function( $er)
{
return $er->createQueryBuilder('d')
->where('d.isActive = :isActive')
->setParameter('isActive', 1 )
->orderBy('d.nomDispositif','ASC');
},
));
It seems like you were confusing the option 'label' of the form field property with the option 'choice_label' . You probably want your label to be something user will read (bu maybe not, it's up to you)
take a look here : https://symfony.com/doc/current/reference/forms/types/entity.html

How to set a class attribute to a Symfony form input with an attribut from entity linked

I have in my form a "beds" attribute, an entity linked to another "bedroom".
I would like for each input to add a class with the id of the linked entity "bedroom".
$form->add('beds', EntityType::class, array(
'class' => 'DamiasResaBundle:Bed',
'query_builder' => function (EntityRepository $er) {
return $er->createQueryBuilder('b')
->orderBy('b.id', 'ASC');
},
'choice_label' => 'id',
'label' => 'lits ',
'multiple' => true,
'expanded' =>true,
'attr' => array(
'class' => function ($bed) {
return $bed->getBedroom()->getId();
}
),
))
I have two problems:
'attr' => array('class'=>'test) return a class attribut in the div containing the input, not a class attribut in the input.
This previous code does not work and returns:
An exception has been thrown during the rendering of a template ("Catchable Fatal Error: Object of class Closure could not be converted to string") in form_div_layout.html.twig at line 358.
Thank you for your help
I see you are using checkboxes.
Your code seems ok, and since you use query_builder, the values should be a Bed Entity. Note that attr is not mentioned in the EntityType documentation, and I think you need to use choice_attr instead.
Can you try this. I'm not sure if it will work or not:
$form->add('beds', EntityType::class, array(
'class' => 'DamiasResaBundle:Bed',
'query_builder' => function (EntityRepository $er) {
return $er->createQueryBuilder('b')
->orderBy('b.id', 'ASC');
},
'choice_label' => 'id',
'label' => 'lits ',
'multiple' => true,
'expanded' =>true,
'choice_attr' => function ($val) {
return ['class' => $val->getId()];
},
))
Let us know the results.
You need to customize form rendering
Previous code doesn't work because you're trying to pass Closure object instead of string value. attr array is used as field attributes, so it must contain only string values (or objects with __toString() method).
For EntityType it would rather look like this:
$form->add('beds', EntityType::class, array(
'class' => 'DamiasResaBundle:Bed',
'query_builder' => function (EntityRepository $er) {
return $er->createQueryBuilder('b')
->orderBy('b.id', 'ASC');
},
'choice_label' => 'id',
'label' => 'lits ',
'multiple' => true,
'expanded' =>true,
'choice_attr' => function (Bed $bed, $key, $index) {
return ['class' => $bed->getBedroom()->getId();];
},
))
Since choice_attr seems not to be working anymore, I am writing another solution. I wasn't able to set attribute (exactly "min") directly from formBuilder. I managed to add it with help of js. I simply searched element by ID given by formBuilder and added atribute.
Inspect your form in browser element inspector and find id.
<div id="form_deadLine">
<input type="date" id="form_deadLine_date" name="form[deadLine][date]" required="required" value="2020-02-20"/>
</div>
Id you wanna look for in my case is form_deadLine_date.
Then you wanna connect .js file to you twig template and write there simple script.
const form = document.getElementById('form_deadLine_date');
if(form){
form.setAttribute("min", "2020-01-02")
}
then my code looks like:
<div id="form_deadLine">
<input type="date" id="form_deadLine_date" name="form[deadLine][date]" required="required" value="2020-02-20"/>
</div>

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.

Drupal 7 - Construct clean URL from form post

I am creating a custom module in Drupal 7 that is a job search. I am wanting to make it so you can specify a clean URL to perform the search like so:
www.example.com/job-board/cardiology/california
Where "cardiology" is the "specialty" variable and "california" is the "location" variable.
now I know how to do this as far as mapping the variables in my hook_menu and accessing the variables. The problem is how do I create a search form that creates the clean url when you submit it? In other words if I had this:
<form method="get" action="job-board">
<select name="specialty">
<option value="cardiology">Cardiology</option>
<option value="some_other_value">Some Other Value</option>
</select>
<select name="location">
<option value="california">California</option>
<option value="some_other_state">Some Other State</option>
</select>
<input type="submit">
</form>
and I submit it, it will go to www.example.com/job-board?specialty=cardiology&location=california instead of www.example.com/cardiology/california. How can I make the form construct a clean URL?
You should create that form using Drupal's Form API and assign a custom submit callback to it.
In that submit callback, you can perform validation and if everything is OK, redirect the user to the appropriate URL.
See the source code of Examples modules, specifically one related to Form API in order to learn more about it.
In short, here's what you would do:
/**
* Sample form.
*/
function MYMODULE_sample_form() {
$form['specialty'] = array(
'#title' => t('Specialty'),
'#type' => 'textfield',
'#required' => TRUE,
);
$form['state'] = array(
'#title' => t('State'),
'#type' => 'select',
'#options' => array(
'california' => t('California')
),
);
$form['actions'] = array('#type' => 'actions');
$form['actions']['submit'] = array('#type' => 'submit', '#value' => t('Submit the form'));
return $form;
}
/**
* Sample form submit processing.
*/
function MYMODULE_sample_form_submit($form, &$form_state) {
$specialty = $form_state['values']['specialty'];
$state = $form_state['values']['state'];
drupal_goto($specialty . '/ ' . $state);
}

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

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