2012-01-04 46 views
2

例如,我有這樣的關係:分頁與中可容納的條件與hasOne工作,但不是的hasMany

UserContact hasMany Contact 
Contact hasOne Info 
Contact hasMany Response 

,我需要分頁聯繫,所以我使用中可容納:

$this->paginate = array(
      'limit'=>50, 
      'page'=>$page, 
      'conditions' =>array('Contact.id'=>$id), 
      'contain'=>array(
       'Response', 
       'Info' 
       ) 
      ); 

我想要通過Info.name和Response.description添加搜索。它適用於信息名稱,但它會引發錯誤,如果我嘗試使用Response.description,說該列不存在。

此外,我試圖改變關係聯繫hasOne響應,然後它過濾正確,但它只返回第一個響應,這是不正確的關係。

因此,舉例來說,如果我有一個搜索鍵$過濾我想只返回這些聯繫人具有匹配Info.name或至少一個匹配Response.description

回答

3

如果您看看CakePHP如何構建SQL查詢,您會看到它生成包含的「單個」關係(hasOnebelongsTo)作爲主查詢中的連接子句,然後它爲包含的「多個」關係添加單獨的查詢。

這使得通過單一關係進行篩選變得輕而易舉,因爲相關模型的表已經加入到主查詢中。

爲了用倍數關係來過濾你必須創建一個子查詢:

// in contacts_controller.php: 
$conditionsSubQuery = array(
    'Response.contact_id = Contact.id', 
    'Response.description LIKE' => '%'.$filter.'%' 
); 
$dbo = $this->Contact->getDataSource(); 
$subQuery = $dbo->buildStatement(array(
    'fields' => array('Response.id'), 
    'table' => $dbo->fullTableName($this->Contact->Response), 
    'alias' => 'Response', 
    'conditions' => $conditionsSubQuery 
), $this->Contact->Response); 
$subQuery = ' EXISTS (' . $subQuery . ') '; 

$records = $this->paginate(array(
    'Contact.id' => $id, 
    $dbo->expression($subQuery) 
)); 

但是如果你需要一個Response字段篩選您應該只生成子查詢,否則你會篩選沒有迴應的聯絡人。

PS。該代碼太大而且難以顯示在控制器中。對於我的項目,我重構它變成app_model.php,讓每一個模型可以生成自己的子查詢:

function makeSubQuery($wrap, $options) { 
    if (!is_array($options)) 
     return trigger_error('$options is expected to be an array, instead it is:'.print_r($options, true), E_USER_WARNING); 
    if (!is_string($wrap) || strstr($wrap, '%s') === FALSE) 
     return trigger_error('$wrap is expected to be a string with a placeholder (%s) for the subquery. instead it is:'.print_r($wrap, true), E_USER_WARNING); 

    $ds = $this->getDataSource(); 

    $subQuery_opts = array_merge(array(
     'fields' => array($this->alias.'.'.$this->primaryKey),   
     'table' => $ds->fullTableName($this),   
     'alias' => $this->alias, 
     'conditions' => array(),  
     'order' => null, 
     'limit' => null, 
     'index' => null, 
     'group' => null 
    ), $options); 

    $subQuery_stm = $ds->buildStatement($subQuery_opts, $this); 
    $subQuery = sprintf($wrap, $subQuery_stm); 
    $subQuery_expr = $ds->expression($subQuery); 
    return $subQuery_expr; 
} 

然後在你的控制器代碼變爲:

$conditionsSubQuery = array(
    'Response.contact_id = Contact.id', 
    'Response.description LIKE' => '%'.$filter.'%' 
); 
$records = $this->paginate(array(
    'Contact.id' => $id, 
    $this->Contact->Response->makeSubQuery('EXISTS (%s)', array('conditions' => $conditionsSubQuery)) 
)); 
+0

這看起來不錯!我肯定會在接下來的幾天裏(在賞金到期之前)出手,並且讓你知道。 – 2012-01-09 12:33:47

+0

結果我不會使用這段代碼,因爲我實際上需要同時搜索多件事情,所以刪除沒有響應的聯繫人將導致問題。儘管如此,答案是正確的(沒有蛋糕的方式),所提供的代碼在另一種情況下肯定會派上用場,所以我會獎勵你的賞金。謝謝! – 2012-01-12 18:00:08

0

我現在不能嘗試,但應該工作,如果您分頁響應模型,而不是聯繫人模型。

+0

分頁會的工作的話,但不會做我需要的。我需要所有聯繫人的分頁(按聯繫人分組)。 – 2012-01-07 18:09:43