2016-09-14 85 views
4

我使用学说2.4和我有一个包含一个方法,像下面的抽象基类:Doctrine2 QueryBuilder的是明确地匹配什么

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的情况下,没有行必须匹配。

一个解决方案当然是返回null为$type == TYPE_N并让每个呼叫者检查null然后如果没有执行任何操作。但是如果我能返回一个永远不会匹配任何东西并且查询永远不会碰到数据库的查询生成器,那将会更好。这将简化许多呼叫者网站。

有没有办法做到这一点?

回答

3

与其返回null并检查是否可以创建一个扩展查询构建器的TypeNQueryBuilder,以便它保持接口,但返回具有您需要的空/空结果的自定义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结果。

+0

我喜欢这个解决方案。它甚至可以被扩展来覆盖'andWhere()','orderBy()'等,以使这些操作更便宜。我会尽力实现这一点,看看它是如何发展的。 – jlh

+1

我认为像'andWhere','innerJoin'等大多数方法都会做一些事情,然后调用'add',这样你就可以覆盖那个只返回'$ this'并切出很多工作。 – qooplmao

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,我只是用来说明这个例子)。

+0

据我所知,建造一个昂贵的物体最后不会返回任何东西,这是很浪费的。然而,它看起来好像你的解决方案不允许我描述的我需要:几个子类将获得这样的查询构建器,然后在它执行之前添加更多的子句。我没有看到你的解决方案是如何实现的,因为查询生成器被构造并且它的查询立即执行。子类在哪里挂钩? – jlh

+0

根据你在评论中给我的信息很少给你一个建议。例如,你可以为你的服务创建一个'addClause'或者'addExpression'方法,但是我觉得可能有更好的方法来实现你的目标。也许你可以问另一个问题,在哪里添加更多的细节来解释你的用户案例?你也可以在子类中检查你是否得到了一个'QueryBuilder'实例,并且简单地忽略了你有'TYPE_N'的情况(所以不需要'Querybuilder',对于查询添加子句没有多大意义。将永远不会执行)。 – Wilt

+0

我需要的用例已经在原始问题中进行了描述。那么你能更具体地了解什么信息缺失?是的,我可以在子课中进行检查,正如我在原始问题中已经提到的那样。这个问题特别是关于不这样做,因为这将是更多的代码来编写。 – jlh