2011-03-18 10 views
31

Powiedzmy, że mam tabelę zawierającą informacje o festiwalach.
Każdy festiwal ma datę rozpoczęcia i zakończenia.Jak używać złożonych kryteriów w repozytorium jednostki doktryny 2?

Chcę wybrać wszystkie festiwale, które są na żywo (które się wydarzyły) w określonym dniu.
Znaczenie, chcę wybrać wszystkie festiwale, których data początkowa przypada przed lub w określonym dniu, oraz że data zakończenia przypada po tej samej dacie lub w tym samym dniu.

Poszedłem więc do klasy repozytorium obiektu festiwalowego i stworzyłem metodę, aby to zrobić.
Ale argument kryterium "findBy" oczekuje, że jest to tablica, której wszystkie przykłady traktują tylko jako proste kryteria (np. "Array (" name '=>' billy ') "wybierze wszystkie wiersze, które mają wartość billy w ich kolumnie nazwy), która używa tylko operatora porównania.

Jak mogę korzystać z innych operatorów takich jak

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

i itp?

Dzięki

+0

... Zgadzam się również z tym pytaniem. A najlepiej bez zapytania Raw ani QueryBuilder .... jeśli to możliwe. – renoirb

+0

możliwy duplikat [Sposób korzystania z metody findBy z kryteriami porównawczymi] (http://stackoverflow.com/questions/14786937/how-to-use-a- findby-method- with-comparative-criteria) –

Odpowiedz

19

Musisz napisać własne zapytanie (prawdopodobnie za pomocą DQL), jeśli chcesz coś, co konkretne. Wierzę, że wbudowane metody "findBy" są bardziej przydatne do szybkiego chwytania obiektów, jeśli masz mniej konkretnych kryteriów. Nie znam nazw twoich jednostek ani miejsca ich przechowywania. Może być coś takiego w funkcji w repozytorium festiwalowym.

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(); 
} 
+3

Po prostu know - wywołując $ this-> createQueryBuilder() z poziomu klasy repozytorium, otrzymujesz kreator zapytań z tabelą i alisem już skonfigurowanym – Doron

+4

, który nie jest prawdziwą odpowiedzią na pytanie zadane – David

+0

Jeśli to niemożliwe. Zakładam, że jest to właściwa odpowiedź ... polegać na manipulacji QueryBuilder. – renoirb

8

ów nie odpowiedź na pytanie Doron doktryny mają repozytorium podmiot, który nie zrobić z nami za pomocą strony internetowej w ogóle ...

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

ale co on zapytał jest jak kompleks operator w tablicy $ kryteria normalny format tablicy $criteria jest array('field'=> $value);

80

Doctrine 2.3 dodał matching() metodę, która pozwala używać Criteria.

Przykład Jeremy'ego Hicksa może być zapisany w ten sposób (uwaga: to zwraca ArrayCollection zamiast tablicy).

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

Osobiście nie użyłby andWhere tutaj i używać kilka dodatkowych linii w celu zwiększenia czytelności, tak:

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

Korzystanie z klauzula jest bardzo prosty.

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

Klasa Kryteria jest w nie-naprawdę-orm-or-DBAL nazw Common doktryny, podobnie jak ich ArrayCollection (która wsparła kryteria dłużej niż EntityRepository).

Ma to być metoda oddzielona od repozytorium w celu stworzenia wyrafinowanych kryteriów. Tak więc powinno być dobrze używać tej klasy poza repozytorium. Ostatnio również QueryBuilder supports Criteria. Więc nawet przy tworzeniu bardziej wyrafinowanych zapytań wymagających QueryBuilder, możesz użyć Kryteriów, aby nadać kodowi innym niż bazowa elastyczność w żądaniach.

+0

Od Doktryny 2.3 jest to poprawna odpowiedź na pytanie. Dzięki! – Wilt

+10

W doctrine/orm 2.5, EntityRepository :: matching zwróci LazyCriteriaCollection, aby zezwolić na liczenie bez pobierania wszystkich wierszy (https://github.com/doctrine/doctrine2/pull/882) –

+4

Czy ktoś mógłby wyjaśnić, dlaczego 'Criteria :: create() 'używane zamiast' new Criteria() '? –

7

Po jakimś czasie miałem ten sam problem, ponieważ moje repozytorium Doktryny stało się bardzo brzydkie z powodu złożonych zapytań. Musiałem również przekonwertować Yii ActiveRecord (z obiektami Criteria) do Doctrine, a Doctrine nie posiadało obiektów Criteria w tym czasie.

Znalazłem blogpost by Benjamin Eberlei, który ma interesujące rozwiązanie tego problemu w oparciu o specification pattern.

Daje możliwość odroczenia manipulacji obiektem konstruktora zapytań na inne klasy.

$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() 

Ponadto można komponować 2 lub więcej klas razem, co stwarza miły wielokrotnego użytku bloki:

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

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

w tym przypadku ExpiredAds() i AdsByUser() zawierają strukturę jak w pierwszym przykładzie kodu .

Jeśli uważasz, że rozwiązanie będzie pracować dla Ciebie, pozwól mi sugerować, dwie biblioteki, które można zainstalować przez kompozytora:

Powiązane problemy