Check a radio button by default (unmapped ChoiceType field) - forms

I'm trying to have one of the options of a ChoiceType field selected by deafult using Symfony's FormBuilder.
I found a lot of similar questions, but most are about a field mapped to an entity, which is not my case here. The other answers I found involved using the "data" or the "empty_data" attribute, none of which seem to work for me.
Here's my current "add" method (in my FormBuilder):
$builder->add('type2', ChoiceType::class, [
'mapped' => false,
'label' => false,
'choices' => [
"Incoming" => ComEntry::INCOMING,
"Outgoing" => ComEntry::OUTGOING,
],
'expanded' => true,
'empty_data' => 'Incoming',
]);
(I also tried with 'empty_data' => ComEntry::INCOMING,.)
When rendering the form, no radio box is selected, what I would like is to have the first one ("Incoming") selected by default.
Thanks by advance for any reply :-)
EDIT : Here's what I used in the end (instead of 'empty_data' => 'Incoming',), because type2 is a subset of type (type is a sum of bits, type2 is a choice between the INCOMING and the OUTGOING bits).
'choice_attr' => function($choice, $key, $value) use ($options) {
// If the record is being edited and the user selected "Outgoing" at creation, check the "Outgoing" choice.
if($options['data']->getType() & ComEntry::OUTGOING and $choice == ComEntry::OUTGOING)
return ['checked' => 'checked'];
// Else, check the "Incoming" choice.
elseif($choice == ComEntry::INCOMING)
return ['checked' => 'checked'];
else
return [];
},```

You can try using the choice_attr option in its callable form:
This can be an associative array where the keys match the choice keys
and the values are the attributes for each choice, a callable or a
property path.
'choice_attr' => function($choice, $key, $value) use ($options) {
// If no value is set mark INCOMING as checked
if (empty($options['data']->type2) && ComEntry::INCOMING == $value) {
return ['checked' => 'checked'];
}
return [];
},

What you can do is : 'data' => ComEntry::INCOMING instead of the empty_data
The empty_data is useful when the form is submitted.
But this method will work only for creation. For the edition you will have to check if the form has been initialized with data.

Related

Symfony4.3 Sorting preferred choices provided by query builder in EntityType

I have a selection of events provided by query builder. All entities have to be shown in the selection field, using the future events as preferred choices. Both parts should be sorted by date (asc).
Till now it worked fine the following way:
->add('event', EntityType::class, array(
'class' => 'App:Event',
'choice_label' => 'name',
'expanded' => false,
'multiple' => false,
'required' => false,
'placeholder' => '-',
'query_builder' => function (EntityRepository $er) {
return $er->createQueryBuilder('e')
->orderBy('e.date', 'ASC');
},
'preferred_choices' => function ($event) {
if($event->getDate() > new \DateTime()){
return true;
}
return false;
}
))
Since the update to Symfony 4.3 the sort order of the preferred choices is no longer kept, as described here:
https://github.com/symfony/symfony/pull/30985
I've no array of the preferred choices, as I use a callable to decide which event is in the future. How can I sort the preferred choices now? I couldn't find any clue for that in the changing description.
Is there really no longer any other way than creating an array of events outside the formbuilder?

Symfony: how to place a specific item in first position with query_builder option?

In a form, I use an EntityType field, which allows selection of several items from entity Member. I am sending the id of a specific member to my form through the form's option (a variable named $selfId) and would like to use the query_builder function to return a list of members where this specific member would appear in first position. How could I achieve this? I'm using Symfony 3.
I'm thinking of something like this:
->add('members', EntityType::class, array(
'required' => true,
'label' => 'Members',
'class' => 'AppBundle:Member',
'multiple' => true,
'query_builder' => function (MemberRepository $er) use ($selfId) {
$qb = $er->createQueryBuilder('m');
return $qb
->orderBy('m.id = :selfId') // invented code!!!!!!!
->setParameter('selfId', $selfId)
;
}
))
;
There is an item you can add to the code above item called preferred_choices that should do what you are asking
http://symfony.com/doc/current/reference/forms/types/entity.html#preferred-choices

Symfony2 what is the best way to make this kind of form

i am making a shopping website and i got a probleme with some form. it's about the size part. I am gonna show some screenshots it's gonna be easier to understand :
what type of field is this kind of form ?
and then i would like the get this to show a list for client
i dont ask you to do the job for me but if you had some stuff (like a tutorial or some documentation about this kind of form) or some cluee i would really appriciate
Thx !
I'm not sure, but I think you are looking for Symfony's Form Types Reference.
In this case, you are probably talking about a choice field. A choice field can be rendered as a set of checkboxes / radio buttons (as in the first image), or as a <select> element (dropdown list), as in the second image, depending on wether the expanded option is set to true or false.
Radio buttons:
$builder->add('size', 'choice', array(
'choices' => array('s' => 'S', 'm' => 'M', 'l' => 'L', 'xl' => 'XL'),
'expanded' => true,
));
Dropdown list:
$builder->add('size', 'choice', array(
'choices' => array('s' => 'S', 'm' => 'M', 'l' => 'L', 'xl' => 'XL'),
'expanded' => false,
));
The default value of expanded is false, so if you don't specify it, the field will be rendered as a dropdown list.
If you have all available sizes stored in a table in your database, you might want to look at the entity field type as well. The entity type basically extends the choice type, but retrieves the available choices from the database:
$builder->add('size', 'choice', array(
'class' => 'MyWebshopBundle:Size',
'property' => 'name',
'expanded' => false,
));
This will fetch all Size entities from the database, and uses their name property in the dropdown list.
It's a choice type field
$form = $this->createFormBuilder($data)
->add('size', 'choice',
array('choices' => array(
1 => 'X',
2 => 'XL',
...
),
'data' =>'selectionnez la taille'
))
->getForm();
The option multiple can switch between radio button (false) and checkboxes ( true)
If you prefer a list like this you have to set the expanded attribute to false, true gives checkboxes or radios.
http://symfony.com/doc/current/reference/forms/types/choice.html

Validating a choice field against an array Symfony2

I am building a form class in Symfony2. In my class, I have a choice field. I built a function to return my choice array:
public function getCardTypes() {
return array('visa' => 'Visa', 'mc' => 'MasterCard', 'amex' => 'American Express');
}
Later, I add a choice field to my form with this array:
$builder->add('PaymentCCType', 'choice', array('choices' => $this->getCardTypes()));
And then in getDefaultOptions function I have a choice constraint for this field:
'PaymentCCType' => new Choice(array('choices' => $this->getCardTypes())),
I seem to be having a problem with this validator. When I submit this form, I get the following error underneath my select box: "The value you selected is not a valid choice". Of course, I am using one of the choices in my array.
What am I doing wrong?
/* edit */
I have noticed that of the 4 fields I have like this, I only get the error on 3 of them. the one where the choice is month (simple 1-12), validation works.
/* edit 2 */
the issue appears to occur when the array key does not match the value. i switched my array to array('Visa' => 'Visa', 'MasterCard' => 'MasterCard', 'American Express' => 'American Express') and now it works.
Is there any way around this? I feel like I can't be the only one with this issue. it occurs even when you have a regular (non-associative) array like array('Visa', 'MasterCard', 'American Express')
IMHO you should do it in different way, create class with ChoiceListInterface with methods:
public function getChoices()
{
return self::$choices;
}
public static function getTypeChoicesKeys()
{
return array_keys(self::$choices);
}
in form class:
$builder->add('type', 'choice',
array(
'expanded' => true,
'multiple' => false,
'choice_list' => new TypeChoices(),
'required' => true,
)
)
in validation.yml
type:
- NotNull: ~
- Choice: { callback: [TypeChoices, getTypeChoicesKeys] }
edit
In response to my issue, the Symfony team pointed out the choice validator accepts an array of possible values (not possible choices like the choice field). the easiest way to do this is to use the array_keys function:
'PaymentCCType' => new Choice(array('choices' => array_keys($this->getCardTypes()))),

Zend_Validate_Db_RecordExists against 2 fields

I usualy use Zend_Validate_Db_RecordExists to update or insert a record. This works fine with one field to check against. How to do it if you have two fields to check?
$validator = new Zend_Validate_Db_RecordExists(
array(
'table' => $this->_name,
'field' => 'id_sector,day_of_week'
)
);
if ($validator->isValid($fields_values['id_sector'],$fields_values['day_of_week'])){
//true
}
I tried it with an array and comma separated list, nothing works... Any help is welcome.
Regards
Andrea
To do this you would have to extend the Zend_Validate_Db_RecordExists class.
It doesn't currently know how to check for the existence of more than one field.
You could just use two different validator instances to check the two fields separately. This is the only work around that I can see right now besides extending it.
If you choose to extend it then you'll have to find some way of passing in all the fields to the constructor ( array seems like a good choice ), and then you'll have to dig into the method that creates the sql query. In this method you'll have to loop over the array of fields that were passed in to the constructor.
You should look into using the exclude parameter. Something like this should do what you want:
$validator = new Zend_Validate_Db_RecordExists(
array(
'table' => $this->_name,
'field' => 'id_sector',
'exclude' => array(
'field' => 'day_of_week',
'value' => $fields_values['day_of_week']
)
);
The exclude field will effectively add to the automatically generated WHERE part to create something equivalent to this:
WHERE `id_sector` = $fields_values['id_sector'] AND `day_of_week` = $fields_values['day_of_week']
Its kind of a hack in that we're using it for the opposite of what it was intended, but its working for me similar to this (I'm using it with Db_NoRecordExists).
Source: Zend_Validate_Db_NoRecordExists example
Sorry for the late reply.
The best option that worked for me is this:
// create an instance of the Zend_Validate_Db_RecordExists class
// pass in the database table name and the first field (as usual)...
$validator = new Zend_Validate_Db_RecordExists(array(
'table' => 'tablename',
'field' => 'first_field'
));
// reset the where clause used by Zend_Validate_Db_RecordExists
$validator->getSelect()->reset('where');
// set again the first field and the second field.
// :value is a named parameter that will be substituted
// by the value passed to the isValid method
$validator->getSelect()->where('first_field = ?', $first_field);
$validator->getSelect()->where('second_field = :value', $second_field);
// add your new record exist based on 2 fields validator to your element.
$element = new Zend_Form_Element_Text('element');
$element->addValidator($validator);
// add the validated element to the form.
$form->addElement($element);
I hope that will help someone :)
Although, I would strongly recommend a neater solution which would be to extend the Zend_Validate_Db_RecordExists class with the above code.
Enjoy!!
Rosario
$dbAdapter = Zend_Db_Table::getDefaultAdapter();
'validators' => array('EmailAddress', $obj= new Zend_Validate_Db_NoRecordExists(array('adapter'=>$dbAdapter,
'field'=>'email',
'table'=>'user',
'exclude'=>array('field'=>'email','value'=>$this->_options['email'], 'field'=>'is_deleted', 'value'=>'1')
))),
For those using Zend 2, If you want to check if user with given id and email exists in table users, It is possible this way.
First, you create the select object that will be use as parameter for the Zend\Validator\Db\RecordExists object
$select = new Zend\Db\Sql\Select();
$select->from('users')
->where->equalTo('id', $user_id)
->where->equalTo('email', $email);
Now, create RecordExists object and check the existence this way
$validator = new Zend\Validator\Db\RecordExists($select);
$validator->setAdapter($dbAdapter);
if ($validator->isValid($username)) {
echo 'This user is valid';
} else {
//get and display errors
$messages = $validator->getMessages();
foreach ($messages as $message) {
echo "$message\n";
}
}
This sample is from ZF2 official doc
You can use the 'exclude' in this parameter pass the second clause that you want to filter through.
$clause = 'table.field2 = value';
$validator = new Zend_Validate_Db_RecordExists(
array(
'table' => 'table',
'field' => 'field1',
'exclude' => $clause
)
);
if ($validator->isValid('value') {
true;
}
I am using zend framework v.3 and validation via InputFilter(), it uses same validation rules as zend framework 2.
In my case I need to check, if location exists in db (by 'id' field) and has needed company's id ('company_id' field).
I implemented it in next way:
$clause = new Operator('company_id', Operator::OP_EQ, $companyId);
$inputFilter->add([
'name' => 'location_id',
'required' => false,
'filters' => [
['name' => 'StringTrim'],
['name' => 'ToInt'],
],
'validators' => [
[
'name' => 'Int',
],
[
'name' => 'dbRecordExists',
'options' => [
'adapter' => $dbAdapterCore,
'table' => 'locations',
'field' => 'id',
'exclude' => $clause,
'messages' => [
'noRecordFound' => "Location does not exist.",
],
]
],
],
]);
In this case validation will pass, only if 'locations' table has item with columns id == $value and company_id == $companyId, like next:
select * from location where id = ? AND company_id = ?