Context of the problem :
I created a symfony form.
Each tool has a collection of modules.
The user has a collection of modules of any tool.
What I want :
I want for each tool there are checkboxes corresponding to the tool's modules. The module checkboxes that the user owns are checked.
([] = checkbox)
Tool1 : []Module1 [x]Module2 [x]Module3
Tool2 : []Module4 [x]Module5
Tool3 : [x]Module6 []Module7
What I currently have:
For each tool, there are checkboxes corresponding to the tool's modules. But I have a problem to tick the checkboxes of user's modules. I get an error on the data parameter.
The form field :
$user = $options['user'];
$tools = $options['tools'];
foreach ($tools as $tool) {
$name = 'profile_'.str_replace(array('-', ' ', '.'), '', $tool->getLibelle());
$builder
->add($name, ChoiceType::class, [
'label' => $tool->getLibelle(),
'choices' => $tool->getModules(),
'choice_value' => 'id',
'choice_label' => function (?Module $module) {
return $module ? $module->getName() : '';
},
'data'=> $user->getModules(), // ERROR HERE
'expanded' => true,
'multiple' => true,
'mapped'=>false
])
;
}
[...]
public function configureOptions(OptionsResolver $resolver): void
{
$resolver->setDefaults([
'data_class' => User::class,
'user'=> null,
'category'=> null,
'tools'=> null,
]);
}
The error :
My question :
Why do I have this error? How can I use the data parameter correctly to achieve the expected result?
You are on the good way, try to dump what is $user->getModules() returning, it has to be an array. May be is not returning an array, check te relation.
I did a little test and it works perfectly.
$name = 'name_field';
$builder->add($name,ChoiceType::class, array(
'choices' => array('Yes', 'No'),
'data' => array('Yes', false),
'mapped' => false,
'expanded' => true,
'multiple' => true
));
Here the solution :
Seems to me that $user->getModules() returns a collection. I managed to find another solution and that works (I changed the type of the field to EntityType)
foreach ($tools as $tool) {
$name = 'acces_'.str_replace(array('-', ' ', '.'), '', $tool->getLibelle());
$builder
->add($name, EntityType::class, [
'class'=> Module::class,
'label' => $tool->getLibelle(),
'data' => $user->getModules(),
'choices'=> $tool->getModules(),
'choice_value' => 'id',
'choice_label' => 'name',
'expanded' => true,
'multiple' => true,
'required' => true,
'mapped'=>false,
])
;
}
ChoiceType: data parameter need array
EntityType: data parameter need collection
Thanks for the help !
Related
I have an entity with age.
I created a search form to show records where ageMin < age < ageMax.
So I added non mapped form fields ageMin and ageMax:
$builder
->add('ageMin', IntegerType::class, [
'mapped' => false,
'required' => false
])
->add('ageMax', IntegerType::class, [
'mapped' => false,
'required' => false
])
;
I would like to check if the user has entered min greater than max (very simple requirement!).
I tried Symfony validate form with mapped false form fields but it is for symfony 2 and Components required is confusing for me.
I found these help pages too:
https://symfony.com/doc/current/form/without_class.html#form-option-constraints and tried:
->add('ageMin', IntegerType::class, [
'mapped' => false,
'required' => false,
'constraints' => new LessThan('ageMax')
])
There are no errors but it doesn't work.
Other page:
https://symfony.com/doc/current/validation/raw_values.html
If there is an entity with the property age you could use LessThan for ageMin and GreaterThan for ageMax to compare these values to age.
$builder
->add('ageMin', IntegerType::class, [
'mapped' => false,
'required' => false,
'constraints' => [new LessThan(['propertyPath' => 'age'])]
])
->add('ageMax', IntegerType::class, [
'mapped' => false,
'required' => false,
'constraints' => [new GreaterThan(['propertyPath' => 'age'])]
])
;
Take care for proper import of the constraints.
EDIT:
The example above assumes that the form makes use of the entity having the property age. If the name of the entity class is Foo, then the method configureOptions would look like:
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults([
'data_class' => Foo::class,
]);
}
For example, I need to take the "id" value and use it to do a search for my model Article, but this value (id) which also appears in the URL: "/article/4/edit" and in the "setColumns" parameters, I don't have any idea how to get it.
I need your help.
This is my sample code:
ArticleCrudController.php
public function __construct()
{
parent::__construct();
$this->crud->setModel('App\Models\Article');
$this->crud->setRoute("admin/article");
$this->crud->setEntityNameStrings('article', 'articles');
$this->crud->setColumns(['id', 'title', 'text']);
// WHERE ARE YOU ID?!?!!!
$article = Article::findOrFail($id);
$pictures = $article->picture()->first()->name;
$this->crud->addFields([
[
'name' => 'title',
'label' => 'Title',
'type' => 'Text'
],
[
'name' => 'text',
'label' => 'Text',
'type' => 'ckeditor'
],
[ // Browse
'name' => 'image',
'label' => 'Article immage',
'type' => 'browse',
'value' => $pictures //Obviously without id don't work :'(
]
]);
}
You could try to override the CrudController::edit method to which is passed the id as first parameter.
public function edit($id)
{
$articlePicture = Article::findOrFail($id)->picture()->first()->name;
$this->crud->addField([
'name' => 'image',
'value' => $articlePicture
]);
return parent::edit($id);
}
This could be a solution but I'm not sure it's the right way to do what you want.
Use getCurrentEntry to get the current model object in crud
$article_id = $this->crud->getCurrentEntry()->id;
I'm building a form like with two non mandatory fileds :
$form = $this->createFormBuilder($contact);
$form->add('name');
$form->add('subject', TextType::class);
$form->getForm();
After rendering the first field is not required (it's normal) but why the second is ?! What's wrong with this code ?
Thanks :)
The problem must be the related entity to this form. Are name and subject nullable?. If no ORM configured then you need to manually set the required attribute to each form field. Look the example of a contact form without ORM.
public function buildForm(FormBuilderInterface $builder, array $options) {
$builder
->add('fullName', null, array(
'required' => true,
'attr' => array(
'placeholder' => 'Name',
'class' => 'text gradient'
)))
->add('email','email', array(
'required' => true,
'attr' => array(
'placeholder' => 'Email',
'class' => 'text gradient'
)))
->add('subject', null, array(
'required' => true,
'attr' => array(
'placeholder' => 'Subject',
'class' => 'text gradient'
)))
->add('body', 'textarea', array(
'required' => true,
'attr' => array(
'placeholder' => 'Message',
'class' => 'text gradient'
)));
}
required default value is defined in type class method configureOptions()
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array(
'required' => true,
));
}
and in all parents for this type (parent is defined by getParent() method)
first parent is Symfony\Component\Form\Extension\Core\Type\FormType and there required default value is defined as true, to it is strange that first input is not required.
you can define required while adding new element $form->add('subject', TextType::class, array('required' => false));
I have a form to select users widh checkboxes.
Now, the list of users is displayed in the form but only the username is displayed. I would like to display all user data with each checkboxes: name, first name, email ...
How can I do this ?
$builder->add('users', 'entity', array(
'class' => 'AppBundle:User',
'choice_label' => 'username',
'expanded' => true,
'multiple' => true,
));
You should create a new method in the entity User. Something like:
public function getAllUserData(){
return $this->name .' | '. $this->email (As you want);
}
In the form:
$builder->add('users', 'entity', array(
'class' => 'AppBundle:User',
'choice_label' => 'allUserData',
'expanded' => true,
'multiple' => true,
));
Cheers...
I created form with date field using single_text widget.
I'm choose this one over choice because I'm using Bootstrap datepicker
Problem I have is that field is always populated with current date instead of being empty.
According to this it should work if i set required to false but id does not.
I tried setting empty_value to empty string same for data but in first case nothing happened probably because this option is for choice fields. In second case I'm getting exception "Expected argument of type "\DateTime", "string" given"
I tried using DataTransformer but didn't make any difference. I found out that for data fields value always goes through DateTimeToLocalizedStringTransformer and if I understand it correctly it is returning empty string if empty value so problem is somewhere further after datatransformers.
One more thing I tried is to set value using attr array and it worked unfortunately the side effect was that populating form with some values doesn't affect date field.
Is there any way to set default value of data field as empty with single_text widget?
Here goes a code
<?php
namespace Psw\AdminBundle\Form;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
use Doctrine\ORM\EntityRepository;
use Psw\AdminBundle\Form\DataTransformer\EmptyDateTransformer;
use Psw\AdminBundle\Form\DataTransformer\EmptyDateViewTransformer;
class OrdersFilterType extends AbstractType
{
private $admin;
public function __construct($admin=false) {
$this->admin = $admin;
}
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('client', 'entity', array(
'class' => 'PswAdminBundle:User',
'required' => false,
'multiple' => false,
'label' => 'orders.client',
'empty_value' => 'orders.allclients',
'query_builder' => function(EntityRepository $er) {
$qb = $er->createQueryBuilder('u');
return $qb->where($qb->expr()->like('u.roles', '?0'))
->setParameters(array('%ROLE_CLIENT%'));
}
));
if($this->admin) {
$builder->add('staff', 'entity', array(
'class' => 'PswAdminBundle:User',
'required' => false,
'multiple' => false,
'label' => 'orders.staff',
'empty_value' => 'orders.allStaff',
'query_builder' => function(EntityRepository $er) {
$qb = $er->createQueryBuilder('u');
return $qb->where($qb->expr()->like('u.roles', '?0'))
->orWhere($qb->expr()->like('u.roles', '?1'))
->orWhere($qb->expr()->like('u.roles', '?2'))
->setParameters(array('%ROLE_STAFF%','%ROLE_ADMIN%','%ROLE_SUPER_ADMIN%'));
}
));
}
$builder->add('start', 'date', array(
'label' => 'orders.start',
'widget' => 'single_text',
'required' => false,
))
->add('end', 'date', array(
'label' => 'orders.end',
'widget' => 'single_text',
'required' => false,
))
->add('min', null, array(
'label' => 'orders.min',
'required' => false,
))
->add('max', null, array(
'label' => 'orders.max',
'required' => false,
));
}
public function getDefaultOptions(array $options)
{
$options = parent::getDefaultOptions($options);
$options['csrf_protection'] = false;
return $options;
}
public function getName()
{
return 'psw_adminbundle_ordersfiltertype';
}
}