如何在doctrine 2实体的存储库中使用复杂的标准?

时间:2011-03-18 08:52:12

标签: php sql doctrine criteria doctrine-orm

假设我有一张桌子,上面有关于节日的信息 每个节日都有开始和结束日期。

我想选择在给定日期生活(发生)的所有节日 这意味着,我想选择他们的开始日期在给定日期之前或之后的所有节日,以及他们的结束日期是在相同的给定日期之后或之后。

所以我继续了节日实体的存储库类,并创建了一种方法来实现这一点 但是标准参数“findBy”期望的是一个数组,所有示例都只将其视为一个简单的标准(例如“array('name'=>'billy')”将选择所有具有billy值的行他们的名字栏,只使用比较运算符。

如何使用其他运算符,例如

>, <, !=, IN, NOT IN, LIKE    

等等?

由于

4 个答案:

答案 0 :(得分:86)

Doctrine 2.3添加了matching()方法,可让您使用Criteria

Jeremy Hicks的例子可能是这样写的(注意,这会返回一个ArrayCollection而不是数组)。

public function findActiveFestivals($start, $end)
{
    $expr = Criteria::expr();
    $criteria = Criteria::create();
    $criteria->where($expr->gte('start', $start));
    $criteria->andWhere($expr->lte('end', $end);
    return $this->matching($criteria);
}

就我个人而言,我不会在这里使用andWhere,并使用更多行来提高可读性,如下所示:

public function findActiveFestivals($start, $end)
{
    $expr = Criteria::expr();
    $criteria = Criteria::create();
    $criteria->where(
      $expr->andX(
        $expr->gte('start', $start),
        $expr->lte('end', $end)
      )
    );
    return $this->matching($criteria);
}

使用IN子句非常简单。

public function findFestivalsByIds($ids)
{
    $expr = Criteria::expr();
    $criteria = Criteria::create();
    $criteria->where($expr->in('id', $ids));
    return $this->matching($criteria);
}

Criteria类在Doctrine的非真正ORM或DBAL Common的命名空间中,就像它们的ArrayCollection(它支持的Criteria比EntityRepository更长)。

它的意思是非存储库代码创建sophicated标准的解耦方式。所以在存储库之外使用这个类应该没问题。最近也是QueryBuilder supports Criteria。因此,即使在构建需要QueryBuilder的更复杂的查询时,您也可以使用Criteria为其提供的非数据库代码灵活性。

答案 1 :(得分:21)

如果你想要特定的东西,你需要编写自己的查询(可能使用DQL)。我相信内置的“findBy”方法更适合在没有特定标准的情况下快速抓取对象。我不知道您的实体名称或存储位置。可能是这样的节日存储库中的一个函数。

public function findActiveFestivals($start, $end)
{
    $qb = $this->_em->createQueryBuilder();
    $qb->select('f')
        ->from('Festival', 'f')
        ->where('f.start >= :start')
        ->andWhere('f.end <= :end')
        ->setParameters(array('start' => $start, 'end' => $end));

    return $qb->getQuery()->getArrayResult();
}

答案 2 :(得分:10)

这不是Doron问题的答案 doctrine有实体存储库,根本不能让我们使用查询...

$this->em->getRepository($this->entity)->findBy(array $criteria);

但他问的是如何在数组$条件中复杂运算符 数组$criteria的正常格式为array('field'=> $value);

答案 3 :(得分:9)

我一直有同样的问题,由于复杂的查询,我的Doctrine存储库变得非常难看。我还必须将Yii ActiveRecord(带有Criteria对象)转换为Doctrine,而Doctrine当时没有Criteria对象。

我发现blogpost by Benjamin Eberlei根据specification pattern找到了解决此问题的有趣方法。

它使您能够将Query Builder对象的操作推迟到其他类。

$spec = new AndX(
    new Equals('ended', 0),
    new OrX(
        new LowerThan('endDate', new \DateTime()),
        new AndX(
            new IsNull('endDate'),
            new LowerThan('startDate', new \DateTime('-4weeks'))
        )
    )
);

return $this->em->getRepository('Advertisement')->match($spec)->execute()

此外,您可以组合2个或更多类,这可以创建漂亮的可重用构建块:

public function myQuery(User $user)
{
    $spec = new AndX(
        new ExpiredAds(),
        new AdsByUser($user)
    );

    return $this->em->getRepository('Advertisement')->match($spec)->execute();
}

在这种情况下,ExpiredAds()和AdsByUser()包含类似于第一个代码示例的结构。

如果您认为该解决方案适合您,请让我建议您可以通过作曲家安装的两个库: