如何基于关系实现Doctrine2过滤器?

6
我有一个Doctrine2监听器和过滤器,作为过滤掉任何未批准/草稿实体的手段,在应用于它的实体上运行良好,但是,我不知道如何使它在其关系中起作用。例如,如果该实体称为“类别”,则我将与该类别相关的产品,当我对产品进行findBy()时,需要查询以确保它们所属的类别已经被批准。加粗的部分是我的过滤器或等效物需要注入的内容。我该如何实现这一点?到目前为止,我在过滤器中注入了子查询作为where的一部分,但这似乎很复杂,我认为必须有更好的方法:
class ApprovableFilter extends SQLFilter
{
    protected $listener;
    protected $entityManager;

    public function addFilterConstraint(ClassMetadata $targetEntity, $targetTableAlias)
    {
        $config = $this->getListener()->getConfiguration($this->getEntityManager(), $targetEntity->name);

        /* this bit works fine for the category */

        if (isset($config['approvable']) && $config['approvable']) {
            $column = $targetEntity->columnNames[$config['fieldName']];

            return $targetTableAlias.'.'.$column.' = true';
        }

        /* this bit works for products.. but seems like a pretty poor solution */

        if (isset($targetEntity->associationMappings['category'])) {
            $config = $this->getListener()->getConfiguration(
                $this->getEntityManager(),
                $targetEntity->associationMappings['category']['targetEntity']
            );

            return '(
                select d.id from dealership d
                where d.id = '.$targetTableAlias.'.dealership_id
                and d.'.$config['fieldName'].' = true
            ) is not null';
        }
    }

你正在做的似乎是最好的。如果请求已经包含了JOIN,你会怎么做呢?等等... - AdrienBrault
@AdrienBrault 目前它会再次执行连接操作,可能会出现错误,并且别名理论上可能会发生冲突。我相信一定有比我示例中更好的方法来完成这个任务,但我不知道该如何去做。 - Steve
2个回答

2

1
我能想到的最好方法是通过类别对象检索您的产品。
这样,您只需要过滤类别中的approved字段即可。
例如:
public function addFilterConstraint(ClassMetadata $targetEntity, $targetTableAlias)
{
    $config = $this->getListener()->getConfiguration($this->getEntityManager(), $targetEntity->name);

    /* this bit works fine for the category */

    if (isset($config['approvable']) && $config['approvable']) {
        $column = $targetEntity->columnNames[$config['fieldName']];

        return $targetTableAlias.'.'.$column.' = true';
    }
}

假设您有一个双向关系,那么您的类别实体应该有一个产品集合。

use Doctrine\Common\Collections\ArrayCollection;

class Category {
    /**
     * @var ArrayCollection $products
     * @ORM\OneToMany(targetEntity="Product", mappedBy="category")
     */
    private $products;

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

    public function getProducts()
    {
        return $this->products;
    }
}

这样您就可以首先检索您的类别

$category = $this->get('doctrine')->getRepository('SomeBundle:Category')->find(5);
if( $category ) {
    //Here you now the category is approved
    $products = $category->getProducts();
}

希望这可以帮到您。

编辑:

为了回答@lracicot的问题并举例说明单向关系: 例如,我会创建一个ProjectRepository方法:

...
findByCategoryApproved( $product_id, $approved = true )
{
    $query =
        'SELECT p
         FROM AcmeBundle:Product
         LEFT JOIN p.categories c
         WHERE p.id = :id AND c.approved = :approved';
    
    return $this
        ->getEntityManager()
        ->createQuery( $query )
        ->setParameter( 'id', $product_id )
        ->setParameter( 'approved', $approved )
        ->getOneOrNullResult();
}

...

$product = $doctrine
     ->getRepository('AcmeBundle:Product')
     ->findByCategoryApproved(5);

我有一个类似的问题,但在我的情况下,“产品”到“类别”的关系是(并且必须是)单向的,所以我无法从“类别”获取我的“产品”。在这种情况下,你会有什么建议? - lracicot

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接