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';
}
Related
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.
On Symfony 2.8, I got the following entities:
Contact:
class Contact
{
/**
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue
*/
protected $id;
/**
* #ORM\Column
* #Assert\NotBlank
*/
protected $name;
/**
* #ORM\OneToMany(targetEntity="EmailContact", mappedBy="contact", cascade={"persist"})
* #Assert\Valid
*/
protected $emails;
// ...
/**
* Add emails
*
* #param \AppBundle\Entity\EmailContact $emails
* #return Contact
*/
public function addEmail(\AppBundle\Entity\EmailContact $emails)
{
$this->emails[] = $emails;
$emails->setContact($this); //this line added by me
return $this;
}
// ...
EmailContact:
class EmailContact
{
/**
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue
*/
protected $id;
/**
* #ORM\Column
* #Assert\NotBlank
*/
protected $email;
/**
* #ORM\ManyToOne(targetEntity="Contact", inversedBy="emails")
* #ORM\JoinColumn(nullable=false)
*/
protected $contact;
// ...
The rest of the methods were automatically generated by the doctrine:generate:entities command.
My forms are as follows:
ContactType:
class ContactType extends AbstractType
{
/**
* #param FormBuilderInterface $builder
* #param array $options
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('name', null, [
'label' => 'contact.name',
])
->add('emails', CollectionType::class, [
'label' => false,
'entry_options' => array('label' => false),
'entry_type' => EmailContactType::class,
'allow_add' => true,
'allow_delete' => true,
'delete_empty' => true,
'prototype' => true,
])
;
}
/**
* #param OptionsResolver $resolver
*/
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults([
'data_class' => 'AppBundle\Entity\Contact'
]);
}
EmailContactType:
class EmailContactType extends AbstractType
{
/**
* #param FormBuilderInterface $builder
* #param array $options
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('email', EmailType::class, [
'label' => 'emailContact.email',
])
;
}
/**
* #param OptionsResolver $resolver
*/
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults([
'data_class' => 'AppBundle\Entity\EmailContact'
]);
}
I do the javascript to add extra fields to the request, and submit it. Example request (from Symfony Profiler):
[
name => test4,
emails => [
0 => [
email => t#t.t4
],
1 => [
email => t#t.t5
]
],
_token => ...
]
But I get the following error:
An exception occurred while executing 'INSERT INTO email_contact ...
SQLSTATE[23000]: Integrity constraint violation: 1048 Column 'contact_id' cannot be null
Debugging, I see that the addEmail method above never gets called. What is happening here?
You missed by_reference => false in form collection definition
->add('emails', CollectionType::class, [
'label' => false,
'entry_options' => array('label' => false),
'entry_type' => EmailContactType::class,
'allow_add' => true,
'allow_delete' => true,
'delete_empty' => true,
'prototype' => true,
'by_reference' => false; // <--- you missed this
]);
Take a look here
Your code should run as expected after this modification.
Moreover remember that if you have a setEmails() method inside Contact class, the framework end up to calling it and so you need (for each element of the collection) to set contact as well (as you're correctly doing in addEmails())
I want to embed a Collection of Forms. That works fine! But the problem is, that the validation of a non mapped field ist not working. The code:
UserType.php
class UserType extends AbstractType
{
/**
* #param FormBuilderInterface $builder
* #param array $options
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('contactPersons', CollectionType::class, array(
'entry_type' => ContactPersonCreateType::class,
'allow_add' => true,
'prototype' => true,
'cascade_validation' => true,
))
...
}
ContactPersonCreateType.php
class ContactPersonCreateType extends AbstractType
{
/**
* #param FormBuilderInterface $builder
* #param array $options
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('kind', 'text', array(
'mapped' => false,
'required' => true,
'constraints' => array(
new NotBlank(),
new Length(array('min' => 3)),
)
))
...
}
I don't know why, but it will not be validated!
Can somebody help?
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