Verwendung einer findBy-Methode mit Vergleichskriterien

75

Ich müsste eine findBy-Methode mit "Magic Finder" verwenden, die Vergleichskriterien verwendet (nicht nur genaue Kriterien). Mit anderen Worten, ich muss so etwas tun:

$result = $purchases_repository->findBy(array("prize" => ">200"));

damit ich alle Einkäufe bekomme, bei denen der Preis über 200 liegt.

ElPiter
quelle
6
Wenn Sie der Meinung sind, dass Doktrin oder Symfonie nicht Ihr Ding sind, haben Sie einfach einen falschen Rahmen für Ihr Projekt ausgewählt. Diese Frameworks eignen sich hervorragend für viele Projekte.
Maske8
1
warum muss es so kryptisch sein
javier_domenech

Antworten:

30

Dies ist ein Beispiel für die Verwendung der Expr () - Klasse. Ich brauchte dies auch vor einigen Tagen und brauchte einige Zeit, um herauszufinden, wie die genaue Syntax und Verwendungsart lautet:

/**
 * fetches Products that are more expansive than the given price
 * 
 * @param int $price
 * @return array
 */
public function findProductsExpensiveThan($price)
{
  $em = $this->getEntityManager();
  $qb = $em->createQueryBuilder();

  $q  = $qb->select(array('p'))
           ->from('YourProductBundle:Product', 'p')
           ->where(
             $qb->expr()->gt('p.price', $price)
           )
           ->orderBy('p.price', 'DESC')
           ->getQuery();

  return $q->getResult();
}
con
quelle
12
Vermeiden Sie die Verwendung von DQL, wenn dies nicht unbedingt erforderlich ist. Dadurch wird Ihre Logik immer mehr an das ORM gekoppelt.
Ocramius
9
@Sliq Dies ist ein Doktrinverhalten und hat nicht unbedingt etwas mit Symfonie zu tun.
Betrug
12
@Sliq, nachdem Sie einige weitere Frameworks ausprobiert haben, werden Sie feststellen, dass Symfony nicht so beschissen ist
Marián Zeke Šedaj
Wenn ich richtig sehe, ist diese Funktion eine Repository-Methode. Hier können Sie $this->createQueryBuilder('p')über EntityManager direkt zu gehen, anstatt herumzugehen : $this->getEntityManager()->createQueryBuilder().
Gander
199

Die Klasse Doctrine\ORM\EntityRepositoryimplementiert die Doctrine\Common\Collections\SelectableAPI.

Die SelectableBenutzeroberfläche ist sehr flexibel und recht neu, aber Sie können Vergleiche und komplexere Kriterien sowohl für Repositorys als auch für einzelne Sammlungen von Elementen problemlos verarbeiten, unabhängig davon, ob es sich um ORM- oder ODM-Probleme oder um vollständig separate Probleme handelt.

Dies wäre ein Vergleichskriterium, wie Sie es gerade angefordert haben, wie in Doctrine ORM 2.3.2:

$criteria = new \Doctrine\Common\Collections\Criteria();
$criteria->where($criteria->expr()->gt('prize', 200));

$result = $entityRepository->matching($criteria);

Der Hauptvorteil dieser API besteht darin, dass Sie hier eine Art Strategiemuster Selectableimplementieren. Sie funktioniert mit Repositorys, Sammlungen, verzögerten Sammlungen und überall dort, wo die API implementiert ist.

Auf diese Weise können Sie Dutzende spezieller Methoden entfernen, die Sie für Ihre Repositorys geschrieben haben (wie z. B. findOneBySomethingWithParticularRule), und sich stattdessen darauf konzentrieren, Ihre eigenen Kriterienklassen zu schreiben, die jeweils einen dieser bestimmten Filter darstellen.

Ocramius
quelle
2
Hinweis: Ich verwende Symfony 2.8.11 mit Doctrine und - vielleicht nur dort - "Criteria :: expr () -> gt ()", nicht "$ Kriterien-> expr () -> gt ()".
Select0r
3
Es ist eine statische Methode: github.com/doctrine/collections/blob/… Auch: Symfony ist KEINE Doktrin. Referenzdoktrin mit Doktrinennamen und Versionierung :-P
Ocramius
@Ocramius dann sollte es $criteria::expr()->gt()ideal sein, nein?
Adrian Föder
2
Criteria::expr()auch OK - Sie können die Antwort jederzeit bearbeiten.
Ocramius
1
Konkrete Repository-Methoden wie findOneBySomethingWithParticularRuleIMO sind eine gute Sache, da sie Ihre Geschäftslogik von Details der Doctrine-Implementierung wie dem Kriterien-Builder entkoppeln.
David
6

Sie müssen entweder DQL oder den QueryBuilder verwenden . Zum Beispiel könnten Sie in Ihrem Purchase- EntityRepository Folgendes tun:

$q = $this->createQueryBuilder('p')
          ->where('p.prize > :purchasePrize')
          ->setParameter('purchasePrize', 200)
          ->getQuery();

$q->getResult();

Für noch komplexere Szenarien werfen Sie einen Blick auf die Expr () - Klasse .

dbrumann
quelle
5
Vermeiden Sie die Verwendung von DQL, wenn dies nicht unbedingt erforderlich ist. Es bindet Sie an die ORM-spezifische API und ist nicht wirklich wiederverwendbar. Es gibt einige Fälle, in denen DQL erforderlich ist, aber dies ist keiner von diesen.
Ocramius
5
Wie können Sie mit dem QueryBuilder nicht genau auf die gleiche Weise an die Lehre gebunden werden?
NDM
6
$criteria = new \Doctrine\Common\Collections\Criteria();
    $criteria->where($criteria->expr()->gt('id', 'id'))
        ->setMaxResults(1)
        ->orderBy(array("id" => $criteria::DESC));

$results = $articlesRepo->matching($criteria);
Patrizio Onorati
quelle
Dies funktioniert nicht für mich, siehe stackoverflow.com/questions/49450970/…
olidem
0

Ich verwende gerne solche statischen Methoden:

$result = $purchases_repository->matching(
    Criteria::create()->where(
        Criteria::expr()->gt('prize', 200)
    )
);

Natürlich können Sie die Logik pushen, wenn es sich um eine Bedingung handelt. Wenn Sie jedoch mehr Bedingungen haben, ist es besser, sie in Fragmente zu unterteilen, zu konfigurieren und an die Methode zu übergeben:

$expr = Criteria::expr();

$criteria = Criteria::create();
$criteria->where($expr->gt('prize', 200));
$criteria->orderBy(['prize' => Criteria::DESC]);

$result = $purchases_repository->matching($criteria);
Gänserich
quelle