Symfony Form Entity ManyToMany - php

I have entity Skill and ManyToMany Language and I need create form and in this form add name language for skill, now I add 'multiple'=>true, in form and have many language but when $form->isValid() I have error
This value is not valid.
in form
invalidValue={array}[2]
0 = "Java"
1 = "PHP"
Why in not valid I not understand ??
rhis is my entity skill
class Skill
{
use Timestampable;
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var string
*
* #ORM\Column(name="skill", type="string", length=255)
*/
private $skill;
/**
* #var \Artel\ProfileBundle\Entity\CodeDirectoryProgramLanguages
*
* #ORM\ManyToMany(targetEntity="CodeDirectoryProgramLanguages", inversedBy="skills")
*/
protected $language;
/**
* Constructor
*/
public function __construct()
{
$this->language = new \Doctrine\Common\Collections\ArrayCollection();
$this->platforms = new \Doctrine\Common\Collections\ArrayCollection();
$this->specialities = new \Doctrine\Common\Collections\ArrayCollection();
}
/**
* Add language
*
* #param \Artel\ProfileBundle\Entity\CodeDirectoryProgramLanguages $language
*
* #return Skill
*/
public function addLanguage(\Artel\ProfileBundle\Entity\CodeDirectoryProgramLanguages $language)
{
$this->language[] = $language;
return $this;
}
/**
* Remove language
*
* #param \Artel\ProfileBundle\Entity\CodeDirectoryProgramLanguages $language
*/
public function removeLanguage(\Artel\ProfileBundle\Entity\CodeDirectoryProgramLanguages $language)
{
$this->language->removeElement($language);
}
/**
* Get language
*
* #return \Doctrine\Common\Collections\Collection
*/
public function getLanguage()
{
return $this->language;
}
this is my form
class SkillType extends AbstractType
{
/**
* #param FormBuilderInterface $builder
* #param array $options
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('mainSkill','checkbox');
$builder->add('language','entity',
array(
'class'=>'Artel\ProfileBundle\Entity\CodeDirectoryProgramLanguages',
'multiple'=>true,
'property'=>'languages', )
);
$builder
->add('edit','submit')
;
}
/**
* #param OptionsResolverInterface $resolver
*/
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'Artel\ProfileBundle\Entity\Skill',
'csrf_protection' => false
));
}
/**
* #return string
*/
public function getName()
{
return 'skill';
}
}
and my action when $form->submit($request); have this error
/**
* Edit skill.
*
* #Route("/skills/edit/{id}", name="skill_edit")
* #Method({"GET", "POST"})
* #Template()
* #ParamConverter("entity", class="MyBundle:Skill")
*/
public function editSkillsAction(Request $request, $entity)
{
$em = $this->getDoctrine()->getManager();
$form = $this->createForm(new SkillType(), $entity);
if ($request->isMethod('POST')) {
$form->bind($request);
if ($form->isValid()) {
$em->persist($entity);
$em->flush();
return $this->redirect($this->generateUrl('skills_show'));
}
}
return array(
'debug' => true,
'form' => $form->createView(),
);
}
UPDATE
I try to add in form 'expanded' => true, and everything work, doctrine create ManyToMany relation in table. Maybe is there another way ?
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('mainSkill','checkbox');
$builder->add('language','entity',
array(
'class'=>'Artel\ProfileBundle\Entity\CodeDirectoryProgramLanguages',
'property'=>'languages',
'multiple'=>true,
'expanded' => true,
)
);
$builder
->add('edit','submit')
;
}

Related

Add selectbox with values of relation in Symfony

I'm a Symfony beginner and I'm eager to learn more about Symfony, that's why I started a learning project.
I have a many-to-one relation (Type has many Games, but Game has 1 Type), and I would like to show a select box with a list of "types" to choose from.
I get this error:
Could not load type "AppBundle\Form\choiceType"
This is my code:
GameController.php
<?php
namespace AppBundle\Controller;
use AppBundle\Entity\Game;
use AppBundle\Entity\Type;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Method;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;use Symfony\Component\HttpFoundation\Request;
/**
* Game controller.
*
* #Route("game")
*/
class GameController extends Controller
{
/**
* Lists all game entities.
*
* #Route("/", name="game_index")
* #Method("GET")
*/
public function indexAction()
{
$em = $this->getDoctrine()->getManager();
$games = $em->getRepository('AppBundle:Game')->findAll();
return $this->render('game/index.html.twig', array(
'games' => $games,
));
}
/**
* Creates a new game entity.
*
* #Route("/new", name="game_new")
* #Method({"GET", "POST"})
*/
public function newAction(Request $request)
{
$type = new Type();
$type->setName('test');
$game = new Game();
$game->setType($type);
$form = $this->createForm('AppBundle\Form\GameType', $game);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$em = $this->getDoctrine()->getManager();
$em->persist($type);
$em->persist($game);
$em->flush($game);
return $this->redirectToRoute('game_show', array('id' => $game->getId()));
}
return $this->render('game/new.html.twig', array(
'game' => $game,
'form' => $form->createView(),
));
}
/**
* Finds and displays a game entity.
*
* #Route("/{id}", name="game_show")
* #Method("GET")
*/
public function showAction(Game $game)
{
$deleteForm = $this->createDeleteForm($game);
return $this->render('game/show.html.twig', array(
'game' => $game,
'delete_form' => $deleteForm->createView(),
));
}
/**
* Displays a form to edit an existing game entity.
*
* #Route("/{id}/edit", name="game_edit")
* #Method({"GET", "POST"})
*/
public function editAction(Request $request, Game $game)
{
$deleteForm = $this->createDeleteForm($game);
$editForm = $this->createForm('AppBundle\Form\GameType', $game);
$editForm->handleRequest($request);
if ($editForm->isSubmitted() && $editForm->isValid()) {
$this->getDoctrine()->getManager()->flush();
return $this->redirectToRoute('game_edit', array('id' => $game->getId()));
}
return $this->render('game/edit.html.twig', array(
'game' => $game,
'edit_form' => $editForm->createView(),
'delete_form' => $deleteForm->createView(),
));
}
/**
* Deletes a game entity.
*
* #Route("/{id}", name="game_delete")
* #Method("DELETE")
*/
public function deleteAction(Request $request, Game $game)
{
$form = $this->createDeleteForm($game);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$em = $this->getDoctrine()->getManager();
$em->remove($game);
$em->flush($game);
}
return $this->redirectToRoute('game_index');
}
/**
* Creates a form to delete a game entity.
*
* #param Game $game The game entity
*
* #return \Symfony\Component\Form\Form The form
*/
private function createDeleteForm(Game $game)
{
return $this->createFormBuilder()
->setAction($this->generateUrl('game_delete', array('id' => $game->getId())))
->setMethod('DELETE')
->getForm()
;
}
}
Update #3:
GameType.php
<?php
namespace AppBundle\Form;
use Doctrine\DBAL\Types\TextType;
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
class GameType extends AbstractType
{
/**
* {#inheritdoc}
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add( 'name', EntityType::class, [
'class' => 'AppBundle:Game',
'choice_label' => 'name',
'label' => 'name'
] );
$builder
->add( 'name', EntityType::class, [
'class' => 'AppBundle:Type',
'choice_label' => 'name',
'multiple' => false,
'expanded' => false
] );
}
/**
* {#inheritdoc}
*/
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'AppBundle\Entity\Game'
));
}
/**
* {#inheritdoc}
*/
public function getBlockPrefix()
{
return 'appbundle_game';
}
}
Entity\Game.php
namespace AppBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Doctrine\Common\Collections\ArrayCollection;
/**
* Game
*
* #ORM\Table(name="game")
* #ORM\Entity(repositoryClass="AppBundle\Repository\GameRepository")
*/
class Game
{
/**
* #ORM\ManyToOne(targetEntity="Type", inversedBy="games")
* #ORM\JoinColumn(name="type_id", referencedColumnName="id")
*/
private $type;
/**
* #var int
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var string
*
* #ORM\Column(name="name", type="string", length=255, unique=true)
*/
private $name;
/**
* Get id
*
* #return int
*/
public function getId()
{
return $this->id;
}
/**
* Set name
*
* #param string $name
*
* #return Game
*/
public function setName($name)
{
$this->name = $name;
return $this;
}
/**
* Get name
*
* #return string
*/
public function getName()
{
return $this->name;
}
/**
* #return mixed
*/
public function getType()
{
return $this->type;
}
/**
* #param mixed $type
*/
public function setType($type)
{
$this->type = $type;
}
}
Entity\Type.php
namespace AppBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Doctrine\Common\Collections\ArrayCollection;
/**
* Type
*
* #ORM\Table(name="type")
* #ORM\Entity(repositoryClass="AppBundle\Repository\TypeRepository")
*/
class Type
{
/**
* #ORM\OneToMany(targetEntity="Game", mappedBy="type")
*/
private $games;
public function __construct()
{
$this->games = new ArrayCollection();
}
/**
* #var int
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var string
*
* #ORM\Column(name="name", type="string", length=255)
*/
private $name;
/**
* Get id
*
* #return int
*/
public function getId()
{
return $this->id;
}
/**
* Set name
*
* #param string $name
*
* #return Type
*/
public function setName($name)
{
$this->name = $name;
return $this;
}
/**
* Get name
*
* #return string
*/
public function getName()
{
return $this->name;
}
/**
* #return mixed
*/
public function getGames()
{
return $this->games;
}
/**
* #param mixed $games
*/
public function setGames($games)
{
$this->games = $games;
}
}
If you are using the symfony form component, then choiceType isn't correct. the class is ChoiceType, simply capitalize the C and add the use statement above class declaration.
EDIT: You also need to update your form component type if you are selecting an existing entity for that field.
use Symfony\Component\Form\Extension\Core\Type\EntityType;
class GameType extends AbstractType
{
/**
* {#inheritdoc}
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('name');
$builder
->add( 'types', EntityType::class, [
'class' => 'AppBundle:Type',
'choice_label' => 'name',
'multiple' => false,
'expanded' => true
] );
}
extra reading on using entities and forms Symfony Docs
In your case, You should use EntityType instead of ChoiseType.
$builder
->add('type', EntityType::class, [
'class' => Type::class,
'choice_label' => 'name',
'multiple' => false,
'expanded' => true
Be aware of upper or lower.

symfony2 embedded form collection and entity mapping

I was following the symfony2 tutorial on how to create an embedded form collection but wasn't able to implement it since it only creates a junction table.
According to doctrine2 documentation:
"Why are many-to-many associations less common? Because frequently you want to associate additional attributes with an association, in which case you introduce an association class. Consequently, the direct many-to-many association disappears and is replaced by one-to-many/many-to-one associations between the 3 participating classes."
Here are some snippets of my code:
src/AppBundle/Entity/Ingredient.php
/**
* Defines the properties of the Ingredient entity to represent the portal ingredients.
*
* #author furious_snail
*
* #ORM\Entity()
* #ORM\Table(name="ingredients")
* #UniqueEntity("name")
*/
class Ingredient
{
/**
* #ORM\Id()
* #ORM\Column(type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #ORM\ManyToOne(targetEntity="IngredientCategory")
* #ORM\JoinColumn(name="category_id", referencedColumnName="id", nullable=true)
*/
private $category;
/**
* #ORM\Column(type="string", unique=true)
*/
private $name;
/**
* #ORM\OneToMany(targetEntity="IngredientNutrient", mappedBy="ingredient", cascade={"persist", "remove"})
*/
private $nutrientsPer100G;
public function __construct()
{
$this->substitute = new ArrayCollection();
$this->nutrientsPer100G = new ArrayCollection();
}
public function getId()
{
return $this->id;
}
public function setName($name)
{
$this->name = $name;
}
public function getName()
{
return $this->name;
}
/**
* #param mixed $nutrientsPer100G
*/
public function setNutrientsPer100G($nutrientsPer100G)
{
$this->nutrientsPer100G = $nutrientsPer100G;
}
/**
* #return array
*/
public function getNutrientsPer100G()
{
return $this->nutrientsPer100G;
}
}
src/AppBundle/Entity/IngredientNutrient.php
/**
* #ORM\Entity()
* #ORM\Table(name="ingredient_nutrient")
*/
class IngredientNutrient
{
/**
* #ORM\Id()
* #ORM\Column(type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var integer
*
* #ORM\ManyToOne(targetEntity="Ingredient", inversedBy="nutrientsPer100G")
* #ORM\JoinColumn(name="ingredient_id", referencedColumnName="id", nullable=true)
*/
protected $ingredient;
/**
* #var integer
*
* #ORM\ManyToOne(targetEntity="Nutrient")
* #ORM\JoinColumn(name="nutrient_id", referencedColumnName="id", nullable=true)
*/
protected $nutrient;
/**
* #ORM\Column(type="float")
*/
private $quantity;
/**
* #ORM\ManyToOne(targetEntity="Unit")
* #ORM\JoinColumn(name="unit_id", referencedColumnName="id", nullable=true)
*/
private $unit;
/**
* #return mixed
*/
public function getId()
{
return $this->id;
}
/**
* #return mixed
*/
public function getIngredient()
{
return $this->ingredient;
}
/**
* #param mixed $ingredient
*/
public function setIngredient($ingredient)
{
$this->ingredient = $ingredient;
}
/**
* #return mixed
*/
public function getNutrient()
{
return $this->nutrient;
}
/**
* #param mixed $nutrient
*/
public function setNutrient($nutrient)
{
$this->nutrient = $nutrient;
}
/**
* #return mixed
*/
public function getQuantity()
{
return $this->quantity;
}
/**
* #param mixed $quantity
*/
public function setQuantity($quantity)
{
$this->quantity = $quantity;
}
/**
* #return mixed
*/
public function getUnit()
{
return $this->unit;
}
/**
* #param mixed $unit
*/
public function setUnit($unit)
{
$this->unit = $unit;
}
}
src/AppBundle/Form/Type/IngredientNutrientType.php
class IngredientNutrientType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('nutrient', 'entity', array(
'class' => 'AppBundle\Entity\Nutrient',
'choice_label' => 'name',
'label' => 'Nutrient',
))
->add('quantity', null, array('label' => 'Cantitate'))
->add('unit', 'entity', array(
'class' => 'AppBundle\Entity\Unit',
'choice_label' => 'unit',
'label' => 'Unitate de masura'
));
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'AppBundle\Entity\IngredientNutrient',
));
}
public function getName()
{
return 'app_ingredient_nutrient';
}
}
src/AppBundle/Form/Type/IngredientType.php
class IngredientType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('name', null, array('label' => 'Name'))
->add('nutrients_per_100_g', 'collection', array(
'type' => new IngredientNutrientType(),
'allow_add' => true,
'label' => 'Nutrient quantity per 100g',
'options' => array('label' => false),
));
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'AppBundle\Entity\Ingredient',
));
}
public function getName()
{
return 'app_ingredient';
}
}
This works, I do get an embedded form collection but the issue is that the ingredient_id in the ingredient_nutrient table is null. How do I make it to fill the table with the right ID?
These are the fields I get on the page:
Name:
Nutrient:
Quantity:
Unit:
The idea is that if I have IngredientNutrient form tied with Ingredient form the user shouldn't have to specify ingredient name twice.
Thank you.
To start with, you need to "cross reference" your entities:
public function setNutrientsPer100G($nutrientsPer100G)
{
$this->nutrientsPer100G = $nutrientsPer100G;
$nutrientsPer100G->setIngrediant($this);
}
Make sure both sides of the relation are being set. That will take care of the null id issues.
The other problem is that you are using collections in your Ingrediant/Nutrient entities but your set methods are not using the array operators.

How to use FormType and ManyToMany relationships with FOSRestBuendle

I'm developing a RESTful web service using Symfony with FOSRestBundle
From the front end I have a form that creates fields and sends to the server with the follow format:
{"targets":[1,3],"title":"This is a title","price":1200000,"description":"This is a description"}
The key targets has TargetField ids. With the below code I get a response with status code 500 saying that foreach argument is invalid (See FieldType->buildForm())
Field
/**
* #ORM\Table(name="field")
* #ORM\Entity
*/
class Field extends Property {
/**
* #var integer
*
* #ORM\Column(name="id", type="integer", nullable=false)
* #ORM\Id
* #ORM\GeneratedValue(strategy="IDENTITY")
*/
private $id;
/**
* #ORM\ManyToMany(targetEntity="FieldTarget")
* #ORM\JoinTable(name="relFieldTarget",
* joinColumns={#ORM\JoinColumn(name="fieldId", referencedColumnName="id")},
* inverseJoinColumns={#ORM\JoinColumn(name="fieldTargetId", referencedColumnName="id")}
* )
* */
private $targets;
public function __construct() {
$this->targets = new \Doctrine\Common\Collections\ArrayCollection();
}
public function getTargets() {
return $this->targets;
}
}
FieldTarget
/**
* #ORM\Table(name="fieldTarget")
* #ORM\Entity
*/
class FieldTarget
{
/**
* #var integer
*
* #ORM\Column(name="id", type="integer", nullable=false)
* #ORM\Id
* #ORM\GeneratedValue(strategy="IDENTITY")
*/
private $id;
/**
* #var string
* #ORM\Column(name="title", type="string")
**/
private $title
}
FieldType
class FieldType extends PropertyType {
private $manager;
function __construct(ObjectManager $manager){
$this->manager = $manager;
}
/**
* #param FormBuilderInterface $builder
* #param array $options
*/
public function buildForm(FormBuilderInterface $builder, array $options) {
parent::buildForm($builder, $options);
$builder
->add('targets');
$builder
->get('targets')
->addModelTransformer(new CallbackTransformer(
function($fieldTargetIds) { // $fieldTargetIds is empty. WHY!?
$fieldTargetRepo = $this->manager->getRepository('FooBundle:FieldTarget');
foreach($fieldTargetIds as $id){
$fieldTarget[] = $fieldTargetRepo->find($id);
}
return $fieldTargets; // Here I'm tried hardcoding array($fieldTargetRepo->find(1)) and the field is created but is not related with the fieldTarget 1
},
function() {
}));
}
/**
* #param OptionsResolverInterface $resolver
*/
public function setDefaultOptions(OptionsResolverInterface $resolver) {
$resolver->setDefaults(array(
'data_class' => 'Cboujon\PropertyBundle\Entity\Field'
));
}
}
FieldController
/**
* Create a Field entity.
*
* #View(statusCode=201, serializerEnableMaxDepthChecks=true)
*
* #param Request $request
*
* #return Response
*
*/
public function postAction(Request $request) {
$entity = new Field();
$form = $this->createForm(new FieldType($this->getDoctrine()->getManager()), $entity, array("method" => $request->getMethod()));
$this->removeExtraFields($request, $form);
$form->handleRequest($request);
if ($form->isValid()) {
$em = $this->getDoctrine()->getManager();
$em->persist($entity);
$em->flush();
return $entity;
}
return FOSView::create(array('errors' => $form->getErrors()), Codes::HTTP_INTERNAL_SERVER_ERROR);
}
You are putting the code in the wrong function. The first function in a callback transformer transforms from the model into the view and the second transforms from the view into the model. In this case you are trying to add code for the second operation. Change your code to :
->addModelTransformer(new CallbackTransformer(
function($fieldTargets) {
//TODO: code to transform from the model into the view
},
function($fieldTargetIds) {
$fieldTargetRepo = $this->manager->getRepository('FooBundle:FieldTarget');
foreach($fieldTargetIds as $id){
$fieldTarget[] = $fieldTargetRepo->find($id);
}
return $fieldTargets;
}));

Symfony2 relationship between two entities

I want to make a relationship between two entities but for some reason I am getting NULL on one of the values...
So in my skin entity I have an email_registration_id field with the relationship :
/**
* #ORM\ManyToOne(targetEntity="Project\UserBundle\Entity\Email")
* #ORM\JoinColumn(name="email_registration_id", referencedColumnName="id")
*/
protected $email_registration_id;
/**
* Set email_registration_id
*
* #param \Project\UserBundle\Entity\Email $email_registration_id
* #return Skin
*/
public function setEmailRegistrationId(\Project\UserBundle\Entity\Email $email_registration_id = null)
{
$this->email_registration_id = $email_registration_id;
return $this;
}
/**
* Get email_registration_id
*
* #return \Project\UserBundle\Entity\Email
*/
public function getEmailRegistrationId()
{
return $this->email_registration_id;
}
And this is the Email entity:
/**
* Project\UserBundle\Entity\Email
*
* #ORM\Entity
* #ORM\Table(name="email")
*/
class Email {
/**
* #var integer $id
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* #var string $title
*
* #ORM\Column(name="title", type="string")
*/
protected $title;
/**
* #var string $registration_content
*
* #ORM\Column(name="registration_content", type="string")
*/
protected $registration_content;
/**
* #var string $confirmation_apuestas
*
* #ORM\Column(name="confirmation_apuestas", type="string")
*/
protected $confirmation_apuestas;
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
public function setId() {
$this->id = null;
}
/**
* Set title
*
* #param string $title
* #return Email
*/
public function setTitle($title)
{
$this->title = $title;
return $this;
}
/**
* Get title
*
* #return string
*/
public function getTitle()
{
return $this->title;
}
/**
* Set registration_content
*
* #param string $registration_content
* #return Email
*/
public function setRegistrationContent($registration_content)
{
$this->registration_content = $registration_content;
return $this;
}
/**
* Get registration_content
*
* #return string
*/
public function getRegistrationContent()
{
return $this->registration_content;
}
/**
* Set $confirmation_apuestas
*
* #param string $confirmation_apuestas
* #return Email
*/
public function setConfirmationApuestas($confirmation_apuestas)
{
$this->confirmation_apuestas = $confirmation_apuestas;
return $this;
}
/**
* Get $confirmation_apuestas
*
*
#return string
*/
public function getConfirmationApuestas()
{
return $this->confirmation_apuestas;
}
}
Now in my cms i create a new email like this:
/**
* #Route("/new", name="cms_email_new")
* #Method({"GET"})
* #Template()
*/
public function newAction() {
$item = new Email();
$form = $this->createForm(new EmailType($this->container->getParameter("langs")), $item);
return array('form' => $form->createView(), 'item' => $item);
}
The form:
public function buildForm(FormBuilderInterface $builder, array $option) {
$builder->add('title', 'text', array('label' => 'cms.Title'));
$builder->add('registration_content', 'textarea', array('label' => 'cms.registration.content'));
$builder->add('confirmation_apuestas', 'textarea', array('label' => 'cms.confirmation.apuestas'));
}
public function getDefaultOptions(array $options) {
return array(
'data_class' => 'Project\UserBundle\Entity\Email',
);
}
This is how I persist the Email to the database:
/**
* #Route("/save", name="cms_email_save")
* #Template("ProjectUserBundle:EmailAdmin:new.html.twig")
* #Method({"POST"})
*/
public function saveAction(Request $request) {
$item = new Email();
$type = new EmailType($this->container->getParameter("langs"));
$form = $this->createForm($type, $item);
$form->bind($request);
$em = $this->getEntityManager();
if ($form->isValid()) {
$this->upload($form, $item);
$em->persist($item);
$em->flush();
return $this->redirect($this->generateUrl('cms_skin_email_list', array('skin_id' => $item->getId())));
}
return array('form' => $form->createView(), 'item' => $item);
}
The problem is that it creates an email, but in my skin entity, the email_registration_id is just NULL and not the same as emails Id... Maybe I missed something?
UPDATE
So this is what I made according to the responses I got:
class Email {
/**
* #ORM\OneToMany(targetEntity="Project\SkinBundle\Entity\Skin", mappedBy="email_registration_id")
*/
protected $skin;
/**
* Set skin
*
* #param string $skin
* #return Email
*/
public function setSkin(\Project\SkinBundle\Entity\Skin $skin = null)
{
$this->skin = $skin;
return $this;
}
/**
* Get skin
*
* #return string
*/
public function getSkin()
{
return $this->skin;
}
And the form:
public function buildForm(FormBuilderInterface $builder, array $option) {
$builder->add('title', 'text', array('label' => 'cms.Title'));
$builder->add('registration_content', 'textarea', array('label' => 'cms.registration.content'));
$builder->add('confirmation_apuestas', 'textarea', array('label' => 'cms.confirmation.apuestas'));
$builder->add('skin', 'entity', array(
'class' => 'ProjectSkinBundle:Skin',
'property' => 'id',
));
}
However when i am trying to flush to the database I get this error:
ContextErrorException: Catchable Fatal Error: Argument 1 passed to Doctrine\Common\Collections\ArrayCollection::__construct() must be of the type array, object given, called in C:\wamp\www\Company\front\vendor\doctrine\orm\lib\Doctrine\ORM\UnitOfWork.php on line 528 and defined in C:\wamp\www\Company\front\vendor\doctrine\collections\lib\Doctrine\Common\Collections\ArrayCollection.php line 48
It's normal that the creation of a new email is not associated to a skin object. How could it ? The relation is unidirectional, and only works when you create a skin and you give it an email. To create an email and give it a skin, you have to make the relation bidirectional, and add it to your email form.
To do this, I'd do the following :
/*
* Class Project\UserBundle\Entity\Email
*/
class Email {
...
/**
* #ORM\OneToMany(targetEntity="Project\SkinBundle\Entity\Skin", mappedBy="email_registration_id")
*/
protected $skin;
and in your form :
public function buildForm(FormBuilderInterface $builder, array $option) {
$builder->add('title', 'text', array('label' => 'cms.Title'))
->add('registration_content', 'textarea', array('label' => 'cms.registration.content'))
->add('confirmation_apuestas', 'textarea', array('label' => 'cms.confirmation.apuestas'))
->add('skin')
;
}
And PS : You should not use the bind() method to handle the request, it is deprecated. Instead use :
$form->handleRequest($request);
UPDATE 1 : Don't forget to also update your ManyToOne annotation adding the inversedBy part :
#ORM\ManyToOne(targetEntity="Project\UserBundle\Entity\Email", inversedBy="skin")
And also, of course, update your database.

Allow all value on choice field type in Symfony2 form builder

I have a problem for a while and I have read a lot on this topic with similar problem but cant implement the answers in my case.
I have a select field that I populate with Ajax. so in my form builder I have this code :
VilleType.php
/**
* #ORM\Entity(repositoryClass="MDB\AnnonceBundle\Entity\RegisterRepository")
*/
class VilleType extends AbstractType {
/**
* #param FormBuilderInterface $builder
* #param array $options
*/
public function buildForm(FormBuilderInterface $builder, array $options) {
$builder
->add('nomComplet', 'choice'
);
}
/**
* #param OptionsResolverInterface $resolver
*/
public function setDefaultOptions(OptionsResolverInterface $resolver) {
$resolver->setDefaults(array(
'data_class' => 'MDB\AdresseBundle\Entity\Ville'
));
}
/**
* #return string
*/
public function getName() {
return 'mdb_adressebundle_ville';
}
}
But my form never validates because their is no value in this choice field. But I can't add the value inside cause I don't know in advance what user will enter as a value.
So my question is how to disable verification on this field from Symfony. Or allow it to accept all value.
Thanks
EDIT
Here, I tried a new approach. I use The event Listener to modify my field with the value than the user submitted.
public function buildForm(FormBuilderInterface $builder, array $options) {
$builder
->add('nomComplet', 'choice');
$builder->get('nomComplet')->addEventListener(
FormEvents::PRE_SUBMIT, function(FormEvent $event) /* use ($formModifier) */ {
$ville = $event->getData();
$event->getForm()->add('nomComplet', 'choice', array('choices' => $ville));
// $formModifier($event->getForm()->getParent(), $ville);
}
);
}
/**
* #param OptionsResolverInterface $resolver
*/
public function setDefaultOptions(OptionsResolverInterface $resolver) {
$resolver->setDefaults(array(
'data_class' => 'MDB\AdresseBundle\Entity\Ville'
));
}
/**
* #return string
*/
public function getName() {
return 'mdb_adressebundle_ville';
}
}
MDB\AdresseBundle\Entity\Ville.php
<?php
namespace MDB\AdresseBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* Ville
*
* #ORM\Table()
* #ORM\Entity(repositoryClass="MDB\AdresseBundle\Entity\VilleRepository");
*/
class Ville
{
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var string
*
* #ORM\Column(name="nomComplet", type="string", length=255)
*/
private $nomComplet;
/**
* #var string
*
* #ORM\Column(name="nomClean", type="string", length=255)
*/
private $nomClean;
/**
* #var array
*
* #ORM\Column(name="cp", type="simple_array")
*/
private $cp;
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set nomComplet
*
* #param string $nomComplet
* #return Ville
*/
public function setNomComplet($nomComplet)
{
$this->nomComplet = $nomComplet;
return $this;
}
/**
* Get nomComplet
*
* #return string
*/
public function getNomComplet()
{
return $this->nomComplet;
}
/**
* Set nomClean
*
* #param string $nomClean
* #return Ville
*/
public function setNomClean($nomClean)
{
$this->nomClean = $nomClean;
return $this;
}
/**
* Get nomClean
*
* #return string
*/
public function getNomClean()
{
return $this->nomClean;
}
/**
* Set cp
*
* #param array $cp
* #return Ville
*/
public function setCp($cp)
{
$this->cp = $cp;
return $this;
}
/**
* Get cp
*
* #return array
*/
public function getCp()
{
return $this->cp;
}
public function __toString()
{
return $this->nomComplet;
}
}
But still its not working, I have following error:
You cannot add children to a simple form. Maybe you should set the option "compound" to true?
So if someone know how to use this way with Event Listener it would be great.
Thanks
This should work
https://github.com/LPodolski/choiceAjaxLoad/blob/master/src/AppBundle/Form/ItemType.php
Entire project demonstrating this case:
https://github.com/LPodolski/choiceAjaxLoad
Code in case file is removed/altered:
/**
* #param FormBuilderInterface $builder
* #param array $options
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('choiceField', 'choice', array(
'attr' => array(
'class' => 'choiceField'
)
))
;
$builder->addEventListener(FormEvents::PRE_SUBMIT, function(FormEvent $event) {
$form = $event->getForm();
$data = $event->getData();
$form->remove('choiceField');
$form->add('choiceField', 'choice', array(
'attr' => array(
'class' => 'choiceField',
),
'choices' => array(
$data['choiceField'] => $data['choiceField'],
)
));
});
$builder->add('save', 'submit');
}
So my question is how to disable verification on this field from Symfony.
According to the Documentation you can suppress form validation by using the POST_SUBMIT event and prevent the ValidationListener from being called.
$builder->addEventListener(FormEvents::POST_SUBMIT, function (FormEvent $event) {
$event->stopPropagation();
}, 900); // Always set a higher priority than ValidationListener

Categories