Embed a Collection of Forms Error: Could not deter

2019-04-03 22:45发布

I am trying to embed collection of Tag forms to Service form, according to this tutorial. Tag and Service entities have many-to-many relationship.

Form is rendering correctly. But when I submit form, I get

Could not determine access type for property "tagList"

error. I don't understand why new Tag object is not added to the Service class by calling the addTag() method.

ServiceType

public function buildForm(FormBuilderInterface $builder, array $options)
{
    $builder
        ->add('title', TextType::class, array(
            'label' => 'Title'
        ))
    ;

    $builder->add('tagList', CollectionType::class, array(
        'entry_type' => TagType::class,
        'allow_add' => true,
        'allow_delete' => true,
        'by_reference' => false
    )));
}

Service class

{
....
 /**
 * @ORM\ManyToMany(targetEntity="Tag", mappedBy="serviceList",cascade={"persist"})
 */ 
private $tagList;

/**
 * @return ArrayCollection
 */
public function getTagList()
{
    return $this->tagList;
}

/**
 * @param Tag $tag
 * @return Service
 */
public function addTag(Tag $tag)
{
    if ($this->tagList->contains($tag) == false) {
        $this->tagList->add($tag);
        $tag->addService($this);
    }
}

/**
 * @param Tag $tag
 * @return Service
 */
public function removeTag(Tag $tag)
{
    if ($this->tagList->contains($tag)) {
        $this->tagList->removeElement($tag);
        $tag->removeService($this);
    }
    return $this;
}
}

Tag class

 {
  /**
 * @ORM\ManyToMany(targetEntity="Service", inversedBy="tagList")
 * @ORM\JoinTable(name="tags_services")
 */
private $serviceList;
 /**
 * @param Service $service
 * @return Tag
 */
public function addService(Service $service)
{
    if ($this->serviceList->contains($service) == false) {
        $this->serviceList->add($service);
        $service->addTag($this);
    }
    return $this;
}

/**
 * @param Service $service
 * @return Tag
 */
public function removeService(Service $service)
{
    if ($this->serviceList->contains($service)) {
        $this->serviceList->removeElement($service);
        $service->removeTag($this);
    }
    return $this;
}
 }

ServiceController

  public function newAction(Request $request)
{
    $service = new Service();
    $form = $this->createForm('AppBundle\Form\ServiceType', $service);
    $form->handleRequest($request);

    if ($form->isSubmitted() && $form->isValid()) {

        $em = $this->getDoctrine()->getManager();
        $em->persist($service);
        $em->flush();

        return $this->redirectToRoute('service_show', array('id' => $service->getId()));
    }

    return $this->render('AppBundle:Service:new.html.twig', array(
        'service' => $service,
        'form' => $form->createView(),
    ));
}

8条回答
祖国的老花朵
2楼-- · 2019-04-03 23:02

Maybe you forgot in the __construct() of Service class and Tag class to initialize $tagList and $serviceList like this ?

$this->tagList = new ArrayCollection();

$this->serviceList = new ArrayCollection();

查看更多
萌系小妹纸
3楼-- · 2019-04-03 23:04

This seems like an error with your constructor. Try this :

public function __construct()
{
    $this-> tagList = new \Doctrine\Common\Collections\ArrayCollection();
}
查看更多
爷的心禁止访问
4楼-- · 2019-04-03 23:08

Maybe the problem is that Symfony can't access that property?

If you look at where that exception is thrown (writeProperty method in the PropertyAccessor class) it says it can be thrown:

If the property does not exist or is not public.

In the tutorial you mentioned it has property $tags, and method addTag. I'm just guessing here, but maybe there's a convention where it tries to call a method names add($singularForm) and this is failing for you because the property is tagList and the method is addTag.

I'm not 100% sure, but you could try debugging by setting a stop point in that Symfony method to see why it's being thrown.

查看更多
走好不送
5楼-- · 2019-04-03 23:17

It's a long shot, but looking at your annotations I think the problem might be related to your manyToMany relationship. Try to change the owning side and inverse side (Swap the relationship) unless you specifically need to update from both ends (In that case I think the only solution is to add the objects manually or use oneToMany relationships).

Changes made only to the inverse side of an association are ignored. Make sure to update both sides of a bidirectional association (or at least the owning side, from Doctrine’s point of view)

This is a problem related to Doctrine I have suffered before, see: http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/reference/unitofwork-associations.html

查看更多
一夜七次
6楼-- · 2019-04-03 23:17

If you are using symfony, and use EntityRepository instead of CollectionType, make sure you use the 'multiple' => true, on your form build, otherwise the input will be for one entity and not for many, therefore it will call the setTagList instead of using the methods addTagList and removeTagList.

查看更多
可以哭但决不认输i
7楼-- · 2019-04-03 23:18

Could you please try to implement code from this URL?

http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/reference/association-mapping.html#owning-and-inverse-side-on-a-manytomany-association

First, please try to change mapped/inverse sides, and remove $service->addTag($this); from Tag::addService method.

查看更多
登录 后发表回答