symfony form choice with entity get result - forms

I'm trying to get the result of my choice form.
The form is like this :
$users = $em->getRepository('UserBundle:User')->findAll();
$form = $this->createFormBuilder($users)
->add('users', 'entity', array(
'label' => 'Pick that user',
'class' => 'UserBundle:User',
'choice_label' => 'usFirstname'))
->add('save', 'submit', array('label' => 'Submit'));
Then I want to get the user picked, I try several things, but nothing worked...
It should be something like this :
$user_picked =
$em->getRepository('UserBundle:User')->
findBy(array('usFirstname' => $form->getForm()->get('users')->getData()));
How should I do to get the user picked after the button 'Submit' is clicked ?

The magic of the form builder does this work for you.
If you dump the data dump($form->get('users')->getData()) it will be an instance of the user for the choice in the form. No need to to do an extra query.
Also the choice_label just filters what is in the text of the select option, not the value.
Example;
<?php
namespace AppBundle\Controller;
use AppBundle\Entity\User,
AppBundle\Form\MyFormType;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route,
Sensio\Bundle\FrameworkExtraBundle\Configuration\ParamConverter,
Sensio\Bundle\FrameworkExtraBundle\Configuration\Security;
use Symfony\Component\HttpFoundation\Request,
Symfony\Bundle\FrameworkBundle\Controller\Controller;
class MyController extends Controller
{
public function addAction(Request $request)
{
$form = $this->createForm(new MyFormType(), null, []);
$form->add('submit', 'submit', [
'label' => 'Create',
'attr' => ['class' => 'btn btn-success pull-right']
]
);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
dump($form->get('users')->getData());
exit(0);
}
return $this->render('AppBundle:user:form.html.twig', [
'form' => $form->createView()
]
);
}
}
<?php
namespace AppBundle\Form;
use Symfony\Component\Form\AbstractType,
Symfony\Component\Form\FormBuilderInterface,
Symfony\Component\OptionsResolver\OptionsResolver,
Symfony\Component\Validator\Constraints as Assert;
class MyFormType extends AbstractType
{
/**
* #param FormBuilderInterface $builder
* #param array $options
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('users', 'entity', [
'required' => false,
'class' => 'AppBundle:User',
'choice_label' => 'usFirstname',
'expanded' => false,
'multiple' => false,
]);
}
/**
* #param OptionsResolver $resolver
*/
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array(
'data_class' => null,
));
}
/**
* #return string
*/
public function getName()
{
return 'my_form';
}
}

Related

Symfony Check if at least one of two fields isn't empty on form validation of CollectionType

In a previous question (Symfony Check if at least one of two fields isn't empty on form validation) I had asked help for form validation using Callback. The answer given by #hous was right, but it doesn't work for elements in a CollectionType, reason why I'm opening a new question.
Based on the previous answer I have done the following:
Here is my "mother" Form:
class BookingVisitorType extends AbstractType
{
private $router;
private $translator;
public function __construct()
{
}
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('visitors', CollectionType::class, [
'entry_type' => VisitorType::class,
'label' => 'entity.booking.visitors',
'allow_add' => true,
'allow_delete' => true,
'delete_empty' => true,
'by_reference' => false,
'entry_options' => [
'label' => false,
'delete-url' => $options['visitor-delete-url']
],
'constraints' =>[
new Count([
'min' => 1,
'minMessage' => 'validator.visitor.at-least-one-visitor',
'max' => $options['numberOfPlaces'],
'maxMessage' => 'validator.visitor.cannot-have-more-visitor-than-spaces',
'exactMessage' => 'validator.visitor.exact-message'
])
]
])
;
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults([
'data_class' => Booking::class,
'numberOfPlaces' => 1,
'visitor-delete-url' => ''
]);
}
}
Here is my "son" Form:
class VisitorType extends AbstractType
{
private $phone;
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('firstName', TextType::class, [
'label' => 'entity.visitor.first-name',
'constraints' => [
new NotBlank(),
new Length([
'min' => 2,
'max' => 255
]),
new Regex([
'pattern' => "/[\pL\s\-]*/",
'message' => 'validator.visitor.not-valide-first-name'
])
]
])
->add('phone', TextType::class, [
'label' => 'entity.visitor.phone-number',
'required' => false,
'constraints' => [
new Regex([
'pattern' => "/[0-9\s\.\+]*/",
'message' => 'validator.visitor.not-valide-phone-number'
]),
new Callback(function($phone, ExecutionContextInterface $context){
$this->phone = $phone;
}),
]
])
->add('email', TextType::class, [
'label' => 'entity.visitor.email',
'required' => false,
'constraints' => [
new Email(),
new Callback(function($email, ExecutionContextInterface $context){
if ($this->phone == null && $email == null) {
$context->buildViolation('validator.visitor.email-or-phone-required')->addViolation();
}
}),
]
])
;
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults([
'data_class' => Visitor::class,
'error_bubbling' => false,
'delete-url' => '',
]);
}
}
My "booking" (shortened) class:
/**
* #ORM\Entity(repositoryClass="App\Repository\BookingRepository")
*/
class Booking
{
/**
* #ORM\Id()
* #ORM\GeneratedValue()
* #ORM\Column(type="integer")
*/
private $id;
/**
* #ORM\OneToMany(targetEntity="App\Entity\Visitor", mappedBy="booking", orphanRemoval=true, cascade={"persist"})
* #Assert\Valid
*/
private $visitors;
}
And finally my "visitor" (shortened) class:
/**
* #ORM\Entity(repositoryClass="App\Repository\VisitorRepository")
*/
class Visitor
{
/**
* #ORM\Id()
* #ORM\GeneratedValue()
* #ORM\Column(type="integer")
*/
private $id;
/**
* #ORM\Column(type="string", length=45, nullable=true)
*/
private $phone;
/**
* #ORM\Column(type="string", length=255, nullable=true)
*/
private $email;
/**
* #ORM\ManyToOne(targetEntity="App\Entity\Booking", inversedBy="visitors")
* #ORM\JoinColumn(nullable=false)
*/
private $booking;
/**
* #Assert\Callback
*/
public function validateAtLeastEmailOrPhone(ExecutionContextInterface $context, $payload)
{
if ($this->getPhone() === null && $this->getEmail() === null) {
$context->buildViolation('validator.visitor.email-or-phone-required-for-all')->addViolation();
}
}
}
I've been able to workaround the problem by adding a property to my VisitorType form that I define with the Callback constraint on the phone value and then check it with a Callback constraint on the email field, but it doesn't seem very "good practice".
If I only try to call the Callback constraint I get the following error message: "Warning: get_class() expects parameter 1 to be object, string given"
Any help is highly appreciated!
Instead of an callback function you could create your own Constraint. Then the Check would be reusable.
I've been using this to check the password on registration against custom rules.

Symfony\Component\OptionsResolver\Exception\UndefinedOptionsException: The options " " do not exist. Known options are: ""

This is my form
namespace AppBundle\Form;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
class JoseType extends AbstractType
{
/**
* #param FormBuilderInterface $builder
* #param array $options
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('nombre')
->add('apellido','entity', array(
// 'required' => false,
'empty_value' => 'Select',
'mapped' => false,
'class' => 'AppBundle:SolutionTypeCategory',
'attr' => array(
'placeholder' => 'Select',
'data-msg-required' => "Required Solution Type Category",
),
))
->add('edad')
;
}
/**
* #param OptionsResolverInterface $resolver
*/
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'AppBundle\Entity\Jose'
));
}
/**
* #return string
*/
public function getName()
{
return 'appbundle_jose';
}
}
I receive this error
Symfony\Component\OptionsResolver\Exception\UndefinedOptionsException: The options "attr", "class", "empty_value", "mapp
ed" do not exist. Known options are: "".
And the following is my test:
class ProjectTypeTest extends TypeTestCase
{
public function testJose()
{
$type = new JoseType();
$form = $this->factory->create($type);
}
// get extensions...
protected function getExtensions()
{
$mockEntityType = $this->getMockBuilder('Symfony\Bridge\Doctrine\Form\Type\EntityType')
->disableOriginalConstructor()
->getMock();
$mockEntityType->expects($this->any())->method('getName')
->will($this->returnValue('entity'));
return array(new PreloadedExtension(array(
$mockEntityType->getName() => $mockEntityType,
), array()));
}
}
I don't understand that error, looking take the values array options of form.
Why?
Help me please!
When you invoke ->add() from $builder - there is a list of pre set options that you are allowed to use.
Each form type has a number of options to configure it, as explained in the Symfony form types reference.

Symfony 3 : Adding checkboxes to form form database

I'm struggling with symfony forms. I want to build a form for an user. This user as a arraycollection field that gather products (nom, description).
I would like to create a form that create a checkbox for each of the products passed to the form builder. Actually it just created input fields without labels... Here is the code of my UserType class :
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('nom')->add('prenom')->add('mail')->add('tel1')->add('tel2', TextType::class, array('required' => false))
->add('username')->add('password', PasswordType::class)
->add('groupe', ChoiceType::class, array(
'choices' => array('Administrateur' => 'ROLE_SUPER_ADMIN', 'Gérant' => 'ROLE_ADMIN', 'Opérateur' => 'ROLE_USER'),
'expanded' => true,
))
->add('produits', CollectionType::class, array(
'entry_type' => ProduitType::class
))
;
}
/**
* {#inheritdoc}
*/
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array(
'data_class' => User::class
));
}
/**
* {#inheritdoc}
*/
public function getBlockPrefix()
{
return 'gestcoupons_userbundle_user';
}
Here is my ProduuctType code :
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('nom')->add('prenom')->add('mail')->add('tel1')->add('tel2', TextType::class, array('required' => false))
->add('username')->add('password', PasswordType::class)
->add('groupe', ChoiceType::class, array(
'choices' => array('Administrateur' => 'ROLE_SUPER_ADMIN', 'Gérant' => 'ROLE_ADMIN', 'Opérateur' => 'ROLE_USER'),
'expanded' => true,
))
->add('produits', CollectionType::class, array(
'entry_type' => ProduitType::class
))
;
}
/**
* {#inheritdoc}
*/
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array(
'data_class' => User::class
));
}
/**
* {#inheritdoc}
*/
public function getBlockPrefix()
{
return 'gestcoupons_userbundle_user';
}
Here is my UserController code :
public function ajouterAction(Request $request){
$this->denyAccessUnlessGranted('ROLE_ADMIN', null, 'Unable to access this page!');
$em = $this->getDoctrine()->getManager();
$produits = $em->getRepository('ProduitBundle:Produit')->findAll();
$societes = $em->getRepository('SocieteBundle:Societe')->findAll();
$user = new User();
foreach ($produits as $produit) {
$user->getProduits()->add($produit);
}
$form = $this->createForm('GestCoupons\UserBundle\Form\UserType', $user);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$em = $this->getDoctrine()->getManager();
$em->persist($user);
$em->flush($user);
return $this->redirect('dashboard_admin');
}
return $this->render('user/new.html.twig', array(
'user' => $user,
'form' => $form->createView(),
));
}
Thanks ahead for your help.
You should use Symfony\Bridge\Doctrine\Form\Type\EntityType instead of CollectionType.
In your UserType
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
use AppBundle\Entity\Produit;
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('nom')
->add('prenom')
->add('mail')
->add('tel1')
->add('tel2', TextType::class, array(
'required' => false
))
->add('username')
->add('password', PasswordType::class)
->add('groupe', ChoiceType::class, array(
'choices' => array(
'Administrateur' => 'ROLE_SUPER_ADMIN',
'Gérant' => 'ROLE_ADMIN',
'Opérateur' => 'ROLE_USER'
),
'expanded' => true,
))
->add('produits', EntityType::class, array(
'class' => Produit::class,
'multiple' => true,
'expanded' => true,
'label' => 'nom' //If you don't have a __toString method in your Produit Entity
))
;
}
/**
* {#inheritdoc}
*/
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array(
'data_class' => User::class
));
}
/**
* {#inheritdoc}
*/
public function getBlockPrefix()
{
return 'gestcoupons_userbundle_user';
}
This way you will have a checkbox for each Product entity in your database and only the one you checked will be associated to your user

Symfony Form Choices Entity

I try to use the 'choices' option into my form :
class FicheInterventionType extends AbstractType
{
/**
* #param FormBuilderInterface $builder
* #param array $options
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('services', EntityType::class, array(
'class' => 'GestionBundle:Service',
'choice_label' => 'nom',
'multiple' => true,
'choices' => $options['services'],
'required' => false))
;
}
/**
* #param OptionsResolver $resolver
*/
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'FichesBundle\Entity\FicheIntervention',
'services' => null
));
}
}
controller :
$form = $this->createForm(FicheInterventionType::class, $ficheObservation,
array('services' => $this->getUser()->getCategorie()->getServices()));
but I get all services present in my database, not the services passed with the parameter $option.
I don't know why.

Symfony2 : data not binded to form with handleRequest()

I have created a complex symfony form with nested collection. When i create my form with data from orm it works :
$categories = $this->getDoctrine()->getRepository('xx:CategoryNutritionProgram')->findAll();
$form = $this->createForm(new CategoryCollectionFormType(), array('categories' => $categories));
CategoryCollectionFormType :
class CategoryCollectionFormType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('categories', 'collection', array(
'type' => new CategoryFormType(),
'cascade_validation' => true,
'allow_add' => true,
'by_reference' => false,
'allow_delete' => true,
'prototype_name' => '__i__'
));
}
/**
* Returns the name of this type.
*
* #return string The name of this type
*/
public function getName()
{
return 'simulator_category_collection';
}
}
CategoryFormType :
class CategoryFormType extends AbstractType
{
/**
* #param FormBuilderInterface $builder
* #param array $options
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('name', 'hidden');
$builder->add('nutritionPrograms', 'collection', array(
'type' => new NutritionProgramFormType(),
'cascade_validation' => true,
'allow_add' => true,
'by_reference' => false,
'allow_delete' => true,
'prototype_name' => '__j__'
));
}
/**
* #param OptionsResolverInterface $resolver
*/
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'xx\Entity\CategoryNutritionProgram'
));
}
/**
* Returns the name of this type.
*
* #return string The name of this type
*/
public function getName()
{
return 'simulator_category';
}
}
etc ...
But handleRequest() function doesn't work and $data are empty when i submit form. Where is the problem ? my code seems good
$data = array('categories' => array());
$form = $this->createForm(new CategoryCollectionFormType(), $data);
$form->handleRequest($request);
Below the data sent on POST request :
simulator_category_collection[categories][0][name]:cat1
simulator_category_collection[categories][0][nutritionPrograms][0][name]:prog1
simulator_category_collection[categories][0][nutritionPrograms][0][applications][0][name]:app1
simulator_category_collection[categories][0][nutritionPrograms][0][applications][0][product]:1
simulator_category_collection[categories][0][nutritionPrograms][0][applications][0][dose]:5
simulator_category_collection[categories][0][nutritionPrograms][0][applications][0][unit]:5
simulator_category_collection[categories][0][nutritionPrograms][0][applications][1][name]:app2
simulator_category_collection[categories][0][nutritionPrograms][0][applications][1][product]:2
simulator_category_collection[categories][0][nutritionPrograms][0][applications][1][dose]:6
simulator_category_collection[categories][0][nutritionPrograms][0][applications][1][unit]:6
simulator_category_collection[categories][0][nutritionPrograms][1][name]:prog2
simulator_category_collection[categories][0][nutritionPrograms][1][applications][0][name]:app3
simulator_category_collection[categories][0][nutritionPrograms][1][applications][0][product]:3
simulator_category_collection[categories][0][nutritionPrograms][1][applications][0][dose]:7
simulator_category_collection[categories][0][nutritionPrograms][1][applications][0][unit]:7
simulator_category_collection[categories][1][name]:cat2
simulator_category_collection[categories][1][nutritionPrograms][0][name]:prog3
simulator_category_collection[_token]:xxx
Thx for help
Resolved, instead of trying to get data from orginal object like this :
$data = array('categories' => array());
$form = $this->createForm(new CategoryCollectionFormType(), $data);
$form->handleRequest($request);
// here array $data is empty
I have to use $form->getData() because my array is passed by value