明确匹配任何内容的 Doctrine Query Builder

Doctrine2 QueryBuilder that explicitely matches nothing

我正在使用 Doctrine 2.4,我有一个抽象基础 class,其中包含如下方法:

protected function getBaseQueryBuilder($type) {
    switch ($type) {
        case self::TYPE_1;
            return $this->em->createQueryBuilder()->...lots of clauses...;
        case self::TYPE_2;
            return $this->em->createQueryBuilder()->...lots of clauses...;
        /* many more types... */
        case self::TYPE_N;
            return /* want to return a query builder for the empty set */
    }
}

有几个子class继承自这个基础class,每个子class都从几个地方调用这个方法。然后,他们在执行 returned 查询构建器之前使用额外的 class 特定子句扩展它们。但是,在 TYPE_N 的情况下,任何行都不能匹配。

当然,一个解决方案是 return 为 $type == TYPE_N 为空,让每个调用者检查 null,如果是,则不执行任何操作。但是,如果我可以 return 一个永远不会匹配任何东西并且查询永远不会访问数据库的查询构建器,那就更好了。这将大大简化许多来电者网站。

有办法吗?

你为什么要做那样的事情?我会说你不应该创建一个昂贵的 QueryBuilder 对象,这样你就可以在稍后调用 getResult()...

时从中获得 null

我建议您重新设计您的解决方案,也许可以在提取 getBaseQueryBuilder 方法的位置和从查询生成器获取实际结果的位置之间添加一个额外的方法。例如:

protected function getBaseQueryBuilder($type) {
    switch ($type) {
        case self::TYPE_1;
            return $this->em->createQueryBuilder()->...lots of clauses...;
        case self::TYPE_2;
            return $this->em->createQueryBuilder()->...lots of clauses...;
        case self::TYPE_N;
            return null;
    }
}

protected function getResultFromBaseQueryBuilder() {
    $type = $this->getType(); // get your type
    $queryBuilder = $this->getBaseQueryBuilder($type);
    if( $queryBuilder === null ){
        return /* empty result set so for example null, [] or new ArrayCollection(); */
    }
    return $queryBuilder->getResult();
}

您也可以直接在该方法中检查类型:

protected function getBaseQueryBuilder($type) {
    switch ($type) {
        case self::TYPE_1;
            return $this->em->createQueryBuilder()->...lots of clauses...;
        case self::TYPE_2;
            return $this->em->createQueryBuilder()->...lots of clauses...;
    }
}

protected function getResultFromBaseQueryBuilder() {
    $type = $this->getType(); // get your type
    if( $type === self:TYPE_N ){
        return /* empty result set so for example null, [] or new ArrayCollection(); */
    }
    $queryBuilder = $this->getBaseQueryBuilder($type);
    return $queryBuilder->getResult();
}

换句话说,与其制作一个包含 getBaseQueryBuilder 方法的通用接口,不如制作一个包含 returns 结果的方法的接口。 (我建议您宁愿调用方法 getResult 而不是 getResultFromBaseQueryBuilder ,我只是用它来阐明示例)。

而不是 returning null 并检查它,您可以创建一个 TypeNQueryBuilder 来扩展查询构建器,这样它可以保留界面,但 return 是一个自定义 TypeNQuery 具有您需要的 null/empty 个结果。

Acme\Doctrine\TypeNQuery

use Doctrine\ORM\AbstractQuery;

class TypeNQuery extends AbstractQuery
{
    /**
     * Override __construct so it doesn't require EntityManager
     */
    public function __construct()
    {

    }

    /**
     * {@inheritdoc}
     */
    public function getResult()
    {
        return [];
    }

    /**
     * {@inheritdoc}
     */
    public function getOneOrNullResult($hydrationMode = null)
    {
        return null;
    }

    /**
     * {@inheritdoc}
     */
    public function getSingleScalarResult()
    {
        return 0;
    }

    //.. add as necessary
    // getArrayResult()
    // getScalarResult()
    // getSingleResult()
}

Acme\Doctrine\TypeNQuery建设者

user Doctrine\ORM\QueryBuilder;

class TypeNQueryBuilder extends QueryBuilder
{
    /**
     * Override getQuery() so it returns your TypeNQuery
     */
    public function getQuery()
    {
        return new TypeNQuery();
    }
}

然后在您的 getBaseQueryBuilder 调用中,您可以根据提供的类型添加子句或 return 您的 TypeNQueryBuilder

protected function getBaseQueryBuilder($type)
{
    $queryBuilder = $this->em->createQueryBuilder();

    switch ($type) {
        case self::TYPE_1:
            $queryBuilder
                ->yadaYadaYada(....)
            ;
            break;
        case self::TYPE_2:
            $queryBuilder
                ->yadaYadaYada(....)
            ;
            break;
        case self::TYPE_N:
            return new TypeNQueryBuilder($this->em);
    }

    return $queryBuilder;
}

如果界面相同,您就可以使用..

$this
    ->getBaseQueryBuilder($type)
    ->andWhere(...)
    ->addOrderBy(...)
    ->getQuery()
    ->getOneOrNullResult();

.. 根据给定的类型,它将正确构建查询或在最后一分钟退出并 return 您的 null 结果。