【问题标题】:Chaining Symfony Repository Methods ( Filters )链接 Symfony 存储库方法(过滤器)
【发布时间】:2017-10-03 14:05:31
【问题描述】:

链接存储库方法以重用查询构建逻辑的最佳实践是什么?

这是我的做法,但我怀疑这是否正确:

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

}

这允许我像这样链接方法:

$order = $em->getRepository('AppBundle:Order')->filterByStatus(10)->findNextForPackaging()->getOneResult();

这当然只是一个例子。实际上还有更多的方法可以链接。

其中一个大问题是我需要为某些“过滤器”加入连接,因此我必须在添加之前检查连接是否已由某些方法/过滤器设置。 (示例中我没有放,但想通了,但不是很漂亮)

另一个问题是我在使用存储库时必须小心,因为查询可能已经设置了一些东西,所以每次使用前我都需要重置查询。

我也知道我可以使用带有标准的学说“匹配”方法,但据我了解,这相当昂贵,而且我不知道如何用这种方法解决“加入”问题.

有什么想法吗?

【问题讨论】:

  • 你绝对不想要你自己的构造函数。如果您不使用 EntityManager::getRepository 工厂方法,那么您将遇到许多有趣的工作单元问题。
  • 我发现您让一些查找方法返回存储库的方法以及“隐藏”查询构建器的概念有点令人困惑,并且可能难以维护。只要确保你真的有足够的过滤器让它值得。
  • 你完全正确!这就是为什么我正在寻找更好的解决方案...
  • 我考虑过使用 SQLFilters,但这似乎有点过头了
  • 通过扩展 Doctrine\ORM\QueryBuilder 创建一个新的 QueryBuilder,添加您自己的方法并在您的存储库中覆盖 createQueryBuilder 以返回您自己的构建器类,而不是默认的。

标签: php symfony doctrine-orm repository


【解决方案1】:

我做了类似你想要的东西:

控制器,这就是你使用它的方式。我没有返回 Response 实例,而是在 kernel.view 侦听器中序列化数组,但它仍然是有效的示例:

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

后存储库:

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

BaseRepository 有最常用的东西,仍在进行中:

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

这对我在控制器示例中链接调用有很大帮助。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-07-02
    • 1970-01-01
    • 2011-05-29
    • 2011-09-05
    • 1970-01-01
    • 2017-02-10
    • 2017-02-08
    相关资源
    最近更新 更多