I have a form which contains an array of entites, rendered as checkboxes:
$form = $this->createForm(new BasicListType(), $lists);
class BasicListType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('lists', 'entity', [
'required' => false,
'class' => 'MyBundle:ListEntity',
'property' => 'id',
'property_path' => '[id]',
'multiple' => true,
'expanded' => true,
]);
}
public function getName()
{
return 'list';
}
}
When I display my form, the rows are not in the same order as the $lists I built it with.
{{ form_start(form) }}
{% for list in form.lists %}
{{ form_row(list) }}
{% endfor %}
{{ form_end(form) }}
In fact, they're alphabetised by the id property. Why is this happening and more importantly, is there any way I can stop it?
Probably you need to use the query_builder option to construct an custom query, and order the result as you want. Should look something like that:
$builder->add('lists', 'entity', [
'required' => false,
'class' => 'MyBundle:ListEntity',
'property' => 'id',
'query_builder' => function(EntityRepository $er){
$qb = $er->createQueryBuilder('l');
$qb
->select('l')
->orderBy('DESIRED ORDER FIELD', 'ASC OR DESC') // change this!!
;
return $qb;
}
'property_path' => '[id]',
'multiple' => true,
'expanded' => true,
]);
You can pass an QueryBuilder Object directly too. Take a look of the docs.
Related
I have an employee entity, a society entity and a site entity,
A society can have several sites (OneToMany),
The employee has a form. Inside, we have the choice of society.
I would like to nest the Site FormType in that of society.
So when I choose a society under EmployeeForm, it only suggests sites linked to society.
Hope I am clear. I followed the symfony documentation on how to embed an ArrayCollection.
https://symfony.com/doc/5.1/form/form_collections.html
and I looked https://symfony.com/doc/current/form/data_transformers.html
I'm not sure which is the best approach ?
I still get the error
The object of class Doctrine\ORM\PersistentCollection could not be
converted to a string
and I am unable in SocietyForm to isolate the "name" attribute of each Site. I don't want a collection, but a list of name (string).
EmployeeType
class EmployeeType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('name', NULL, [
'label' => 'Nom',
])
->add('firstname', NULL, [
'label' => 'Prénom',
])
->add('societe', EntityType::class, [
'label' => 'Société',
'class' => RefSociety::class,
'choice_label' => 'Name',
])
->add('site', EntityType::class, [
'label' => 'Site',
'class' => RefSociety::class,
'choice_label' => 'refSites'
])
;
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults([
'data_class' => Employee::class,
]);
}
}
RefSocietyType
class RefSocietyType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('Name', NULL, [
'label' => 'Nom de société'
])
->add('refSites', CollectionType::class, array(
'type' => RefSiteType::class,
'allow_add' => true,
'allow_delete' => true,
'prototype' => true,
'by_reference' => false,
))
->add('Adress', NULL, [
'label' => 'Adresse'
])
->add('PostalCode', NULL, [
'label' => 'Code postal'
])
->add('Country', NULL, [
'label' => 'Pays'
])
->add('City', NULL, [
'label' => 'Ville'
])
->add('save', SubmitType::class, [
'attr' => ['class' => 'btn btn-primary btn-block btn-radius'],
'label' => 'Sauvegarder'
])
;
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults([
'data_class' => RefSociety::class,
]);
}
}
RefSiteType
class RefSiteType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('name')
;
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults([
'data_class' => RefSite::class,
]);
}
}
index.html.twig
{ form_start(employeeForm) }}
{{form_row(employeeForm.name, {'attr' : {'class' : ""} }) }}
{{form_row(employeeForm.firstname, {'attr' : {'class' : ""} }) }}
{{form_row(employeeForm.societe) }}
<ul class="sites">
{% for site in employeeForm.refSites %}
<li>{{ form_row(site.name) }}</li>
{% endfor %}
</ul>
{{ form_end(employeeForm) }}
->add('site', EntityType::class, [
'label' => 'Site',
'class' => RefSociety::class,
'choice_label' => 'refSites'
])
'choice_label' => 'refSites' means that the method getRefSites() are called by PropertyAccessor to get a label name, so the method getRefSites returns the collection (because one to many), but the label must be a string.
Maybe should you use 'choice_label' => 'name' ?
I'm trying to make a form to add an entity in my database (a project). I realized exactly the same thing for other entities, everything works, but for this one (a project), it does not work ...
Screen of error : http://image.noelshack.com/fichiers/2019/02/1/1546884788-capture.png
ProjectController :
/**
* #Route("/projects/add", name="add_projects")
*/
public function addProject(Request $request)
{
$em = $this->getDoctrine()->getManager();
$project = new Project();
$form = $this->createForm(AddProjectType::class, $project);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$em->persist($project);
$em->flush();
return $this->redirectToRoute('index_projects');
}
return $this->render('/project/add.html.twig', [
'form' => $form->createView(),
]);
}
AddProjectType :
class AddProjectType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('name', TextType::class, array(
'attr' => array(
'placeholder' => 'Nom',
),
'label' => false,
))
->add('price', IntegerType::class, array(
'attr' => array(
'placeholder' => 'Prix',
),
'label' => false,
))
->add('type', ChoiceType::class, array(
'choices' => array(
'Application web' => 'Application web',
'Site internet' => 'Site internet',
'Application mobile' => 'Application mobile',
'Autre' => 'Autre',
),
'label' => false,
))
->add('client', EntityType::class, array(
'class' => User::class,
'choice_label' => function($user) {
return $user->getUsername();
},
'label' => false,
))
->add('state', ChoiceType::class, array(
'choices' => array(
'A faire' => 'A faire',
'En cours' => 'En cours',
'Terminé' => 'Terminé',
),
'label' => false,
))
->add('description', TextareaType::class, array(
'attr' => array(
'placeholder' => 'Description',
),
'label' => false,
))
->add('Ajouter', SubmitType::class, [
'attr' => [
'class' => 'btn btn-success',
]
])
;
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults([
'data_class' => Project::class,
]);
}
}
add.html.twig :
{% extends "./base.html.twig" %}
{% block title %}{{ parent() }}Ajouter un projet{% endblock %}
{% block stylesheets %}
{{ parent() }}
<style>
form input, form select, form textarea {
width: 100%;
margin: .5em 0;
}
</style>
{% endblock %}
{% block body %}
{{ parent() }}
<h1 class="title-page">Ajouter un projet</h1>
<div class="container-fluid">
{{ form_start(form) }}
{{ form_widget(form) }}
{{ form_end(form) }}
</div>
{% endblock %}
Did you look into the database whether the project is added?
In your controller I don't see a reason for a ParamConverter, therefore I guess that the error happens after the redirect to index_projects
I just managed to find out why I had this error, I'll post the salution here so that other people have it:
I had in this controller a route /projects/{id} (to access the details of a project), I modified it by /projects/details/{id}
I want to use a form_widget to render a field for a collectionType form. Here is my controller :
/**
* #Route("/ticket", name="ticket")
*/
public function ticket(Request $request)
{
$data = $request->getSession()->get('orders');
$number = $data->getNumberOfTickets();
for ($i=1; $i<=$number ;$i++){
$tickets[] = new Tickets();
}
$form = $this->createForm(CollectionType::class, $tickets, ['entry_type' => TicketsType::class] );
$form->handleRequest($request);
dump($request);
return $this->render('louvre/ticket.html.twig', [
'tickets' =>$tickets,
'form' => $form->createView()
]);
}
and when i try :
{{ form_widget(tickets.firstname)}}
or
{{ form_widget(form.firstname)}}
or
{{ form_widget(form.tickets.firstname)}}
I have an error :
Neither the property "firstname" nor one of the methods "firstname()", "getfirstname()"/"isfirstname()"/"hasfirstname()" or "__call()" exist and have public access in class "Symfony\Component\Form\FormView".
Here is my form :
class TicketsType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('category', CheckboxType::class, [
'attr' => [
'class' => 'form-control'
]
])
->add('firstname', TextType::class, [
'attr' => [
'class' => 'form-control'
]
])
->add('lastname', TextType::class, [
'attr' => [
'class' => 'form-control'
]
])
->add('country', TextType::class, [
'attr' => [
'class' => 'form-control'
]
])
->add('dateOfBirth', DateType::class, [
'attr' => [
'class' => 'form-control'
],
'widget' => 'single_text',
])
;
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults([
'data_class' => Tickets::class,
]);
}
}
To render a field I just need to use the prototype in twig:
{{ form_widget(form.vars.prototype.firstname) }}
and add this in my form method, in my controller:
'allow_add' => true
You might want to add the code of the entity to your question: Tickets.php
In Tickets.php you probably define the class Tickets and in that class you probably don't have any of the methods listed in the error message. Adding this method with the exact name should help:
public function getfirstname() {
return $this->firstname;
}
About the twig code: you might want to add some more to the question. For example, do you have {{ form_start(form) }} or something else in the beginning?
Then as it is a CollectionType, you probably want to render some input field for each of the members in the collection. Maybe something like this:
{% for ticket in form.tickets %}
<div class="ticket">{{ form_widget(ticket.firstname) }}</div>
{% endfor %}
I have this problem in Symfony 2.8: I can't render a custom variable with my query passed to form option.
See the below code what i have tried :
This is my controller:
$form = $this->createForm('AppBundle\Form\FooAdminType', $res, array('attr' => array('fooOnes' => $Choices)));
//when $choices is my dql query
This is my formType:
public function buildForm(FormBuilderInterface $builder, array $options) {
$builder->add('bar', EntityType::class, array(
'class' => 'AppBundle:Foo',
'choices' => $options['attr']['FooOnes'],
'required' => true,
'property' => 'name',
'attr' => array(
'class' => 'col-lg-2 control-label text-center'
)
))
finally, my twig template
{% for foo in form.bar %}
{{ form_widget(foo) }}
{% endfor %}
...Without the for block, the form is rendered. With the for block, I have this error:
An exception has been thrown during the rendering of a template ("Catchable Fatal Error: Object of class Doctrine\ORM\PersistentCollection could not be converted to string") in form_div_layout.html.twig at line 277.
PS: I have defined the public function __toString() in the entity
Without testing your code, the way you have set it up right now, you will be rendering a select element. Therefore, it doesn't make any sense for you to be looping through it.
You will need to set the attribute expanded to true in order for you to be able to use the for loop. This way, you will be rendering either radio buttons or checkboxes, depending on the multiple value.
For checkboxes:
public function buildForm(FormBuilderInterface $builder, array $options) {
$builder
->add('bar', EntityType::class, array(
'class' => 'AppBundle:Foo',
'choices' => $options['attr']['FooOnes'],
'required' => true,
'expanded' => true,
'multiple' => true,
'property' => 'name',
'attr' => array(
'class' => 'col-lg-2 control-label text-center'
)
))
I have a form where the dropdown value is coming from another entity.
->add('country', 'entity', array(
'label' => 'Country',
'query_builder' => function (EntityRepository $er) {
return $er->createQueryBuilder('u')
->orderBy('u.countryName', 'ASC');
},
'empty_value' => 'Select Country',
'required' => true,
'mapped' => true,
'class' => 'BundleAdminBundle:KidsKulaCountry',
'attr' => array('class' => 'form-control sml-frm'),
//...
))
In the twig file i want to set selected the value at edit.
{{ form_widget(form.country, {value: Setcountry } ) }}
if I print
{{Setcountry}}
its returns result but it does not set selected.Please help me out.
I suppose that your Setcountry is the id of the entity you want to select. You can do this with the conversion of the Setcountry of int to string in the next way:
{{ form_widget(form.country, {value: Setcountry ~ "" } ) }}