如何防止EntityType在同一个实体(父)的ManyToOne关系中显示当前对象?

问题描述 投票:0回答:2

我有一个与自身有ManyToOne关系的实体,因为它的对象可以拥有相同类型的父母。

我扩展了一个EntityType以显示实体中的对象,但我不希望当前对象显示在选择列表中,因为对象不能是其自身的父对象。

要通过其所有者过滤对象,我正在做这样的事情

public function configureOptions(OptionsResolver $resolver)
{
    $resolver->setDefault('query_builder', function (Options $options) {
        return function (EntityRepository $er) use ($options) {
            return $er->createQueryBuilder('con')
                ->orderBy('con.name', 'ASC')
                ->andWhere('con.owner = :owner')
                ->setParameter('owner', $this->getLoggedUser());
        };
    });
}

但是我不知道如何让当前对象添加一个andWhere子句来从选择列表中删除它。

那么,任何想法如何从EntityType中的选择列表中删除正在编辑的对象?

forms symfony doctrine sonata
2个回答
0
投票

为了修复你当前的代码,你可以使用$options['data'],因为它保存了表单的底层数据。我相信你的情况是(例如)Folder实体。试试这个(请注意,这里我假设底层实体是持久的):

$resolver->setDefault('query_builder', function (Options $options) {
    return function (EntityRepository $er) use ($options) {
        return $er->createQueryBuilder('con')
            ->orderBy('con.name', 'ASC')
            ->andWhere('con != :current')
            ->andWhere('con.owner = :owner')
            ->setParameter('current', $options['data'])
            ->setParameter('owner', $this->getLoggedUser())
        ;
    };
});

如果底层实体可能尚未持久化(例如添加新的Folder时),则必须稍微修改代码以解决此问题:

$resolver->setDefault('query_builder', function (Options $options) {
    return function (EntityRepository $er) use ($options) {
        $qb = $er->createQueryBuilder('con')
            ->andWhere('con.owner = :owner')
            ->setParameter('owner', $this->getLoggedUser())
            ->orderBy('con.name', 'ASC')
        ;

        $current = $options['data'];
        if (null !== $current->getId()) {
            $qb
                ->andWhere('con != :current')
                ->setParameter('current', $options['data'])
            ;
        }

        return $qb;
    };
});

希望有所帮助。


0
投票

感谢michał-tomczuk并感谢jakumi,你们两个都非常有帮助,但我猜你的建议没有用,因为FormType是在AdminType之前创建的,而'data'在选项中还没有。至少我无法在任何地方找到它。

我尝试了另一种有效的方法,即使它有点矫枉过正。

由于formtype总是在编辑上下文中使用,在我的情况下,在SonataAdmin范围内,我将路由器注入到类型中,并通过我能够从PathInfo检索的对象id过滤查询:

<?php
use Symfony\Component\Routing\RouterInterface;

/** @var RouterInterface $router */
private $router;  


/** {@inheritdoc} */
public function configureOptions(OptionsResolver $resolver)
{
    $resolver->setDefault('query_builder', function (Options $options) {
        return function (EntityRepository $er) use ($options) {
            $matches = [];
            preg_match(
                '/^.*\/([0-9a-z\-]+)\/edit$/',
                $this->router->getContext()->getPathInfo(),
                $matches
            );

            $queryBuilder = $er->createQueryBuilder('ent')
                ->orderBy('ent.name', 'ASC')
            if (true === array_key_exists('1', $matches)) {
                $queryBuilder
                    ->andWhere('ent.id != :id')
                    ->setParameter('id', $matches[1]);
            }
            return $queryBuilder;
        };
    });
}

我知道这是一个肮脏的解决方案,但有效。

© www.soinside.com 2019 - 2024. All rights reserved.