Doctrine2 QueryBuilder明确地匹配任何内容

时间:2016-09-14 06:19:29

标签: php symfony doctrine-orm abstract-class query-builder

我正在使用Doctrine 2.4,我有一个抽象的基类,它包含如下方法:

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 */
    }
}

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

一个解决方案当然是为$type == TYPE_N返回null并让每个调用者检查null然后如果是这样则不执行任何操作。但是如果我能够返回一个永远不会匹配任何东西并且查询永远不会命中DB的查询构建器会更好。这将大大简化许多来电者网站。

有办法做到这一点吗?

2 个答案:

答案 0 :(得分:3)

您可以创建扩展查询构建器的TypeNQueryBuilder,而不是返回null并检查它,以便保留接口,但返回具有您需要的null / empty结果的自定义TypeNQuery

的Acme \学说\ 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 \学说\ TypeNQueryBuilder

user Doctrine\ORM\QueryBuilder;

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

然后在getBaseQueryBuilder来电中,您可以添加条款或返回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();

..并且根据给定的类型,它将正确构建查询,或者只是在最后一刻退出并返回null结果。

答案 1 :(得分:2)

你为什么要做那样的事情?我会说你不应该创建一个昂贵的QueryBuilder对象,以便稍后当你拨打null时可以从中获取getResult() ...

我建议你重新设计你的解决方案,可以在你提取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方法的公共接口,而是创建一个包含返回结果的方法的接口。 (我建议您调用方法getResult而不是getResultFromBaseQueryBuilder,而我只是用来澄清示例。