How to merge 2 form in Symfony2 - forms

I'm trying to create a very simple forum with Symfony2.
My entities are:
ForumCategory (name, description...)
ForumTopic (category_id, title)
ForumPost (isFirstPost, body, topic_id, author_id...)
When a user try to create a Topic, I want to display only one form in the same page to create a Topic and the first post message. Like:
Insert topic title: ...
Insert topic body (related Post Body): ...
[...]
How can I do that? It's possible merge two form in this case?

Make a form type that contains both of your sub forms.
class MergedFormType
$builder->add('topic', new TopicFormType());
$builder->add('post', new PostFormType());
In your controller just pass an array to MergedFormType
public function myAction()
$formData['topic'] = $topic;
$formData['post'] = $post;
$form = $this->createForm(new MergedFormType(), $formData);

Incase if you are looking to merge forms for 2 entities with one to many or one to one relationship; you will need to use form collection extension of symfony 2 component. for eg: where Task entity has many Tags
class TaskType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('description');
$builder->add('tags', 'collection', array('type' => new TagType()));
}
Rendering can be done this way
{{ form_start(form) }}
<h3>Tags</h3>
<ul class="tags">
{# iterate over each existing tag and render its only field: name #}
{% for tag in form.tags %}
<li>{{ form_row(tag.name) }}</li>
{% endfor %}
</ul>
Further details:
http://symfony.com/doc/2.7/cookbook/form/form_collections.html

You can also map the same entity to multiple merged forms.
$entity = new Form();
$form = $this->get('form.factory')->create(FormType::class, [
'form_builder' => $entity,
'submit_builder' => $entity,
]);
FormType.php
<?php
namespace GenyBundle\Form\Type;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Form\Extension\Core\Type;
use Symfony\Component\OptionsResolver\OptionsResolver;
use GenyBundle\Entity\Form;
class FormType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('form_builder', FormBuilderType::class, [
'data_class' => Form::class,
'label' => false, // Important!
])
->add('submit_builder', SubmitBuilderType::class, [
'data_class' => Form::class,
'label' => false,
])
->add('save', Type\SubmitType::class, [
'label' => 'geny.type.form.save.label',
])
;
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults([
'translation_domain' => 'geny',
]);
}
}
FormBuilderType.php
<?php
namespace GenyBundle\Form\Type;
use GenyBundle\Base\BaseType;
use Symfony\Component\Form\Extension\Core\Type;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
class FormBuilderType extends BaseType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('title', Type\TextType::class, [
'attr' => [
'placeholder' => 'geny.type.form.title.placeholder',
],
'empty_data' => $this->get('translator')->trans('geny.type.form.title.default', [], 'geny'),
'label' => 'geny.type.form.title.label',
'required' => true,
])
->add('description', Type\TextareaType::class, [
'attr' => [
'placeholder' => 'geny.type.form.description.placeholder',
],
'empty_data' => null,
'label' => 'geny.type.form.description.label',
'required' => false,
])
;
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults([
'data_class' => 'GenyBundle\Entity\Form',
'translation_domain' => 'geny',
]);
}
}
SubmitBuilderType.php
<?php
namespace GenyBundle\Form\Type;
use GenyBundle\Base\BaseType;
use Symfony\Component\Form\Extension\Core\Type;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
class SubmitBuilderType extends BaseType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('submit', Type\TextType::class, [
'attr' => [
'placeholder' => 'geny.type.submit.submit.placeholder',
],
'empty_data' => $this->get('translator')->trans('geny.type.submit.submit.default', [], 'geny'),
'label' => 'geny.type.submit.submit.label',
'required' => true,
])
;
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults([
'data_class' => 'GenyBundle\Entity\Form',
'translation_domain' => 'geny',
]);
}
}
Form.php
<?php
namespace GenyBundle\Entity;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\ORM\Mapping as ORM;
use JMS\Serializer\Annotation as Serializer;
use Symfony\Component\Validator\Constraints as Assert;
/**
* #ORM\Table(name="geny_form")
* #ORM\Entity(repositoryClass="GenyBundle\Repository\FormRepository")
* #ORM\ChangeTrackingPolicy("DEFERRED_EXPLICIT")
* #Serializer\ExclusionPolicy("NONE")
*/
class Form
{
/**
* #var int
*
* #ORM\Column(name="id", type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
* #ORM\Id
* #Serializer\Exclude
*/
protected $id;
/**
* #var string
*
* #ORM\Column(name="title", type="string", length=128)
* #Assert\Length(min = 1, max = 128)
* #Serializer\Type("string")
*/
protected $title;
/**
* #var string
*
* #ORM\Column(name="description", type="text", nullable=true)
* #Assert\Length(min = 0, max = 4096)
* #Serializer\Type("string")
*/
protected $description;
/**
* #var ArrayCollection
*
* #ORM\OneToMany(targetEntity="Field", mappedBy="form", cascade={"all"}, orphanRemoval=true)
* #ORM\OrderBy({"position" = "ASC"})
* #Assert\Valid()
* #Serializer\Type("ArrayCollection<GenyBundle\Entity\Field>")
*/
protected $fields;
/**
* #var string
*
* #ORM\Column(name="submit", type="text")
* #Assert\Length(min = 1, max = 64)
* #Serializer\Type("string")
*/
protected $submit;
}
Result:

Related

Symfony : OrderBy in CollectionType

I have two tables (Player & Historique) that have a OneToMany association. In my PlayerType form, I have a CollectionType with an entry_type to my HistoriqueType. My question is about the order in which the data from HistoriqueType arrives. For the moment, it appears in ASC order of the id. But I would like it to appear in ASC order of the years (season).
Here are my two entities :
<?php
/**
* #ORM\Entity(repositoryClass=PlayerRepository::class)
*/
class Player
{
/**
* #ORM\Id
* #ORM\GeneratedValue
* #ORM\Column(type="integer")
*/
private $id;
/**
* #ORM\Column(type="string", length=255)
*/
private $name;
/**
* #ORM\OneToMany(targetEntity=Historique::class, mappedBy="player", cascade={"persist"}, orphanRemoval = true)
*/
public $playerHistoriques;
public function __construct()
{
$this->playerHistoriques = new ArrayCollection();
}
And my Historique Class :
<?php
/**
* #ORM\Entity(repositoryClass=HistoriqueRepository::class)
*/
class Historique
{
/**
* #ORM\Id
* #ORM\GeneratedValue
* #ORM\Column(type="integer")
*/
private $id;
/**
* #ORM\ManyToOne(targetEntity=Club::class, inversedBy="historiques")
* #ORM\JoinColumn(nullable=true)
*/
private $club;
/**
* #ORM\ManyToOne(targetEntity=Season::class, inversedBy="historiques")
* #ORM\JoinColumn(nullable=true)
* #ORM\OrderBy({"season" = "ASC"})
*/
private $season;
/**
* #ORM\ManyToOne(targetEntity=Player::class, inversedBy="playerHistoriques")
* #ORM\JoinColumn(nullable=true)
*/
private $player;
/**
* #ORM\ManyToOne(targetEntity=Position::class, inversedBy="historiques")
*/
private $position;
My PlayerType :
<?php
class PlayerType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('name')
->add('playerHistoriques', CollectionType::class, [
'entry_type' => HistoriqueType::class,
'entry_options' => [
'label' => false
],
'by_reference' => false,
'allow_add' => true
])
;
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults([
'data_class' => Player::class,
]);
}
}
And My HistoriqueType:
<?php
class HistoriqueType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('club', EntityType::class, [
'class' => Club::class,
'choice_label' => 'name',
'label' => false,
'required' => false,
'placeholder' => '-',
'query_builder' => function (EntityRepository $er) {
return $er->createQueryBuilder('c')
->orderBy('c.name', 'ASC');
}
])
->add('season', EntityType::class, [
'class' => Season::class,
'choice_label' => 'year',
'label' => false,
'placeholder' => '-',
'query_builder' => function (EntityRepository $er) {
return $er->createQueryBuilder('s')
->orderBy('s.year', 'ASC');
}
])
->add('position', EntityType::class, [
'class' => Position::class,
'choice_label' => 'position',
'label' => false,
'placeholder' => '-',
'required' => false
])
;
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults([
'data_class' => Historique::class,
'method' => 'get',
'csrf_protection' => false
]);
}
public function getBlockPrefix() {
return '';
}
}
In my edit form, I would like to order my collectionType by 'season' => 'ASC', in order to have the years in chronological order even in my edit form.
I have tried a query_builder like so in my PlayerType :
'query_builder' => function (EntityRepository $er) {
return $er->createQueryBuilder('h')
->orderBy('h.season', 'ASC');
}
But it generated an error since collectionTypes cannot have queries in them.
I have tried to order it automatically in my PlayerEntity #ORM\OrderBy({"season" = "ASC"}) but it didn't work.
In your Historique Entity change the order by to year instead of season (I believe in your other form you are sorting by the year so hopefully this is the property you are looking to sort by).
/**
* #ORM\ManyToOne(targetEntity=Season::class, inversedBy="historiques")
* #ORM\JoinColumn(nullable=true)
* #ORM\OrderBy({"year" = "ASC"})
*/
private $season;
You should be able to remove the query builder now, unless you need to narrow the selection.
OrderBy must be in Palyer entity in OneToMany relation not in Historique
/**
*#ORM\OneToMany(targetEntity=Historique::class, mappedBy="player", cascade={"persist"}, orphanRemoval = true)
*#ORM\OrderBy({"season" = "ASC"})
*/
public $playerHistoriques;

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.

Form Subscriber and "this form should not contain extra fields" error

I'm using symfony 2.3, so apparently, I can't use the 'allow_extra_fields' option discussed here.
I have a main Form Type, RegistrationStep1UserType :
/**
* Class RegistrationStep1UserType
* #package Evo\DeclarationBundle\Form\Type
*/
class RegistrationStep1UserType extends AbstractType
{
/**
* #param FormBuilderInterface $builder
* #param array $options
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('customer', new RegistrationStep1CustomerType(), [
'label' => false,
'data_class' => 'Evo\UserBundle\Entity\Customer',
'cascade_validation' => true,
])
->add('declaration', 'evo_declaration_bundle_registration_step1_declaration_type', [
'label' => false,
'cascade_validation' => true,
])
;
}
/**
* #param OptionsResolverInterface $resolver
*/
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'Evo\UserBundle\Entity\User',
'validation_groups' => false,
));
}
/**
* #return string
*/
public function getName()
{
return 'evo_declaration_bundle_registration_step1_user_type';
}
}
This form type includes an embedded Form Type (on "declaration" field), RegistrationStep1DeclarationType, registered as a service :
/**
* Class RegistrationStep1DeclarationType
* #package Evo\DeclarationBundle\Form\Type
*/
class RegistrationStep1DeclarationType extends AbstractType
{
/**
* #var EntityManagerInterface
*/
private $em;
/**
* #var EventSubscriberInterface
*/
private $addBirthCountyFieldSubscriber;
/**
* RegistrationStep1DeclarationType constructor.
* #param EntityManagerInterface $em
* #param EventSubscriberInterface $addBirthCountyFieldSubscriber
*/
public function __construct(EntityManagerInterface $em, EventSubscriberInterface $addBirthCountyFieldSubscriber)
{
$this->em = $em;
$this->addBirthCountyFieldSubscriber = $addBirthCountyFieldSubscriber;
}
/**
* #param FormBuilderInterface $builder
* #param array $options
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('birthLastname', null, [
'label' => 'Nom de naissance',
'attr' => [
'required' => true,
],
])
->add('nationality', 'entity', [
'label' => 'Nationalité',
'class' => 'Evo\GeoBundle\Entity\Country',
'property' => 'nationalityFr',
'attr' => [
'required' => true,
'class' => 'selectpicker',
],
'preferred_choices' => $this->fillPreferredNationalities(),
])
->add('birthCountry', 'entity', [
'label' => 'Pays de naissance',
'class' => 'Evo\GeoBundle\Entity\Country',
'property' => 'nameFr',
'empty_value' => '',
'empty_data' => null,
'attr' => [
'required' => true,
'class' => 'trigger-form-modification selectpicker',
],
'preferred_choices' => $this->fillPreferredBirthCountries(),
])
->add('birthCity', null, [
'label' => 'Ville de naissance',
'attr' => [
'required' => true,
],
])
;
$builder->get("birthCountry")->addEventSubscriber($this->addBirthCountyFieldSubscriber);
}
/**
* #return array
*/
private function fillPreferredNationalities()
{
$nationalities = $this->em->getRepository("EvoGeoBundle:Country")->findBy(["isDefault" => true]);
return $nationalities;
}
/**
* #return array|\Evo\GeoBundle\Entity\Country[]
*/
private function fillPreferredBirthCountries()
{
$countries = $this->em->getRepository("EvoGeoBundle:Country")->findBy(["isDefault" => true]);
return $countries;
}
/**
* #param OptionsResolverInterface $resolver
*/
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array(
'required' => false,
'data_class' => 'Evo\DeclarationBundle\Entity\Declaration',
'validation_groups' => false,
));
}
/**
* #return string
*/
public function getName()
{
return 'evo_declaration_bundle_registration_step1_declaration_type';
}
}
This embedded Form Type adds a Subscriber (registered as a service too, because it needs injection of EntityManager) on the "birthCountry" field.
The goal is to dynamically add or remove an extra field (called "birthCounty") depending on the value of the birthCountry choice list (note the 2 fields are different here, "birthCountry" and "birthCounty").
Here is the Subscriber :
/**
* Class AddBirthCountyFieldSubscriber
* #package Evo\CalculatorBundle\Form\EventListener
*/
class AddBirthCountyFieldSubscriber implements EventSubscriberInterface
{
/**
* #var EntityManagerInterface
*/
private $em;
/**
* AddBirthCountyFieldSubscriber constructor.
* #param EntityManagerInterface $em
*/
public function __construct(EntityManagerInterface $em)
{
$this->em = $em;
}
/**
* #return array
*/
public static function getSubscribedEvents()
{
return array(
FormEvents::POST_SET_DATA => 'postSetData',
FormEvents::POST_SUBMIT => 'postSubmit',
);
}
/**
* #param FormEvent $event
*/
public function postSetData(FormEvent $event)
{
$birthCountry = $event->getData();
$form = $event->getForm()->getParent();
$this->removeConditionalFields($form);
if ($birthCountry instanceof Country && true === $birthCountry->getIsDefault()) {
$this->addBirthCountyField($form);
}
}
/**
* #param FormEvent $event
*/
public function postSubmit(FormEvent $event)
{
$birthCountry = $event->getData();
$form = $event->getForm()->getParent();
if (!empty($birthCountry)) {
$country = $this->em->getRepository("EvoGeoBundle:Country")->find($birthCountry);
$this->removeConditionalFields($form);
if ($country instanceof Country && true === $country->getIsDefault()) {
$this->addBirthCountyField($form);
}
}
}
/**
* #param FormInterface $form
*/
private function addBirthCountyField(FormInterface $form)
{
$form
->add('birthCounty', 'evo_geo_bundle_autocomplete_county_type', [
'label' => 'Département de naissance',
'attr' => [
'required' => true,
],
])
;
}
/**
* #param FormInterface $form
*/
private function removeConditionalFields(FormInterface $form)
{
$form->remove('birthCounty');
}
}
In the view, when the "birthCountry" choice list changes, it trigger an AJAX request to the controller, which handles the request and render the view again (as explained in the documentation about dynamic form submission) :
$form = $this->createForm(new RegistrationStep1UserType(), $user);
if ($request->isXmlHttpRequest()) {
$form->handleRequest($request);
} elseif ("POST" == $request->getMethod()) {
[...]
}
The problem is the following :
When I make a change on the birthCountry choice list and select a Country supposed to hide the "birthCounty" field, the form correctly render without that field, but it shows an error message :
Ce formulaire ne doit pas contenir des champs supplémentaires.
or
this form should not contain extra fields (in english)
I tried many different solutions :
adding a 'validation_groups' option to RegistrationStep1UserType and RegistrationStep1DeclarationType
adding a preSubmit event to AddBirthCountyFieldSubscriber replicating the logic of preSetData and postSubmit methods
even adding 'mapped' => false, to the birthCounty field triggers the error. very surprising
Even $form->getExtraData() is empty if I dump it just after $form->handleRequest($request);
But in vendor\symfony\symfony\src\Symfony\Component\Form\Extension\Validator\Constraints\FormValidator, I can see an extra field
array(1) {
["birthCounty"]=>
string(0) ""
}
here :
// Mark the form with an error if it contains extra fields
if (count($form->getExtraData()) > 0) {
echo '<pre>';
\Doctrine\Common\Util\Debug::dump($form->getExtraData());
echo '</pre>';
die();
$this->context->addViolation(
$config->getOption('extra_fields_message'),
array('{{ extra_fields }}' => implode('", "', array_keys($form->getExtraData()))),
$form->getExtraData()
);
}
Did I miss something about form dynamic extra fields ?
I did not analyzed all the question but, I guess, that you can invert the logic: always add that field and remove it when the condition is not satisfied.
That way you don't need to perform operations in postSubmit (that is where the issue is)

Add or remove fields in Symfony 3 form type according to the environment

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';
}
}

Symfony 2 - Form collection for one entity without parent entity

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 :)