How to customize EntityType option text? - forms

I would like to display selection with options from DB. In this case, I am using EntityType with query_builder:
$builder
->add('internships', EntityType::class, array(
'class' => 'IndexBundle\Entity\Internship',
'property' => 'id',
'empty_value' => 'Choose',
'query_builder' => function (EntityRepository $er) use ($trainee) {
return $er->createQueryBuilder('i')
->where('i.trainee = :trainee')
->andWhere('i.state = :state')
->setParameter('trainee', $trainee)
->setParameter('state', 'unverified');
},
'constraints' => array(
new NotBlank(array(
'message' => 'choice.not.blank'
))
)
))
Now all is fine. I get select element with necessary options within with text of id value.
<select>
<option value="id">id</option>
...
</select>
How do I customize it?
For example I would like it to be combination of id and type table columns:
<select>
<option value="id">#id (type)</option>
...
</select>

You can use the choice_label option to customize your options.
You can either pass a function to retrieve the text you want, or you can add a getter to your entity if you reuse it at another place.
With a function:
$builder
->add('internships', EntityType::class, array(
'class' => 'IndexBundle\Entity\Internship',
'property' => 'id',
'empty_value' => 'Choose',
'query_builder' => function (EntityRepository $er) use ($trainee) {
return $er->createQueryBuilder('i')
->where('i.trainee = :trainee')
->andWhere('i.state = :state')
->setParameter('trainee', $trainee)
->setParameter('state', 'unverified');
},
'choice_label' => function ($internship) {
return '#'.$internship->getId().' ('.$internship->getType().')';
},
'constraints' => array(
new NotBlank(array(
'message' => 'choice.not.blank'
))
)
))
With a getter:
$builder
->add('internships', EntityType::class, array(
'class' => 'IndexBundle\Entity\Internship',
'property' => 'id',
'empty_value' => 'Choose',
'query_builder' => function (EntityRepository $er) use ($trainee) {
return $er->createQueryBuilder('i')
->where('i.trainee = :trainee')
->andWhere('i.state = :state')
->setParameter('trainee', $trainee)
->setParameter('state', 'unverified');
},
'choice_label' => 'idAndType',
'constraints' => array(
new NotBlank(array(
'message' => 'choice.not.blank'
))
)
))
Internship.php:
Class Internship
{
//...
public function getIdAndType()
{
return '#'.$this->id.' ('.$this->type.')';
}
}
Note:
For older Symfony versions (<= 2.6), this option was named property and use something supported by the PropertyAccessor component, so you can't use a function, only a getter for it.

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

Synfony 2.8 one of the two fields must be filled

I have this form and I want to checked if one of the two fields (numberPlate or expirationDate) is filled.
This is my buildForm:
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('type', ChoiceType::class, array(
'choices_as_values' => true,
'required' => true,
'label' => 'Tipo Veicolo',
'empty_data' => '',
'empty_value' => '',
'attr' => array('class'=> 'form-control select2'),
'choices' => array('Auto' => 'Auto', 'Moto' => 'Moto', 'Camper' => 'Camper' ,'Barca' => 'Barca')
))
->add('numberPlate', TextType::class, array(
'label' => 'Targa',
'required' => false,
'attr' => array(
'class'=> 'form-control',
'minlength' => 5,
'maxlength' => 7
)
))
->add('expirationDate', DateTimeType::class, array(
'label' => 'Scadenza',
'widget' => 'single_text',
'input' => 'datetime',
'format' => 'dd/MM/yyyy',
'attr' => array('class'=> 'form-control')
))
;
}
You can ensure one of the fields are not empty, by adding a callback constraint to your entity.
namespace App\Entity;
use Symfony\Component\Validator\Constraints as Assert;
use Symfony\Component\Validator\Context\ExecutionContextInterface;
class YourModel
{
/**
* #Assert\Callback
*/
public function validate(ExecutionContextInterface $context)
{
if (!$this->numberPlate && !$this->expirationDate) {
$context->buildViolation('Targa or Scadenza is required')
//optionally display the error at the numberPlate field, omit to display at the top of the form errors
->atPath('numberPlate')
->addViolation()
;
}
}
}
Then update your Scadenza field as not required.
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
//...
->add('expirationDate', DateTimeType::class, array(
'label' => 'Scadenza',
'required' => false,
'widget' => 'single_text',
'input' => 'datetime',
'format' => 'dd/MM/yyyy',
'attr' => array('class'=> 'form-control')
))
;
}
When the form is submitted it will execute the YourModel::validate method, and if the numberPlate and expirationDate are empty, it will fail $form->isValid().
Be sure to clear your cache after making the changes, to refresh the annotations.
NOTE: This will apply to any/all forms this entity model is used in,
to separate the validation you will need to implement validation groups

Radio button: input was not found in the haystack?

Whenever I submit the form I get this message:
The input was not found in the haystack.
This is for the shipping-method element (radio button). Can't figure out what it means, the POST data for that element is not null.
public function getInputFilter()
{
if (!$this->inputFilter) {
$inputFilter = new InputFilter();
// Some other basic filters
$inputFilter->add(array(
'name' => 'shipping-method',
'required' => true,
'filters' => array(
array('name' => 'StripTags'),
array('name' => 'StringTrim')
),
'validators' => array(
array(
'name' => 'StringLength',
'options' => array(
'encoding' => 'UTF-8',
'max' => 20,
),
),
array(
'name' => 'Db\RecordExists',
'options' => array(
'table' => 'shipping',
'field' => 'shipping_method',
'adapter' => $this->dbAdapter
)
),
),
));
$inputFilter->get('shipping-address-2')->setRequired(false);
$inputFilter->get('shipping-address-3')->setRequired(false);
$this->inputFilter = $inputFilter;
}
return $this->inputFilter;
}
I only keep finding solutions for <select>.
Here's the sample POST data:
object(Zend\Stdlib\Parameters)#143 (1) {
["storage":"ArrayObject":private] => array(9) {
["shipping-name"] => string(4) "TEST"
["shipping-address-1"] => string(4) "test"
["shipping-address-2"] => string(0) ""
["shipping-address-3"] => string(0) ""
["shipping-city"] => string(4) "TEST"
["shipping-state"] => string(4) "TEST"
["shipping-country"] => string(4) "TEST"
["shipping-method"] => string(6) "Ground"
["submit-cart-shipping"] => string(0) ""
}
}
UPDATE:
form.phtml
<div class="form-group">
<?= $this->formRow($form->get('shipping-method')); ?>
<?= $this->formRadio($form->get('shipping-method')
->setValueOptions(array(
'Ground' => 'Ground',
'Expedited' => 'Expedited'))
->setDisableInArrayValidator(true)); ?>
</div>
ShippingForm.php
$this->add(array(
'name' => 'shipping-method',
'type' => 'Zend\Form\Element\Radio',
'options' => array(
'label' => 'Shipping Method',
'label_attributes' => array(
'class' => 'lbl-shipping-method'
),
)
));
The problem lies with when you use the setValueOptions() and the setDisableInArrayValidator(). You should do this earlier within your code as it is never set before validating your form and so the inputfilter still contain the defaults as the InArray validator. As after validation, which checks the inputfilter, you set different options for the shipping_methods.
You should move the setValueOptions() and the setDisableInArrayValidator() before the $form->isValid(). Either by setting the right options within the form itsself or doing this in the controller. Best way is to keep all of the options in one place and doing it inside the form class.
$this->add([
'name' => 'shipping-method',
'type' => 'Zend\Form\Element\Radio',
'options' => [
'value_options' => [
'Ground' => 'Ground',
'Expedited' => 'Expedited'
],
'disable_inarray_validator' => true,
'label' => 'Shipping Method',
'label_attributes' => [
'class' => 'lbl-shipping-method',
],
],
]);
Another small detail you might want to change is setting the value options. They are now hardcoded but your inputfilter is checking against database records whether they exist or not. Populate the value options with the database records. If the code still contains old methods but the database has a few new ones, they are not in sync.
class ShippingForm extends Form
{
private $dbAdapter;
public function __construct(AdapterInterface $dbAdapter, $name = 'shipping-form', $options = [])
{
parent::__construct($name, $options)
// inject the databaseAdapter into your form
$this->dbAdapter = $dbAdapter;
}
public function init()
{
// adding form elements to the form
// we use the init method to add form elements as from this point
// we also have access to custom form elements which the constructor doesn't
$this->add([
'name' => 'shipping-method',
'type' => 'Zend\Form\Element\Radio',
'options' => [
'value_options' => $this->getDbValueOptions(),
'disable_inarray_validator' => true,
'label' => 'Shipping Method',
'label_attributes' => [
'class' => 'lbl-shipping-method',
],
],
]);
}
private function getDbValueOptions()
{
$statement = $this->dbAdapter->query('SELECT shipping_method FROM shipping');
$rows = $statement->execute();
$valueOptions = [];
foreach ($rows as $row) {
$valueOptions[$row['shipping_method']] = $row['shipping_method'];
}
return $valueOptions;
}
}
Just had this happen yesterday.
The select and multi select ZF2+ elements have a built in in_array validator.
Remember filters occur before validators.
You may be doing too much here -- it is very rare to need to filter or add validators ot select and multi select form elements in ZF2 forms. The built in element validator is robust, ZF does a lot of work for us.
Try removing both filter and validator for the element, such as:
$inputFilter->add(array(
'name' => 'shipping-method',
'required' => true,
));
There is another edge case that I have seen: changing the select element's valueOptions somewhere in the controller (or view) resulting in different valueOptions used in view vs form validation (in our case it was replacing the element with a new one before validation).
I think your problem lies in the fact you are adding your value options after the InArray validator has been set, hence the validator has no haystack.
Try this
$this->add(array(
'name' => 'shipping-method',
'type' => 'Zend\Form\Element\Radio',
'options' => array(
'label' => 'Shipping Method',
'label_attributes' => array(
'class' => 'lbl-shipping-method'
),
'value_options' => array(
'Ground' => 'Ground',
'Expedited' => 'Expedited'
),
'disable_inarray_validator' => TRUE,
)
));
and remove setValueOptions and setDisableInArrayValidator from your view.
Hope this works.

Symfony give class to option entitytype element

i have an entity type with field (nome, id,id_Categoria,id_tipo)
id_tipo has value 1,2,or 3
$builder->add('idTipologiaEsame', EntityType::class, array(
'placeholder' => 'tipologia esame',
'label' => false,
'mapped' => false,
'required' => false,
'class' => 'AppBundle:Nome_esame',
'choice_label' => 'nome',
'group_by' => 'idCategoriaEsame.tipo',
))
My goal is give a class to option value in select if id_tipo is 1 or 2.
like this:
<select>
<option class="ruminanti">val 1</option> ->id_tipo=1
<option class="pippo">val 2</option> ->id_tipo=2
<option class="ruminanti">val 3</option> ->id_tipo=1
</select>
it is possible??
thank's to Ramazan Apaydın i add this
$builder->add('idTipologiaEsame', EntityType::class, array(
'placeholder' => 'tipologia esame',
'label' => false,
'mapped' => false,
'required' => false,
'class' => 'AppBundle:Nome_esame',
'choice_label' => 'nome',
'group_by' => 'idCategoriaEsame.tipo',
'choice_attr' => function($val, $key, $index) {
// adds a class like attending_yes, attending_no, etc
if($index){ ----> i want id_tipo =1
return ['class' => '.ruminati';}else{
return ['class' => '.suini';
}
},
but i want add condition id_tipo=1
EntityType is a ChoiceType element. An example is available in the Symfony documentation.
https://symfony.com/doc/current/reference/forms/types/choice.html#choice-attr

Symfony2: Pass Parameter to Form entity object for query_builder

In My form i use this code
$form->add('user', 'entity',
array(
'label' => 'User Name',
'class' => 'DotArtBundle:User',
'property' => 'name',
'query_builder' => function(EntityRepository $er){
return $er->createQueryBuilder('u')->where('u.type = 1');
}
)
);
I want
if user role is ROLE_ADMIN run this code and show all user (This code do this)
if user role is ROLE_USER this code only show authenticated user in list
'query_builder' => function(EntityRepository $er){
return $er->createQueryBuilder('u')->where('u.type = 1 and u.id = ' . $this->getUser()->getId());
}
Error
I check this code and return error:
$where = 'u.id = '.$userid;
$form = $this->createFormBuilder($poduct)
->add('user', 'entity',
array(
'label' => 'نانم کاربری',
'class' => 'DotArtBundle:User',
'property' => 'name',
'query_builder' => function(EntityRepository $er){
return $er->createQueryBuilder('u')->where($where);
}
)
)
Notice: Undefined variable: where in C:\xampp\htdocs\ArtGirl\src\Dot\ArtBundle\Controller\ProductController.php line 38
Solution:
$where = '';
$userid = $this->getUser()->getId();
if (!$this->get('security.context')->isGranted('ROLE_ADMIN')){
$where = ' and u.id = ' . $userid;
}
$form->add('user', 'entity',
array(
'label' => 'نانم کاربری',
'class' => 'DotArtBundle:User',
'property' => 'name',
'query_builder' => function(EntityRepository $er) use ($where){
return $er->createQueryBuilder('u')->where('u.type = 1 '.$where);
}
)
)