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
Related
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.
On my site, people can post comments on my posts, and I can reply to them from my back office.
I want people to fill a recaptcha on the front-office, so I used EWZRecaptchaBundle, and made the following CommentaireType :
<?php
namespace Babdelaura\BlogBundle\Form;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\Extension\Core\Type\TextareaType;
use Symfony\Component\Form\Extension\Core\Type\EmailType;
use EWZ\Bundle\RecaptchaBundle\Form\Type\EWZRecaptchaType;
use EWZ\Bundle\RecaptchaBundle\Validator\Constraints\IsTrue as RecaptchaTrue;
class CommentaireType extends AbstractType
{
/**
* #param FormBuilderInterface $builder
* #param array $options
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('auteur', TextType::class)
->add('email', EmailType::class, array('required' => false))
->add('site', TextType::class, array('required' => false))
->add('contenu', TextareaType::class)
->add('recaptcha', EWZRecaptchaType::class, array(
'mapped' => false,
'constraints' => array(new RecaptchaTrue())
))
;
}
/**
* #param OptionsResolver $resolver
*/
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'Babdelaura\BlogBundle\Entity\Commentaire'
));
}
/**
* #return string
*/
public function getBlockPrefix()
{
return 'babdelaura_blogbundle_commentaire';
}
}
But now, I have a recaptcha on my back-office too, and I don't want it.
Before Symfony 3 and FQCN for types I used to do new CommentaireType(true) in my back office, retrieve the boolean in CommentaireType::__construct, and add the recaptcha if is was true. But now I can't do this anymore.
Does somebody have a clean solution to handle that case ?
Thank you !
You can use options when you call your service to pass a boolean for example like this :
$form = $this->createForm(new CommentaireType(), $commentaire, array(
'recaptcha' => false,
));
and then in your CommentaireType:
class CommentaireType extends AbstractType
{
/**
* #param FormBuilderInterface $builder
* #param array $options
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('auteur', TextType::class)
->add('email', EmailType::class, array('required' => false))
->add('site', TextType::class, array('required' => false))
->add('contenu', TextareaType::class);
if($options['recaptcha']) {
$builder
->add('recaptcha', EWZRecaptchaType::class, array(
'mapped' => false,
'constraints' => array(new RecaptchaTrue())
));
}
}
/**
* #param OptionsResolver $resolver
*/
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'Babdelaura\BlogBundle\Entity\Commentaire',
'recaptcha' => false,
));
}
/**
* #return string
*/
public function getBlockPrefix()
{
return 'babdelaura_blogbundle_commentaire';
}
}
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.
I am using a collection with type field type. This is retrieving fields from a table. I am able to add/edit the fields.
What I would like to do is only return certain fields in the collection.
eg only the fields where the column reference_id = 2
The reason I would like to do this is because I am grouping the returned values to their group.
So I will be returning multiple collections grouped by their group.
DetailsType.php
$builder
->add('FieldText', 'collection', array(
'type' => new FieldTextType(),
'prototype' => true,
'allow_add' => true,
'allow_delete' => true,
))
FieldTextType.php
$builder
->add('label', 'text')
->add('value', 'text')
;
Edit - Added the type
DetailsType.php
class VillaDetailsType extends AbstractType
{
/**
* #param FormBuilderInterface $builder
* #param array $options
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('CollectionOne', 'collection', array(
'type' => new FieldTextType(),
'prototype' => true,
'allow_add' => true,
'allow_delete' => true,
))
->add('CollectionTwo', 'collection', array(
'type' => new FieldCheckboxType(),
'prototype' => true,
'allow_add' => true,
'allow_delete' => true,
))
;
}
/**
* #param OptionsResolverInterface $resolver
*/
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'some/entity'
));
}
/**
* Returns the name of this type.
*
* #return string The name of this type
*/
public function getName()
{
return 'base';
}
FieldTextType.php
class FieldTextType extends AbstractType
{
/**
* {#inheritdoc}
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('label', 'text')
->add('value', 'text')
;
}
/**
* {#inheritdoc}
*/
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'Some/Entity'
));
}
/**
* Returns the name of this type.
*
* #return string The name of this type
*/
public function getName()
{
return 'detail';
}
I have problem with form collection. I want to show one form with all values from one entity and I want to be able to add or remove some record(line) from this entity on one page. I have the following solutions, which is ok.
CurrencyController
class CurrencyController extends Controller {
/**
* #Template()
*/
public function testAction() {
$em = $this->getDoctrine()->getManager();
$currencies = $em->getRepository('MyWebBundle:Currency')->findAll();
$arr = array('currencies' => $currencies);
$form = $this->createFormBuilder($arr)
->add('currencies', 'collection', array(
'type' => new CurrencyType(),
'allow_add' => true,
'allow_delete' => true,
'by_reference' => false,
))
->add('submit', 'button', array('label' => 'Odeslat'))
->getForm();
return array(
'form' => $form->createView(),
);
}
}
CurrencyType
class CurrencyType extends AbstractType {
/**
* #param FormBuilderInterface $builder
* #param array $options
*/
public function buildForm(FormBuilderInterface $builder, array $options) {
$builder
->add('abbreviation', 'text')
->add('rate', 'number')
;
}
/**
* #param OptionsResolverInterface $resolver
*/
public function setDefaultOptions(OptionsResolverInterface $resolver) {
$resolver->setDefaults(array(
'data_class' => 'My\WebBundle\Entity\Currency'
));
}
/**
* #return string
*/
public function getName() {
return 'currency';
}
}
Twig
{% extends '::base.html.twig' %}
{% block body -%}
<h1>Test</h1>
{{ form(form) }}
{% endblock %}
If I use form class for CurrenciesType, then Symfony throws exception
Notice: Object of class My\WebBundle\Entity\Currency could not be converted to int in
....\web\vendor\symfony\symfony\src\Symfony\Component\
Form\Extension\Core\ChoiceList\ChoiceList.php line 462
Code for this is below.
CurrencyController
class CurrencyController extends Controller {
/**
* #Template()
*/
public function testAction() {
$em = $this->getDoctrine()->getManager();
$currencies = $em->getRepository('MyWebBundle:Currency')->findAll();
$arr = array('currencies' => $currencies);
$form = $this->createForm(new CurrenciesType(), $arr);
return array(
'form' => $form->createView(),
);
}
}
CurrenciesType
class CurrenciesType extends AbstractType {
/**
* #param FormBuilderInterface $builder
* #param array $options
*/
public function buildForm(FormBuilderInterface $builder, array $options) {
$builder
->add('currencies', 'collection', array(
'type' => new CurrencyType(),
'allow_add' => true,
'allow_delete' => true,
'by_reference' => false,
))
->add('submit', 'button', array('label' => 'Send'))
;
}
/**
* #param OptionsResolverInterface $resolver
*/
public function setDefaultOptions(OptionsResolverInterface $resolver) {
$resolver->setDefaults(array(
'data_class' => null
));
}
/**
* #return string
*/
public function getName() {
return 'my_webbundle_currencies';
}
}
CurrencyType and Twig are same as above.
I found solution these solution #1 solution #2, but my symfony still throws exception as above and I don't see different in my solution and these solutions. Please help with this problem. Thank you all :)