Reputation: 162
I am trying to create a form for a media with a sub collection of tags. Following doctrine documentation I create that :
Test\CommonBundle\Entity\Media:
type: entity
table: media
repositoryClass: Test\CommonBundle\Repository\MediaRepository
indexes:
index_title:
columns: [ 'title' ]
fields:
id:
type: integer
id: true
generator: { strategy: IDENTITY }
nullable: false
title:
type: string
nullable: false
length: 200
oneToMany:
tagAssociate:
targetEntity: Test\CommonBundle\Entity\TagAssociateMedia
mappedBy: targetAssociate
Test\CommonBundle\Entity\TagAssociateMedia:
type: entity
table: tag_associate_media
repositoryClass: Test\CommonBundle\Repository\TagAssociateMediaRepository
fields:
createdAt:
type: datetime
nullable: true
manyToOne:
targetAssociate:
targetEntity: Test\CommonBundle\Entity\Media
inversedBy: tagAssociate
joinColumn:
name: target_id
referencedColumnName: id
tag:
targetEntity: Test\CommonBundle\Entity\TagMedia
inversedBy: tagAssociate
joinColumn:
name: tag_id
referencedColumnName: id
Test\CommonBundle\Entity\TagMedia:
type: entity
table: tag_media
repositoryClass: Test\CommonBundle\Repository\TagMediaRepository
indexes:
index_name:
columns: [ 'name' ]
fields:
id:
type: integer
id: true
generator: { strategy: IDENTITY }
nullable: false
name:
type: string
nullable: false
length: 100
oneToMany:
tagAssociate:
targetEntity: Test\CommonBundle\Entity\TagAssociateMedia
mappedBy: tag
I create entities. For exemple I have for Media :
<?php
namespace Test\CommonBundle\Entity;
use Doctrine\Common\Collections\ArrayCollection;
use \Test\CommonBundle\Entity\TagAssociate;
/**
* Media
*/
class Media
{
/**
* @var integer
*/
protected $id;
/**
* @var string
*/
protected $title;
/**
* @var \Doctrine\Common\Collections\Collection
*/
protected $tagAssociate;
/**
* Constructor
*/
public function __construct()
{
$this->tagAssociate = new ArrayCollection();
}
/**
* Get id
*
* @return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set title
*
* @param string $title
*
* @return Media
*/
public function setTitle($title)
{
$this->title = $title;
return $this;
}
/**
* Get title
*
* @return string
*/
public function getTitle()
{
return $this->title;
}
/**
* Add tagAssociate
*
* @param \Test\CommonBundle\Entity\TagAssociate $tagAssociate
*
* @return Media
*/
public function addTagAssociate(TagAssociate $tagAssociate)
{
$this->tagAssociate[] = $tagAssociate;
$tagAssociate->setTargetAssociate($this);
return $this;
}
/**
* Remove tagAssociate
*
* @param \Test\CommonBundle\Entity\TagAssociate $tagAssociate
*/
public function removeTagAssociate(TagAssociate $tagAssociate)
{
$this->tagAssociate->removeElement($tagAssociate);
}
/**
* Get tagAssociate
*
* @return \Doctrine\Common\Collections\Collection
*/
public function getTagAssociate()
{
return $this->tagAssociate;
}
}
I create the TagMedia on the same model and create intermediate entity with $targetAssociate and $tag attributs and their getter/setter. Until now, I can manipulate my entities without problem.
Now the problem, I try to create a Form like this :
<?php
namespace Test\BackBundle\Entity\Form\Type;
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\CollectionType;
use Symfony\Component\Form\FormInterface;
use Test\CommonBundle\Entity\Media;
class MediaType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options){
$builder
->add('title', TextType::class, array(
'label' => 'entity.media.title',
'required' => true,
))
->add('tagAssociate', CollectionType::class, array(
'label' => 'entity.tagAssociate',
'required' => false,
'entry_type' => TagAssociateType::class,
'allow_add' => true,
'allow_delete' => true,
))
;
}
public function configureOptions(OptionsResolver $resolver){
$resolver->setDefaults(array(
'data_class' => Media::class,
'translation_domain' => 'messages',
'validation_groups' => function (FormInterface $form) {
$data = $form->getData();
$id = $data->getId();
if( $id ){
return array('update');
}
return array('Default');
},
));
}
public function getName(){
return 'test_back_type_media';
}
}
and the sub Form :
<?php
namespace Test\BackBundle\Entity\Form\Type;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\Form\FormInterface;
use Test\CommonBundle\Entity\TagAssociateMedia;
class TagAssociateType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options){
$builder
// what i am suppose to add here ?
->add('tag', EntityType::class, array(
'class' => TagMedia::class,
'label' => 'entity.tag',
'required' => false,
'choice_label' => 'name',
))
;
}
public function configureOptions(OptionsResolver $resolver){
$resolver->setDefaults(array(
'data_class' => TagAssociateMedia::class,
'translation_domain' => 'messages',
'validation_groups' => function (FormInterface $form) {
$data = $form->getData();
$id = $data->getId();
if( $id ){
return array('update');
}
return array('Default');
},
));
}
public function getName(){
return 'test_back_type_tag_associate';
}
}
With that, I don't have error and I have 0 and 1 display (in twig with {{ form_row(form.tagAssociate) }}
) when I have 2 ligns in the relation as in this screen :
But my problem come when I want to have this : I want to have a list of checkbox corresponding to the relation and when I uncheck, on the update, this relation will be remove (I will manage in JS to add new relation with prototype and ajax request to ask server about available tags).
Any idea how I can do ?
Upvotes: 2
Views: 122
Reputation: 865
I don't understand why you have TagAssociateMedia. This entity doesn't provide additional data, it's just a bridge between Media and TagMedia. If this is the case you can skip TagAssociateMedia and add TagMedia as a ManyToMany relation with Media. Doctrine will handle the associative table on its own.
This way is really easy to have the result you want, just add the field in your form:
->add('tagMedia', EntityType::class, array(
'class' => 'TestCommonBundle:TagMedia',
'multiple' => true,
'expanded' => true,
'required' => false
))
Upvotes: 0
Reputation: 1389
You have to call the query builder inside the form to call the tags entity https://symfony.com/doc/current/reference/forms/types/entity.html#using-a-custom-query-for-the-entities For remove you just have to unset the relation between the entities in the Media Class with a specific method that you create. Using Ajax you send the tag id, get the Entity in your logic and remove the relation
Upvotes: 1