2016-09-14 12 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