我有一个与自身有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中的选择列表中删除正在编辑的对象?
为了修复你当前的代码,你可以使用$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;
};
});
希望有所帮助。
感谢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;
};
});
}
我知道这是一个肮脏的解决方案,但有效。