Symfony3: form: populate select with related model entries - php

I have two models, topic and user. Both are related by many-to-one relationship (a topic is defined by only one user) such as:
class User
{
private $idUser;
private $username;
}
class Topic
{
private $idTopic;
private $topicName;
private $idUser;
}
MAIN CONCERN: I would like (using symfony-forms) to create a creation form for the topic model. The form would contain:
a topic name input
a user select (list populated by the existing users in the database. The displayed value would be the username of course).
I have created a TopicType class that will build the topic creation form:
class TopicType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->
->add('topicName')
->add(/* 'idUser', 'choice', 'THE USER LIST ???*/)
}
public function configureOptions(FormBuilderInterface $builder, array $options)
{
$resolver->setDefaults(array(
'data_class' => 'AppBundle\Entity\Topic'
));
}
}
How can I retrieve the list of users and populate the choices considering I don't have access to the entity manager in TopicType context?
Could I pass a $users array in the controller as a parameter when invoking createForm method ? If so, how ?
If you understood what I'm trying to do, Is there a better/simplier way to get it done ? Am I missing something ?
I know this question might look similar but all the solutions I found on related topics are somehow deprecated in Symfony3
Any help would be much appreciated.
Have a good day to you all.

you should try something like this (you must adapt the code):
->add('User', EntityType::class, array(
'class' => 'xxxBundle\Entity\User',
'choice_label' => 'username',
'required' => true,
'multiple' => false,
))
do not forget :
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
More info here : http://symfony.com/doc/current/reference/forms/types/entity.html

Related

Symfony how to validate EntityType field

I have this EntityType field on my UserType's form:
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('country', EntityType::class, array(
'class' => Country::class,
'choice_label' => 'nicename'
));
}
How can i use validation constraints to validate this type of field in the way that user can only select a value in the range of all rows of country's table? I think that I should use Choice constraint with callback, and call the getAllCountries function inside my CountryRepository class. So what's the best way to manage this scenario?
Somethins like this:
// UserEntity.php
class User {
/**
* #Assert\Choice(callback="App\Repository\CountryRepository", "getAllCountries")
* #ORM\ManyToOne(targetEntity="App\Entity\Country", inversedBy="users")
*/
protected $country;
}
But CountryRepository is not a static function!!
Entity field doesn't allow to select invalid value (if you have invalid value it would't find the entity -> wouldn't be able to send form). This is as well behaviour of choice type.
But for callback, there is special callback constraint - https://symfony.com/doc/current/reference/constraints/Callback.html which can be used to call constraint function.

How to pass parameters to build selects in collection of embedded forms in Symfony

Please, I need some advice on Symfony forms and entities.
I have Questionarie(entity) form with number of assigned Rows(entities). Rows objects are assigned to Questionarie object. Each row has select input with options from DB. Options are entities, let's say OptionEntity. Each select is filled with query for OptionEntities based on one parameter.
Each Row stores chosen answer. Each answer is assigned to question. Row knows nothing about question.
So I build a QuestionarieType form with some fields and collection of embedded RowType forms.
The question is how to pass parameters to queries to build options in each row. As Rows objects are assigned to Questionarie object all rows in form are built automatically. So I don't know how map parameters to corresponding rows.
I think about additional field in Row entity to store this paramater but I don't know whether it is bad idea because Row entity is used to store chosen answer and knows nothing about question.
Thank you! Any thoughts are appreciated.
Controller action:
{
$questionarie = new Questionarie(); // just a wrapper for questions with some meta data: userId, timestamp, etc.
/*here I fetch questions from DB somehow and then iterate through them:*/
foreach ($question as $q) {
$row = new FormRow();
$questionarie->addFormRow($row);
}
$form = $this->createForm(QuestionarieType::class, $questionarie);
}
class QuestionarieType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('FormRows', CollectionType::class, array(
'entry_type' => FormRowType::class,
));
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'Sfedu\RatingBundle\Entity\Questionarie',
));
}
}
class FormRowsType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('answer', EntityType::class, array(
'class' => 'SfeduRatingBundle:Answer',
'query_builder' => function (EntityRepository $er) use ($question_id){
return $er->createQueryBuilder('a')
->where('a.question = :question')
->setParameter('question', $question_id); //! here I want to use parameter to filter possible answers for each row
},
));
}
}

Assign filtered list of entities to Entity field in Symfony2 form

I have a little problem in my Symfony form.
This is my code:
class ProfileFormType extends AbstractType
{
/**
* #param FormBuilderInterface $builder
* #param array $options
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('adress',null,array('label' => 'form.adress', 'translation_domain' => 'FOSUserBundle'))
->add('niveau','entity',array(
'class'=>'EnsajAdministrationBundle:Niveau',
'property'=>'libelle'
,'multiple'=>false)
)
The problem is that normally it returns all rows for the named Entity, but I want to return just the 2 first rows from the "niveau" ("level") table, to be used as the choices for my form.
What is the solution for this problem?
You have (at least) a couple of options here, but the obvious one is to supply a QueryBuilder to the field which provides the required rows (see Symfony docs on EntityType Field)
E.g.
//Create function which accepts EntityRepository and returns required QueryBuilder
$qbFunction = function(EntityRepository $er) {
return $er->createQueryBuilder('n')
//->orderBy() //If you need to, to get the correct 2 rows!
->setMaxResults(2); //Just two rows
};
$builder->add('adress',null,array('label' => 'form.adress', 'translation_domain' => 'FOSUserBundle'))
->add('niveau','entity',array(
'class'=>'EnsajAdministrationBundle:Niveau',
'property'=>'libelle'
,'multiple'=>false
,'query_builder' => $qbFunction) //give function to field
)
You can make the query more complex if you need to, e.g. add joins

Filtering which items to show up in collection field

I have a form using this class type:
class DespesasContainerType extends AbstractType
{
public function buildForm(FormBuilder $builder, array $options)
{
$builder
->add('despesas', 'collection', array(
'type' => new DespesasFamiliasType(),
'by_reference' => false,
))
;
}
// ...
}
This way it shows all items in the despesas attribute of the object.
Is there a way to filter which items to use? Something similar to the query_builder option on the entity field type.
No way from FormTypeInterface, but you can filter this collection before passing it to the Form.
Another tricky tip :
Define a public getter like getFilteredDespeas on your Entity that returns the filtered list of despeas. In your Form, just call the field filteredDespeas instead of despeas. This involves that you specifically manage the form binding, by adding a public setFilteredDespeas to your entity, or any other way...

Symfony 2 Form with select list

How can i create a select list with values from a database table in Symfony 2?
I have 2 entities: Student and Classroom with a ManyToOne relationship and i need to create a form with the folowing fields: name, surname, age, classroom(select list from available classes).
In my Student Form i have
$builder
->add('name')
->add('surname')
->add('age')
->add('classroom', new ClassroomType())
;
In my Classroom Form i have this:
$classrooms =$this->getDoctrine()->getRepository('UdoCatalogBundle:Classroom')->findAll();
$builder
->add('clasa','choice',array('choices' => array($classrooms->getId() => $classrooms->getName())));
I get this following error:
Fatal error: Call to undefined method Udo\CatalogBundle\Form\ClassroomType::getDoctrine() in /var/www/html/pos/src/Udo/CatalogBundle/Form/ClassroomType.php on line 13
Kind Regards,
Cearnau Dan
Not sure if you found an answer yet but I just had to do some digging around to figure this out for my own project.
The form class isn't set up to use Doctrine like the controller is so you can't reference the Entity the same way. What you want to do is use the entity Field Type which is a special choice Field Type allowing you to load options from a Doctrine entity as you are trying to do.
Ok so long story short. Instead of doing what you are doing to create the choice field, do this:
->add('category', 'entity', array(
'class' => 'VendorWhateverBundle:Category',
'query_builder' => function($repository) { return $repository->createQueryBuilder('p')->orderBy('p.id', 'ASC'); },
'property' => 'name',
))
I'm not sure if you could place the query_builder function into a repository or what, I'm kind of swinging wildly as I go. Up to this point the documentation I linked to above is pretty clear on what to do. I guess the next step is to read up on Doctrine's QueryBuilder.
While you're in there I think you want to drop the bit where you are embedding the Classroom form,
->add('classroom', new ClassroomType())
You probably don't want people creating their own classrooms. Unless you do, then yeah.
If the entities are mapped, this is a clean solution for Symfony 2.8+ or 3+
<?php
namespace My\AppBundle\Form\Type;
use My\AppBundle\Entity\Student;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
class StudentType extends AbstractType
{
/**
* {#inheritdoc}
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('name')
->add('surname')
->add('age')
/*
* It will be resolved to EntityType, which acts depending on your doctrine configuration
*/
->add('classroom');
}
/**
* {#inheritdoc}
*/
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(['data_class' => Student::class]);
}
}

Categories