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

时间:2021-01-17 06:45:15

Lets say I have a table that holds information about festivals.
Each festival has a start and end date.

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

I want to select all the festivals that are live (that happen) on a given date.
Meaning, I want to select all the festivals that their start date is before or on a given date, and that their end date is after or on a the same given date.

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

So I went on to the repository class of the festival entity, and created a method to do just that.
But the criteria argument "findBy" expects is an array, which all the examples only treat as a simple criteria (eg. "array('name' => 'billy')" will select all the rows that have the value billy in their name column), which uses only the comparison operator.

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

How can I use other operators such as

我怎样才能使用其他运算符

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

and etc. ?

等等。 ?

Thanks

谢谢

4 个解决方案

#1


19  

You'll need to write your own query (probably using DQL) if you want something that specific. I believe the built in "findBy" methods are more for just grabbing objects quickly if you have less specific criteria. I don't know your entity names or where they are stored. Could be something like this as a function in your Festival Repository.

如果你想要特定的东西,你需要编写自己的查询(可能使用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


83  

Doctrine 2.3 added a matching() method that lets you use Criteria.

Doctrine 2.3添加了一个匹配()方法,允许您使用Criteria。

The example by Jeremy Hicks may be written like this (note, this returns an ArrayCollection instead of an array).

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

Personally, I wouldn't use andWhere here, and use a few more lines to improve readability, like this:

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

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

Using an IN clause is very simple.

使用IN子句非常简单。

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

The Criteria class is in Doctrine's not-really-ORM-or-DBAL Common's namespace, like their ArrayCollection (which has supported Criteria longer than EntityRepository).

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

Its meant to be a decoupled way for non-repository code to create sophicated criteria. So it should be fine to use this class outside of the repository. QueryBuilder supports Criteria recently as well. So even when building more sophisticated queries that require QueryBuilder, you can use Criteria to give the non-database code flexibility in what it requests.

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

#3


9  

thats not the answer for Doron question doctrine have entity repository that not make us using query at all...

这不是Doron问题学说的答案有实体存储库,不会让我们使用查询...

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

but what did he asked is how to complex operator in array $criteria normal format of array $criteria is array('field'=> $value);

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

#4


7  

I have had the same problem a while back, where my Doctrine repositories became very ugly due to complex queries. I also had to convert Yii ActiveRecord (with Criteria objects) to Doctrine, and Doctrine did not have Criteria objects at the time.

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

I found a blogpost by Benjamin Eberlei which has an interesting solution to this problem based on the specification pattern.

我找到了Benjamin Eberlei的博客文章,它基于规范模式对这个问题有一个有趣的解决方案。

It gives you the ability to defer the manipulation of the Query Builder object to other classes.

它使您能够将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()

Furthermore you can compose 2 or more classes together, which creates nice reusable building blocks:

此外,您可以组合2个或更多类,从而创建可靠的可重用构建块:

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

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

In this case ExpiredAds() and AdsByUser() contain a structure like in the first code example.

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

If you think that solution would work for you, let me suggest two libraries which you can install through composer:

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

#1


19  

You'll need to write your own query (probably using DQL) if you want something that specific. I believe the built in "findBy" methods are more for just grabbing objects quickly if you have less specific criteria. I don't know your entity names or where they are stored. Could be something like this as a function in your Festival Repository.

如果你想要特定的东西,你需要编写自己的查询(可能使用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


83  

Doctrine 2.3 added a matching() method that lets you use Criteria.

Doctrine 2.3添加了一个匹配()方法,允许您使用Criteria。

The example by Jeremy Hicks may be written like this (note, this returns an ArrayCollection instead of an array).

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

Personally, I wouldn't use andWhere here, and use a few more lines to improve readability, like this:

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

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

Using an IN clause is very simple.

使用IN子句非常简单。

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

The Criteria class is in Doctrine's not-really-ORM-or-DBAL Common's namespace, like their ArrayCollection (which has supported Criteria longer than EntityRepository).

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

Its meant to be a decoupled way for non-repository code to create sophicated criteria. So it should be fine to use this class outside of the repository. QueryBuilder supports Criteria recently as well. So even when building more sophisticated queries that require QueryBuilder, you can use Criteria to give the non-database code flexibility in what it requests.

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

#3


9  

thats not the answer for Doron question doctrine have entity repository that not make us using query at all...

这不是Doron问题学说的答案有实体存储库,不会让我们使用查询...

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

but what did he asked is how to complex operator in array $criteria normal format of array $criteria is array('field'=> $value);

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

#4


7  

I have had the same problem a while back, where my Doctrine repositories became very ugly due to complex queries. I also had to convert Yii ActiveRecord (with Criteria objects) to Doctrine, and Doctrine did not have Criteria objects at the time.

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

I found a blogpost by Benjamin Eberlei which has an interesting solution to this problem based on the specification pattern.

我找到了Benjamin Eberlei的博客文章,它基于规范模式对这个问题有一个有趣的解决方案。

It gives you the ability to defer the manipulation of the Query Builder object to other classes.

它使您能够将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()

Furthermore you can compose 2 or more classes together, which creates nice reusable building blocks:

此外,您可以组合2个或更多类,从而创建可靠的可重用构建块:

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

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

In this case ExpiredAds() and AdsByUser() contain a structure like in the first code example.

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

If you think that solution would work for you, let me suggest two libraries which you can install through composer:

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