如何使用具有比较标准的 findBy 方法

我需要使用“ Magic finder”findBy 方法,使用比较标准(而不仅仅是精确标准)。换句话说,我需要这样做:

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

这样我就能买到所有奖金在200以上的东西。

136841 次浏览

You have to use either DQL or the QueryBuilder. E.g. in your Purchase-EntityRepository you could do something like this:

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


$q->getResult();

For even more complex scenarios take a look at the Expr() class.

This is an example using the Expr() Class - I needed this too some days ago and it took me some time to find out what is the exact syntax and way of usage:

/**
* 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();
}

The class Doctrine\ORM\EntityRepository implements Doctrine\Common\Collections\Selectable API.

The Selectable interface is very flexible and quite new, but it will allow you to handle comparisons and more complex criteria easily on both repositories and single collections of items, regardless if in ORM or ODM or completely separate problems.

This would be a comparison criteria as you just requested as in Doctrine ORM 2.3.2:

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


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

The major advantage in this API is that you are implementing some sort of strategy pattern here, and it works with repositories, collections, lazy collections and everywhere the Selectable API is implemented.

This allows you to get rid of dozens of special methods you wrote for your repositories (like findOneBySomethingWithParticularRule), and instead focus on writing your own criteria classes, each representing one of these particular filters.

The Symfony documentation now explicitly shows how to do this:

$em = $this->getDoctrine()->getManager();
$query = $em->createQuery(
'SELECT p
FROM AppBundle:Product p
WHERE p.price > :price
ORDER BY p.price ASC'
)->setParameter('price', '19.99');
$products = $query->getResult();

From http://symfony.com/doc/2.8/book/doctrine.html#querying-for-objects-with-dql

$criteria = new \Doctrine\Common\Collections\Criteria();
$criteria->where($criteria->expr()->gt('id', 'id'))
->setMaxResults(1)
->orderBy(array("id" => $criteria::DESC));


$results = $articlesRepo->matching($criteria);

I like to use such static methods:

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

Of course, you can push logic when it is 1 condition, but when you have more conditions it is better to divide it into fragments, configure and pass it to the method:

$expr = Criteria::expr();


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


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

Copying the findBy query and modifying it to return your expected result is a good approach.