必须是一个CollectionValuedAssociationField,试图找不到多对多

时间:2017-12-01 00:23:18

标签: php symfony doctrine-orm

在ManyToMany关系中使用Artist和Show的实体,尝试构建一个列出现有艺术家尚未在给定节目中的表单会导致错误

  

错误:无效的PathExpression。必须是   CollectionValuedAssociationField

编辑:

Doctrine's documentation处有notIn($x, $y)表达式,但它完全没有明确(即尝试失败)如何在表单类中使用它。

编辑2:

可以在Artist Repository中获得预期结果,其功能如下所示。但是它在表单类中不可用,因为它的结果不是QueryBuilder的实例! [感谢xurshid29' s SO answer。]

public function notInShow($show)
{
    $qb = $this->getEntityManager()->createQueryBuilder();

    $ids = $qb
        ->select('a.id')
        ->from('AppBundle:Artist', 'a', 'a.id')
        ->leftJoin('a.shows', 's')
        ->where('s.show = ?1')
        ->setParameter(1, $show->getShow())
        ->getQuery()
        ->getArrayResult();

    $ids = array_keys($ids);

    $qbA = $this->getEntityManager()->createQuery(
        'SELECT a FROM AppBundle:Artist a '
        . 'WHERE a.id NOT IN (:ids)')
        ->setParameter(':ids', $ids)
        ->getResult();

    return $qbA;
}

构建字段的最新尝试(很多)如下所示:

表单类(代码段):

public function buildForm(FormBuilderInterface $builder, array $options)
{
    $show = $options['show'];
    $builder->add('artists', EntityType::class,
        [
            'class' => Artist::class,
            'choice_label' => function($artist, $key, $index) {
                return $artist->getLastName() . ', ' . $artist->getFirstName();
            },
            'query_builder' => function (EntityRepository $er) use($show) {
                return $er->createQueryBuilder('a')
                        ->join('a.shows', 's')
                        ->where('a NOT MEMBER of s')
                        ->andWhere('IDENTITY(s) = :show')
                        ->setParameter(':show', $show->getId())
                        ->orderBy('a.firstName', 'ASC')
                        ->orderBy('a.lastName', 'ASC')
                ;
            },
            'expanded' => true,
            'multiple' => true,
    ]);
}

实体摘录:

艺术家:

/**
 * @var \Doctrine\Common\Collections\Collection
 *
 * @ORM\ManyToMany(targetEntity="Show", mappedBy="artists")
 */
protected $shows;

显示:

/**
 * @var \Doctrine\Common\Collections\Collection
 *
 * @ORM\ManyToMany(targetEntity="Artist", inversedBy="shows", cascade={"persist"})
 * @ORM\JoinTable(name="participation",
 *      joinColumns={@ORM\JoinColumn(name="show_id", referencedColumnName="id")},
 *      inverseJoinColumns={@ORM\JoinColumn(name="artist_id", referencedColumnName="id")}
 *      ))
 */
protected $artists;

1 个答案:

答案 0 :(得分:0)

最后!最后的一些调整,这是有效的:

public function buildForm(FormBuilderInterface $builder, array $options)
{
    $show = $options['show'];
    $builder->add('artists', EntityType::class,
            [
                'class' => Artist::class,
                'choice_label' => function($artist, $key, $index) {
                    return $artist->getLastName() . ', ' . $artist->getFirstName();
                },
                'query_builder' => function (EntityRepository $er) use($show) {
                    $qb = $er->createQueryBuilder('a');
                    $ids = $qb
                        ->select('a.id')
                        ->leftJoin('a.shows', 's')
                        ->where('s.show = ?1')
                        ->setParameter(1, $show->getShow())
                        ->getQuery()
                        ->getResult();
                    if (empty($ids)) {
                        return $er->createQueryBuilder('a');
                    } else {
                        return $er->createQueryBuilder('a')
                            ->where($er->createQueryBuilder('a')->expr()->notIn('a.id', ':ids'))
                            ->setParameter(':ids', $ids);
                    }
                },
                'expanded' => true,
                'multiple' => true,
        ])
        ->add('save', SubmitType::class,
            array(
                'label' => 'Add artist(s)',
                'label_format' => ['class' => 'text-bold']
    ));
}