Symfony2单向ManyToMany集合表单

时间:2014-01-15 21:04:09

标签: symfony doctrine-orm associations

我被困住了: - )

也许我的研究中只有错误的关键词。但我没有通过。所以我希望其中一个人可以帮助我!

我有一个单向的ManyToMany协会。当我尝试提交表单(因此持续存在)时,我收到错误:

  

通过“TrainerInnenPool \ AppBundle \ Entity \ Trainer #applicationFields”关系找到了一个新实体,该关系未配置为实体级联持久化操作:TrainerInnenPool \ AppBundle \ Entity \ ApplicationField @ 0000000022ef36c600000000087bcbc3。

当我执行“cascade persist”时,会创建一个实际已经存在的新实体。

我有2个实体:

  • ApplicationField

Trainer具有与ApplicationField的单向ManyToMany关联:

class Trainer {

    public function __construct()
    {
        $this->applicationFields = new ArrayCollection();
    }

    [...]

    /**
     * @ORM\ManyToMany(targetEntity="ApplicationField")
     */
    protected $applicationFields;

ApplicationField具有自引用的OneToMany关联:

class ApplicationField {

    public function __construct() {
        $this->children = new ArrayCollection();
    }

    [...]

    /**
     * @ORM\OneToMany(targetEntity="ApplicationField", mappedBy="parent")
     */
    private $children;

    /**
     * @ORM\ManyToOne(targetEntity="ApplicationField", inversedBy="children")
     * @ORM\JoinColumn(name="parent_id", referencedColumnName="id")
     */
    private $parent;

我想创建一个表单,我可以在其中添加Trainer - ApplicationField关联。

因此我有一个ApplicationFieldCollectionType:

class ApplicationFieldCollectionType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder
            ->add('applicationFields', 'collection', array(
                'type'         => new ApplicationFieldType(),
                'allow_add'    => true,
                'label' => false
                ))
       ;
    }

    public function setDefaultOptions(OptionsResolverInterface $resolver)
    {
        $resolver->setDefaults(array(
            'data_class' => 'TrainerInnenPool\AppBundle\Entity\Trainer',
        ));
    }

embeded类型如下:

class ApplicationFieldType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder->add('applicationFieldName', 'entity', array(
                'class' => 'TrainerInnenPoolAppBundle:ApplicationField',
                'label' => false,
                'mapped' => false,
                'property' => 'name',
                'query_builder' => function(EntityRepository $repository) {
                    return $repository->createQueryBuilder('application_field')
                        ->where('application_field.parent is NULL');
                }
        )); 

        $builder->add('name', 'entity', array(
                'class' => 'TrainerInnenPoolAppBundle:ApplicationField',
                'label' => false,
                'property' => 'name',
                'query_builder' => function(EntityRepository $repository) {
                    return $repository->createQueryBuilder('application_field')
                        ->where('application_field.parent = 1');
                }
        ));
    }

    public function setDefaultOptions(OptionsResolverInterface $resolver)
    {
        $resolver->setDefaults(array(
            'data_class' => 'TrainerInnenPool\AppBundle\Entity\ApplicationField',
        ));
    }

最后遗漏的部分:控制器:

    public function editApplicationField($id, Request $request)
    {
        $entityManager = $this->getDoctrine()->getEntityManager();

        $trainer = $entityManager->getRepository('TrainerInnenPoolAppBundle:Trainer')->find($id);

        $editForm = $this->createForm(new ApplicationFieldCollectionType(), $trainer);

        if ($request->getMethod() == 'POST') {

            $editForm->handleRequest($request);

            $entityManager->flush();
        }

当我从Trainer中获取ApplicationField实体并尝试保留它们时,

        $editForm->handleRequest($request);

        $af = $trainer->getApplicationFields();

        foreach ($af as $applicationField) {
            $trainer->addApplicationField($applicationField);
            $entityManager->persist($applicationField);
        }

        $entityManager->flush();

我无法这样做,因为我得到了“关键主要重复条目” - 例外。

我想我非常想念任何明显的观点。如果有人可以帮助我,给我一个提示或刚提到用信息更新我的问题,我会非常感激。

亲切的问候......

2 个答案:

答案 0 :(得分:1)

由于缺少属性,因此未调用嵌套类型设置器:

->add('applicationFields', 'collection', array(
                'type'         => new ApplicationFieldType(),
                ...
                'by_reference' => false
                ...

http://symfony.com/doc/current/reference/forms/types/collection.html#by-reference

当您计划拥有可添加/删除的收集字段时(" allow_add"," allow_delete"),您应始终提供" by_reference" => false选项,以便直接在相关实体上调用setter,然后构建关联,而不是从原始实体链接方法。

希望这有帮助!

答案 1 :(得分:0)

您需要cascade = {“persist”}注释,因为您希望将整个实体与ApplicationField的关联持久化。如果您不使用cascade = {“persist”},则必须手动保留实体。

实体已添加到培训师,因此如果您想手动保留实体,则应删除该行

$trainer->addApplicationField($applicationField);

并且只执行持久性。

这应该有效。试试吧。但我认为效果与使用级联持久性相同。所以这不是我认为的最终解决方案,而是理解问题的第一步,为什么手册持续存在以前不起作用。