In my code I am reusing a list-find operation with custom keyField and valueField like this:
->find('list', [
'keyField' => 'key',
'valueField' => 'value'
])
I would like to define a custom list-find method that sets the keyField and valueField, so I don't have to repeat myself. Also it should be chainable with additional custom-find methods.
Edit: Simple and clear solution by calling findList inside the custom finder:
public function findCustomList(Query $query, array $options)
{
return $this->findList($query, [
'keyField' => 'key',
'valueField' => 'value',
]);
}
First Answer:
It is possible to use the formatResults-method of the query-Object to register a formatter that will format the results into the desired list:
public function findCustomList(Query $query, array $options)
{
$query->formatResults(function ($results) {
/** #var \Cake\Collection\CollectionInterface $results */
$formatedResults = [];
foreach ($results as $key => $result) {
$formatedResults[$result->key] = $result->value;
}
return new Collection($formatedResults);
});
return $query;
}
i'm creating a application in which i need to populate data in select element from a db table.
i need to populate user roles from db
my form code is
$this->pass2->addValidator('Identical', false, array('token' => 'pass1'));
$this->addElement('select', 'userrole', array(
'class' => 'form-control',
'required' => true,
'multiOptions' =>
));
what should i do with multi options ?,
is there any way to load data from db in element using controller ,please helpme
thanks
What I have done in the past is to pass the db-adapter (or a model that knows how to do the required db query) to the form as a constructor parameter.
Something like this:
class Application_Form_MyForm extends Zend_Form
{
protected $db;
public function __construct($db)
{
$this->db = $db;
// Don't forget to call the parent __construct. Ultimately
// it is the parent __construct() that calls your init()
// method that adds your elements
parent::__construct();
}
public function init()
{
// Create your form elements
// $this->addElement('text', 'my_text_field'); // etc
// Now your select field...
$this->addElement('select', 'my_select', array(
'multiOptions' => $this->buildMultiOptions(),
'validators' => array(
// blah, blah
),
);
}
protected function buildMultiOptions()
{
$select = $this->db->select()
->from('my_table', array(
'my_value_column',
'my_display_column'
))
->order(array(
'my_display_column ASC',
));
$results = $this->db->query($select)->fetchAll();
$return = array();
foreach ($results as $row) {
$return[$row['my_value_column']] = $row['my_display_column'];
}
return $return;
}
}
Then in the controller action, when you instantiate your form, you grab the db-adapter and pass it in as a constructor parameter:
$db = $this->getInvokeArg('bootstrap')->getResource('db');
$form = new Application_Form_MyForm($db);
// Then process your form as usual
on case with is necessary populate options outside form class.
$form->getElement( 'ele_name' )
->setConfig(new Zend_Config( array(
'multiOptions' => array('option1','option2') )
)));
I have a form that collects data about an Article, and I want to save that data, as well as for a model called Abstract, where an Article hasMany Abstracts. My models look like this:
namespace App\Model\Table;
use Cake\ORM\Table;
use Cake\Validation\Validator;
class AbstractsTable extends Table
{
public function initialize(array $config)
{
$this->belongsTo('Articles');
}
public function validationDefault(Validator $validator)
{
$validator
->notEmpty('body');
return $validator;
}
}
And
namespace App\Model\Table;
use Cake\ORM\Table;
use Cake\Validation\Validator;
class ArticlesTable extends Table
{
public function initialize(array $config)
{
$this->addBehavior('Timestamp');
$this->hasMany('Abstracts');
}
public function validationDefault(Validator $validator)
{
$validator ->notEmpty('category')
return $validator;
}
}
My input form has a field named 'abstracts.body', and in my ArticlesController I have this function:
public function add()
{
$data = $this->request->data;
$article = $this->Articles->newEntity($data, [
'associated' => ['Abstracts']
]);
if ($this->request->is('post')) {
$article->user_id = $this->Auth->user('id');
$data['abstracts']['user_id'] = $article->user_id;
$data['abstracts']['approved'] = 0;
$article = $this->Articles->patchEntity($article, $data, [
'associated' => ['Abstracts']
]);
if ($this->Articles->save($article, [ 'validate' => false,
'associated' => ['Abstracts']
]) )
{
$this->Flash->success(__('Your article has been saved.'));
return $this->redirect(['action' => 'index']);
}
$this->Flash->error(__('Unable to add your article.'));
}
$this->set('article', $article);
}
My Abstracts table is pretty straightforward:
CREATE TABLE 'abstracts' ('id' INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, 'article_id' INTEGER , 'user_id' INTEGER , 'body' TEXT, 'approved' BOOLEAN )
From debugging I can see that I have the correct 'abstracts' array within my $data (in add()), but it doesn't appear to ever try to save it to the database. Can someone please point out my error? Thanks!
Got it.
I started going wrong here:
My input form has a field named 'abstracts.body'
Because it's a hasMany relationship, I need to have that input be 'abstracts.0.body'
Then the rest of LeWestopher's answer will work-- adding an index to the fields I want to fill in from the Controller, so $data[abstracts][0]['user_id'] => ... and so on. Thanks!
You're post processing your $data['abstracts'] array incorrectly resulting in the association not saving. $data['abstracts'] is expected to be an array of Abstracts. Your issue lies here:
$data['abstracts']['user_id'] = $article->user_id;
$data['abstracts']['approved'] = 0;
You should be able to fix this pretty easily by changing this to:
foreach($data['abstracts'] as $index => $abstract) {
$abstract['user_id'] = $article->user_id;
$abstract['approved'] = 0;
$data['abstracts'][$index] = $abstract;
}
This should correctly iterate over your array of abstracts, set the user_id and approved keys appropriately and then it should save correctly.
CakePHP 3.x Documentation on Saving Associations
EDIT: Very interesting issue indeed. Try it without using patchEntity, and use newEntity by itself instead:
public function add()
{
if ($this->request->is('post')) {
$data = $this->request->data;
// Post process abstracts objects
foreach($data['abstracts'] as $index => $abstract) {
$abstract['user_id'] = $article->user_id;
$abstract['approved'] = 0;
$data['abstracts'][$index] = $abstract;
}
// Build newEntity
$article = $this->Articles->newEntity($data, [
'associated' => ['Abstracts']
]);
// Save our entity with associations
if ($this->Articles->save($article, [
'validate' => false,
'associated' => ['Abstracts']
])) {
$this->Flash->success(__('Your article has been saved.'));
return $this->redirect(['action' => 'index']);
}
// On save fail
$this->Flash->error(__('Unable to add your article.'));
$this->set('article', $article);
}
}
EDIT 2: Your issue looks like it's definitely in your form helper. Your current form helper input creates an $data array that looks like this:
$data = [
'abstracts' => [
'body' => 'example text'
],
'category' => 'Science'
];
Which SHOULD look like:
$data = [
'abstracts' => [
['body' => 'example text'],
['body' => 'Im your second abstract'],
['body' => 'Abstract three!']
],
'category' => 'Science'
];
The issue lies in:
abstracts.body
Which should read as (in array dot notation):
// abstracts.0.body
echo $this->Form->input('abstracts.0.body', [
'label' => 'summary of article',
'maxlength' =>'440',
'rows' => '7'
]);
I believe that should be the last issue you run into.
I have not found any easy way to accomplish to simply check a Checkbox by default. That can not be that hard, so what am i missing?
You can also just set the attr attribute in the form builder buildForm method:
$builder->add('isPublic', CheckboxType::class, array(
'attr' => array('checked' => 'checked'),
));
In Symfony >= 2.3 "property_path" became "mapped".
So:
$builder->add('checkboxName', 'checkbox', array('mapped' => false,
'label' => 'customLabel',
'data' => true, // Default checked
));
You would simply set the value in your model or entity to true and than pass it to the FormBuilder then it should be checked.
If you have a look at the first example in the documentation:
A new task is created, then setTask is executed and this task is added to the FormBuilder. If you do the same thing with your checkbox
$object->setCheckboxValue(true);
and pass the object you should see the checkbox checked.
If it's not working as expected, please get back with some sample code reproducing the error.
Setting the 'data' option works for me. I'm creating a non entity based form:
$builder->add('isRated','checkbox', array(
'data' => true
));
In TWIG
If you wish to do this in the template directly:
{{ form_widget(form.fieldName, { 'attr': {'checked': 'checked'} }) }}
Use the FormBuilder::setData() method :
$builder->add('fieldName', 'checkbox', array('property_path' => false));
$builder->get('fieldName')->setData( true );
"property_path" to false cause this is a non-entity field (Otherwise you should set the default value to true using your entity setter).
Checkbox will be checked by default.
To complete a previous answer, with a multiple field you can do that to check all choices :
'choice_attr' => function ($val, $key, $index) {
return ['checked' => true];
}
https://symfony.com/doc/3.3/reference/forms/types/choice.html#choice-attr
You should make changes to temporary object where entity is stored before displaying it on form. Something like next:
<?php
namespace KPI\AnnouncementsBundle\Form;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
class AnnouncementType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
// ...
if ($options['data']->getDisplayed() === null) {
$options['data']->setDisplayed(true);
}
// ...
$builder
->add('displayed', 'checkbox', array(
'required' => false
));
}
}
As per documentation:
http://symfony.com/doc/current/reference/forms/types/checkbox.html#value
To make a checkbox or radio button checked by default, use the data option.
UserBundle\Entity\User
let's assume that you have an entity called ( User ) and it has a member named isActive, You can set the checkbox to be checked by default by setting up isActive to true:
$user = new User();
// This will set the checkbox to be checked by default
$user->setIsActive(true);
// Create the user data entry form
$form = $this->createForm(new UserType(), $user);
I had the same problem as you and here is the only solution I found:
$builder->addEventListener(FormEvents::PRE_SET_DATA, function (FormEvent $event) {
$entity= $event->getData();
$form = $event->getForm();
$form->add('active', CheckboxType::class, [
'data' => is_null($entity) ? true : $entity->isActive(),
]);
});
This works as well, but aware of persistent "checked" state
$builder->add('isPublic', 'checkbox', array(
'empty_data' => 'on',
));
This is how you can define the default values for multiple and expanded checkbox fields. Tested in Symfony4, but it has to work with Symfony 2.8 and above.
if you want to active the 1st and the 2nd checkboxes by default
class MyFormType1 extends AbstractType
{
CONST FIELD_CHOICES = [
'Option 1' => 'option_1',
'Option 2' => 'option_2',
'Option 3' => 'option_3',
'Option 4' => 'option_4',
'Option 5' => 'option_5',
];
public function buildForm(FormBuilderInterface $builder, array $options)
{
$this->addSettingsField('my_checkbox_field', ChoiceType::class, [
'label' => 'My multiple checkbox field',
'choices' => self::FIELD_CHOICES,
'expanded' => true,
'multiple' => true,
'data' => empty($builder->getData()) ? ['option_1', 'option_2'] : $builder->getData(),
]);
}
}
if you want to active every checkbox by default
class MyFormType2 extends AbstractType
{
CONST FIELD_CHOICES = [
'Option 1' => 'option_1',
'Option 2' => 'option_2',
'Option 3' => 'option_3',
'Option 4' => 'option_4',
'Option 5' => 'option_5',
];
public function buildForm(FormBuilderInterface $builder, array $options)
{
$this->addSettingsField('my_checkbox_field', ChoiceType::class, [
'label' => 'My multiple checkbox field',
'choices' => self::FIELD_CHOICES,
'expanded' => true,
'multiple' => true,
'data' => empty($builder->getData()) ? array_values(self::FIELD_CHOICES) : $builder->getData(),
]);
}
}
The only watertight solution for me in Symfony 4, 2022 is:
OPTION 1:
First, set it default to "true" on the entity parameter itself:
class MyEntity {
/**
* #ORM\Column(name="my_param", type="boolean", nullable=true)
*/
private $myParameter = true;
...
}
Secondly, in the form, first see if you can get it from the entity itself. If Not, set the default
public function buildForm(FormBuilderInterface $builder, array $options)
{
/** #var MyEntity $entity */
$entity = $builder->getData();
$builder->add('myParameter', CheckboxType::class, [
'required' => false,
'data' => $entity ? $entity->getMyParameter() : true,
]);
}
This way the real value (coming from the database) has precedence over the default value.
Also good to know is: Submitted data has precedence over the 'data' => true but initially loaded data before submit gets overridden by 'data' => true
OPTION 2:
An alternative way of setting it default true on the MyEntity Class you can choose to set it as default only just before creating the form.
But then you always need the object to create the form with. So you then may not create a form without a given object
if (empty($entity)) {
// Warning: Only if it's a new object, set the default
$entity = new MyEntity();
$entity->setMyParameter(true);
}
// For this option you must always give the form an entity
$form = $this->createForm(MyType::class, $entity);
$form->handleRequest($request);
So for this option you don't need to do anything special in the FormType
$builder->add('myParameter', CheckboxType::class, [
'required' => false,
]);
I'm building a form which contains a category field. I need a choice list to do that, but I don't find out how to fill this choice list with the several categories stored in the database.
public function buildForm(FormBuilder $builder, array $options) {
$builder->add('item', 'text', array('label' => 'Item'));
$builder->add('category', 'choice', array(
'choices' => ???,
'label' => 'Category'
));
}
How can I get the categories from the database?
(I can't seem to access $this->getDoctrine() inside this class.)
Use type entity instead of choice
$builder
->add('entity_property', 'entity', array(
'class' => 'Namespace\\To\\Entity',
'query_builder' => function(EntityRepository $repository) {
return $repository->createQueryBuilder('q')
->where('q.a_field = yourvalue');
}
));
Edit:
Two ways for using custom parameters in your query. In both situations, the parameters are injected from outside, so your FormType don't need any references to the session or request objects or whatever.
1- Pass required parameters to your constructor
class TaskType extends AbstractType
{
private $custom_value;
public function __construct($custom_value) {
$this->custom_value = $custom_value;
}
// ...
}
in your buildForm() you must copy the value to local variable and make it available for the query_builder callback:
public function buildForm(/*...*/) {
$my_custom_value = $this->custom_value;
// ...
'query_builder' => function(EntityRepository $repository) use ($my_custom_value) {
return $repository->createQueryBuilder('q')
->where('q.a_field = :my_custom_value')
->setParameter('my_custom_value', $my_custom_value);
}
// ...
}
2- use the $options parameter of the buildForm method.
First you have to define a default value by overriding getDefaultOptions:
public function getDefaultOptions(array $options)
{
return array(
'my_custom_value' => 'defaultvalue'
);
}
Then you can pass it from your controller in the third argument of the createForm method.
$this->createForm(new YourFormType(), $entity, array('my_custom_value' => 'custom_value'));
Now the value should be available through the $options parameter of youru buildForm method. Pass it to the callback as described above.
In Symfony 2.1
You now have to use the OptionsResolverInterface within the setDefaultOptions method. Here is the code you would have to use if you wanted to retrieve the options (using the same example as the accepted answer)
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
public function buildForm(FormBuilderInterface $builder, array $options){
parent::buildForm($builder, $options);
$my_custom_value = $options[custom_value];
// ...
'query_builder' => function(EntityRepository $repository) use ($my_custom_value) {
return $repository->createQueryBuilder('q')
->where('q.a_field = :my_custom_value')
->setParameter('my_custom_value', $my_custom_value);
}
// ...
}
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array(
'my_custom_value' => 'defaultvalue'
));
}
You still pass the options in the same way:
$this->createForm(new YourFormType(), $entity, array('my_custom_value' => 'custom_value'));