Reputation: 365
I am having some issues when trying to create a form that embeds a collection of another entity.
I want to create a Recipe and for that purpose I want the user to be able to insert several Tags for that Recipe.
I've followed the current Symfony documentation and I am actually able to insert both entities Recipe and Tag, but for Tag entity, only id is actually inserted.
Here is what I've done so far:
RecipeType form:
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('name')
->add('recipe_tags', CollectionType::class, array(
'entry_type' => TagsType::class,
'allow_add' => true,
'by_reference' => false,
));
}
Which adds the collationType TagsType form that it's coded as follows:
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('name');
}
Then I create a tag object in the controller beforehand so the recipe entity has a default tag that will be updated after submit the form.
$recipe = new Recipe();
$tag = new Tags();
$tag->setName('tag1');
$recipe->addRecipeTag($tag);
$form = $this->get('form.factory')->createNamed(null, RecipeType::class,
$recipe);
And finally, the Recipe Entity with the (I think so) proper information:
/**
* @var \Doctrine\Common\Collections\Collection
*
* @ORM\ManyToMany(targetEntity="Tags", inversedBy="idRecipe", cascade=
{"persist"})
* @ORM\JoinTable(name="recipe_tags",
* joinColumns={
* @ORM\JoinColumn(name="id_recipe", referencedColumnName="id_recipe")
* },
* inverseJoinColumns={
* @ORM\JoinColumn(name="id_tag", referencedColumnName="id_tag")
* }
* )
* @Groups({"recipe_detail"})
*
*/
private $recipe_tags;
I added the cascade persist annotation following the documentation as well. Here is the method for adding tags.
/**
* Add recipeTag
*
* @param \AppBundle\Entity\Tags $recipeTag
*
* @return Recipe
*/
public function addRecipeTag(\AppBundle\Entity\Tags $recipeTag)
{
$this->recipe_tags[] = $recipeTag;
return $this;
}
And this is what I get inserted into my database (is the return after the POST request):
{
"recipe": {
"idRecipe": 3671,
"name": "TagName#76232",
"description": null,
"duration": null,
"updatedAt": null,
"createdAt": null,
"active": null,
"image": null,
"portions": null,
"idCategory": null,
"createdBy": null,
"recipeTags": [
{
"idTag": 143,
"name": null
}
],
"recipeSteps": [],
"recipeIngredients": null
} }
As you can see, the recipe is corretly added, but no name is added for the tag I just created. Plus,the pivot table recipe_tags does not add data at all.
What am I doing wrong?
EDIT:
I think the problem was that I was using the same form name field for both entities. Now I've changed the field and a new error appears:
{
"code": 400,
"message": "Validation Failed",
"errors": {
"errors": [
"This value is not valid."
],
"children": {
"name": [],
"recipe_tags": {
"children": [
{
"children": {
"tag": []
}
}
]
}
}
} }
And this is the parameters I am passing with the POST request:
{"name":"Recipe#2342"}
{"recipe_tags":"TagName#76232"}
Any ideas? Thank you.
Upvotes: 1
Views: 3532
Reputation: 365
I finally solved the problem. I wasn't passing correctly the POST parameters. This is how it should be done in case the form is for an restful api:
{
"recipe_form[name]":"recipeName",
"recipe_form[recipe_tags][0][tag]":"tag1",
"recipe_form[recipe_tags][1][tag]":"tag2",
"recipe_form[recipe_tags][2][tag]":"tag3"
}
..and so on. I alse named the form which made me easier to understand how it works. Also it is not necessary to create tags and then pass them to the form, so I can create as many tags as a want.
This is the controller:
$recipe = new Recipe();
$form = $this->get('form.factory')->
createNamed('recipe_form', RecipeType::class, $recipe);
$form->handleRequest($request);
if ($form->isValid() && $form->isSubmitted()) {
$em = $this->getDoctrine()->getManager();
$em->persist($recipe);
$em->flush();
return array("recipe" => $recipe);
}
return array(
'form' => $form,
);
And then, the formType classes:
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('name')
->add('recipe_tags', CollectionType::class, array(
'entry_type' => TagsType::class,
'allow_add' => true,
'by_reference' => false,
));
}
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('tag');
}
Cheers.
Upvotes: 1
Reputation: 1539
With a ManyToMany
you should simply add an EntityType
field just with multiple=true
in RecipeType
and you are done, unless you want to also create new tags.
Upvotes: 1