web-dev-qa-db-ja.com

doctrine 2エンティティのリポジトリ内で複雑な基準を使用するにはどうすればよいですか?

フェスティバルに関する情報を保持するテーブルがあるとしましょう。
各フェスティバルには開始日と終了日があります。

特定の日にライブ(発生)するすべてのフェスティバルを選択したいと思います。
つまり、開始日が特定の日付より前または特定の日付であり、終了日が特定の日付より後または同じであるすべてのフェスティバルを選択します。

それで、フェスティバルエンティティのリポジトリクラスに進み、それを行うためのメソッドを作成しました。
ただし、条件引数「findBy」は配列であり、すべての例で単純な基準としてのみ扱われます(例:「array( 'name' => 'billy')」は名前列の値は「billy」)、比較演算子のみを使用します。

次のような他の演算子を使用するにはどうすればよいですか

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

や。。など。 ?

ありがとう

34
Doron

特定の何かが必要な場合は、(おそらく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();
}
21
Jeremy Hicks

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クラスは、ArrayCollection(EntityRepositoryより長いCriteriaをサポートしている)のように、Doctrineの非ORMまたはDBAL Commonの名前空間にあります。

これは、非リポジトリコードが洗練された基準を作成するための分離された方法であることを意味します。したがって、リポジトリの外部でこのクラスを使用しても問題ありません。 QueryBuilder Criteriaをサポート 最近も。そのため、QueryBuilderを必要とするより高度なクエリを作成する場合でも、Criteriaを使用して、非データベースコードに要求の柔軟性を与えることができます。

86
Reece45

それは、Doronの質問に対する答えではありませんdoctrineクエリをまったく使用しないエンティティリポジトリがあります...

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

しかし、彼が尋ねたのは、配列$criteriaの配列$ criteriaの通常の形式で演算子を複雑にする方法ですarray('field'=> $value);

10
nuenuh

私はしばらく前と同じ問題を抱えていましたが、そこではDoctrineリポジトリは複雑なクエリのために非常に見苦しくなりました。また、Yiiオブジェクト)からDoctrine、およびDoctrineにはCriteriaオブジェクトがありませんでした。

Benjamin Eberleiによるブログ投稿 を見つけました。これは 仕様パターン に基づいてこの問題に対する興味深い解決策を持っています。

クエリビルダオブジェクトの操作を他のクラスに延期する機能を提供します。

$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つ以上のクラスを一緒に構成して、Niceの再利用可能なビルディングブロックを作成できます。

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

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

この場合、ExpiredAds()およびAdsByUser()には、最初のコード例のような構造が含まれています。

その解決策があなたにとってうまくいくと思うなら、作曲家を通してインストールできる2つのライブラリを提案させてください:

9
rikbruil