Php 链接Symfony存储库方法(筛选器)
链接存储库方法以重用查询构建逻辑的最佳实践是什么 我是这样做的,但我怀疑这是否正确:Php 链接Symfony存储库方法(筛选器),php,symfony,doctrine-orm,repository,Php,Symfony,Doctrine Orm,Repository,链接存储库方法以重用查询构建逻辑的最佳实践是什么 我是这样做的,但我怀疑这是否正确: use Doctrine\ORM\Mapping; use Doctrine\ORM\EntityManager; class OrderRepository extends \Doctrine\ORM\EntityRepository { private $q; public function __construct(EntityManager $em, Mapping\ClassMe
use Doctrine\ORM\Mapping;
use Doctrine\ORM\EntityManager;
class OrderRepository extends \Doctrine\ORM\EntityRepository
{
private $q;
public function __construct(EntityManager $em, Mapping\ClassMetadata $class)
{
parent::__construct($em, $class);
$this->q = $this->createQueryBuilder('o');
}
public function getOneResult()
{
return $this->q->getQuery()->getOneOrNullResult();
}
public function getResult()
{
return $this->q->getQuery()->getResult();
}
public function filterByStatus($status)
{
$this->q->andWhere('o.status = :status')->setParameter('status', $status);
return $this;
}
public function findNextForPackaging()
{
$this->q->leftjoin('o.orderProducts', 'p')
->orderBy('o.deliveryDate', 'ASC')
->andHaving('SUM(p.qtePacked) < SUM(p.qte)')
->groupBy('o.id')
->setMaxResults(1);
return $this;
}
}
这当然只是一个例子。实际上,还有更多的方法可以链接
这方面的一个大问题是,我需要一些过滤器的联接,因此在添加联接之前,我必须检查联接是否已由某个方法/过滤器设置。我没有把它放在示例中,但我找到了它,但它不是很漂亮
另一个问题是,我在使用存储库时必须小心,因为查询可能已经设置为某个值,所以每次使用它之前,我都需要重置查询
我也知道我可以使用条令匹配方法和标准,但据我所知,这是相当昂贵的,而且,我不知道如何用这种方法解决连接问题
有什么想法吗?我做了一些类似于你想要的东西: 控制器,这就是你使用它的方式。我没有返回响应实例,而是在kernel.view listener中序列化数组,但它仍然是有效的示例:
/**
* @Route("/root/pending_posts", name="root_pending_posts")
* @Method("GET")
*
* @return Post[]
*/
public function pendingPostsAction(PostRepository $postRepository, ?UserInterface $user): array
{
if (!$user) {
return [];
}
return $postRepository->begin()
->wherePublished(false)
->whereCreator($user)
->getResults();
}
PostRepository:
class PostRepository extends BaseRepository
{
public function whereCreator(User $user)
{
$this->qb()->andWhere('o.creator = :creator')->setParameter('creator', $user);
return $this;
}
public function leftJoinRecentComments(): self
{
$this->qb()
->leftJoin('o.recentCommentsReference', 'ref')->addSelect('ref')
->leftJoin('ref.comment', 'c')->addSelect('c');
return $this;
}
public function andAfter(\DateTime $after)
{
$this->qb()->andWhere('o.createdAt > :after')->setParameter('after', $after);
return $this;
}
public function andBefore(\DateTime $before)
{
$this->qb()->andWhere('o.createdAt < :before')->setParameter('before', $before);
return $this;
}
public function wherePublished(bool $bool)
{
$this->qb()->andWhere('o.isPending = :is_pending')->setParameter('is_pending', !$bool);
return $this;
}
}
这对我链接控制器示例中的调用有很大帮助。您肯定不想要自己的构造函数。如果您不使用EntityManager::getRepository工厂方法,那么您将遇到许多有趣的工作单元问题。我发现您让一些find方法返回存储库以及隐藏查询生成器的方法有点混乱,可能难以维护。只要确保你真的有足够的过滤器,使它值得。你是绝对正确的!这就是为什么我在寻找一个更好的解决方案……我考虑过使用SQLFilters,但这似乎有点过头了。通过扩展Doctrine\ORM\QueryBuilder创建一个新的QueryBuilder,添加您自己的方法并覆盖存储库中的createQueryBuilder,以返回您自己的生成器类,而不是默认类。
class PostRepository extends BaseRepository
{
public function whereCreator(User $user)
{
$this->qb()->andWhere('o.creator = :creator')->setParameter('creator', $user);
return $this;
}
public function leftJoinRecentComments(): self
{
$this->qb()
->leftJoin('o.recentCommentsReference', 'ref')->addSelect('ref')
->leftJoin('ref.comment', 'c')->addSelect('c');
return $this;
}
public function andAfter(\DateTime $after)
{
$this->qb()->andWhere('o.createdAt > :after')->setParameter('after', $after);
return $this;
}
public function andBefore(\DateTime $before)
{
$this->qb()->andWhere('o.createdAt < :before')->setParameter('before', $before);
return $this;
}
public function wherePublished(bool $bool)
{
$this->qb()->andWhere('o.isPending = :is_pending')->setParameter('is_pending', !$bool);
return $this;
}
}
namespace wjb\CoreBundle\Model;
use Doctrine\ORM\EntityRepository;
use Doctrine\ORM\QueryBuilder;
abstract class BaseRepository extends EntityRepository
{
/** @var QueryBuilder */
private $qb;
public function begin()
{
$this->qb = $this->createQueryBuilder('o');
return $this;
}
public function qb(): QueryBuilder
{
return $this->qb;
}
public function none()
{
$this->qb()->where('o.id IS NULL');
return $this;
}
public function setMaxResults($maxResults)
{
$this->qb()->setMaxResults($maxResults);
return $this;
}
public function addOrderBy($sort, $order = null)
{
$this->qb()->addOrderBy($sort, $order);
return $this;
}
public function getResults()
{
return $this->qb()->getQuery()->getResult();
}
}