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

时间:2012-09-10 14:56:00

标签: php symfony doctrine-orm symfony-2.1

我有一个Doctrine2听众&过滤器,作为过滤掉任何未经批准/草案实体的手段,在其应用的实体上工作正常,但是,我不知道如何使其适用于它的关系。

让我们说实体被称为类别,然后我有与该类别相关的产品,当我为产品做findBy()时,我需要查询以检查它们所涉及的类别是否已被批准。

  

select * from products p
  的 left join category c on p.category_id = c.id
  where p.id = 5 and c.approved = true

粗体位是需要由我的过滤器或等效物注入的。

我该如何实施?

到目前为止,我有一个子查询作为过滤器中的一部分注入,但这似乎是地狱般的,我认为必须有更好的方法:

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';
        }
    }

2 个答案:

答案 0 :(得分:1)

我能想到的最好的方法是通过Category对象检索您的产品 这样您只需要过滤category.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';
    }
}

然后您的Category实体应该有一个产品集合(假设您有双向关系)。

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);

答案 1 :(得分:0)

使用注释可以使您的解决方案更加通用。我在https://gist.github.com/technetium/0c62164400a411e9ffc3713260448b25

写了一篇关于它的要点