2012-03-11 70 views
0

我正在構建一個網站,它有三種模式:StoreStoreReviewUser。網站列出商店,用戶可以查看商店。因此,我的Store型號可以有多行StoreReview行,並且每個StoreReview行都屬於User行。如何獲取與CakePHP的查找操作的深層關聯?

我的問題是:當獲取所有Store行時,我怎樣才能獲取相關的User以及StoreReview行?目前我正在使用:

<?php 
class StoresController extends AppController { 

    public function view($slug) { 
     $stores = $this->Store->find('all'); 
    } 
} 

但是,這隻返回'StoreReview'行。由於User行是更深層次的另一個級別,因此我不確定如何獲取此行;我檢查過CakePHP的文檔和谷歌搜索,但是CakePHP最近重新調整了他們的文檔網站,並且我的谷歌搜索網站上的示例沒有工作。

預先感謝您。

回答

6

有兩種方法。您可以增加recursive屬性:

$stores = $this->Store->find('all', array('recursive' => 2)); 

或者使用Containable行爲(我喜歡這一點,因爲你可以使超過2級):

$this->Store->Behaviors->attach('Containable'); 
$this->Store->contain(array('StoreReview' => array('User'))); 
$stores = $this->Store->find('all'); 
$this->Store->Behaviors->detach('Containable'); 

更多信息:

+0

啊,當然!謝謝!我忘記將可容納行爲附加到我的模型中。我已經完成了所有工作。進一步證明爲什麼你不應該在星期天編碼;) – 2012-03-11 15:55:09

0

我寫了一個類似於可容納的函數來執行深層查詢。

數據得到的返回格式與您期望從可容納的相同。

如果您需要將其他搜索條件添加到查詢的子級別,它可能很有用。

簡而言之,該功能允許您按照自己的想法深入鑽取,而不會返回所有多餘的垃圾,但可以讓您更多地控制調用之間發生的情況。

可封閉很棒,但不會調用可能需要調用的行爲和其他函數。

例如:我需要在每次調用後對返回的數據運行一個acl過濾器。無法找到一種方式來做到這一點與可容納。

現在很容易在該腳本的開頭和結尾添加額外的函數調用作爲前後調用操作。

只需將其插入您的AppModel並觀看魔術發生。

下面是一個電話是什麼樣子的一個例子:

$options = ['conditions'=>['User.id'=>9]]; 
$options['drill'] => ['Relation1', 'Relation2'=>['drill'=>['Subrelation1', 'Subrelation2'=>['drill'=>['ThirdLevelRelation']]]]]; 
$this->request('find', $options); 

這裏是如何添加選項子關係。

$options['drill'] => ['Relation1', 'Relation2'=>['fields'=>['field_a','field_b'], 'conditions'=>['alias'=>'test'], 'drill'=>[....] ]]; 

這裏所說:

public function request($method='first', $options=array()){ 
    $result = $this->find($method, $options); 
    if(isset($options['drill'])){ 
     $bits = $bitOptions = $subDrils = $subBits = []; 
     if(is_array($options['drill'])){ 
     foreach($options['drill'] as $key => $val){ 
      if(is_array($val)){ 
      $bits[]=$key; 
      $bitOptions[$key] = $val; 
      if(isset($val['drill'])){ 
       if(is_array($val['drill'])){ 
       foreach($val['drill'] as $sKey => $sVal){ 
        $subBits[$key][] = is_array($sVal)?$sKey:$sVal; 
       } 
       } else { 
       $subBits[$key][] = $val['drill']; 
       } 
      } 
      } else { 
      $bits[] = $val; 
      } 
     } 
     } else { 
     $bits[] = $options['drill']; 
     } 
     foreach($bits as $bit){ 
     if(isset($gems)){unset($gems);$gems=[];} 
     if(isset($result[$bit])){ 
      $gems[] =& $result[$bit]; 
     } else { 
      foreach($result as $k => $v){ 
      if(isset($result[$k][$bit])){ 
       $gems[] =& $result[$k][$bit]; 
      } 
      } 
     } 
     foreach($gems as $key => $gem){ 
      if(!empty($gem)){ 
      $m = $this->$bit; 
      if(is_object($m)){ 
       foreach(['hasOne','belongsTo','hasMany','hasAndBelongsToMany'] as $relation){ 
       foreach(array_keys($m->$relation) as $alias){ 
        if(isset($subBits[$bit])){ 
        if(!in_array($alias, $subBits[$bit])){ 
         $m->unBindModel([$relation=>[$alias]]); 
        } 
        } 
       } 
       } 
       if(!empty($subBits[$bit])){ 
       $opts = isset($bitOptions[$bit])?$bitOptions[$bit]:[]; 
       if(isset($gem[$m->primaryKey])){ 
        if(!isset($opts['conditions'])){ 
        $opts['conditions'] = [$m->alias.'.'.$m->primaryKey=>$gem[$m->primaryKey]]; 
        } else { 
        $opts['conditions'] = Hash::merge($opts['conditions'], [$m->alias.'.'.$m->primaryKey=>$gem[$m->primaryKey]]); 
        } 
        if($r = $m->request('first', $opts)){ 
        unset($r[$m->alias]); 
        $gems[$key] = Hash::merge($gems[$key], $r); 
        } 
       } else { 
        reset($gem); 
        $first_key = key($gem); 
        $first = $gem[$first_key]; 
        if(isset($first[$m->primaryKey])){ 
        foreach($gem as $gemKey => $gemVal){ 
         if(!isset($opts['conditions'])){ 
         $opts['conditions'] = [$m->alias.'.'.$m->primaryKey=>$gemVal[$m->primaryKey]]; 
         } else { 
         $opts['conditions'] = Hash::merge($opts['conditions'], [$m->alias.'.'.$m->primaryKey=>$gemVal[$m->primaryKey]]); 
         } 
         if(isset($opts['method'])){ 
         $method = $opts['method']; 
         } else { 
         $method = 'first'; 
         } 
         if($r = $m->request('first', $opts)){ 
         unset($r[$m->alias]); 
         $gems[$key][$gemKey] = Hash::merge($gems[$key][$gemKey], $r); 
         } 
        } 
        } 
       } 
       } 
      } 
      } 
     } 
     } 
    } 
    } 

寫一個輔助函數,使調用這個函數有點清潔(PS php5.4 +可以取代數組語法如果使用舊版本的PHP):

查詢現在看起來是這樣的:

$this->Model->find('all', ['drill'=>$this->Model->drill(['Assoc1'=>['SubAssoc1','SubAssoc2'=>['o'=>['conditions'=>'condition', 'fields'=>['fielda', 'fieldb', 'fieldc']], 'SubAssoc3' ]]])]); 

助手:

public function drill($array=array(), $first=true){ 
$drill = []; 
foreach($array as $key => $value){ 
    if(is_array($value)){ 
    if(isset($value['o']) && is_array($value['o'])){ 
     foreach($value['o'] as $k => $v){ 
     $drill['drill'][$key][$k] = $v; 
     } 
     unset($value['o']); 
    }   
    if(!empty($value)){ 
     if(isset($drill['drill'][$key])){ 
     $drill['drill'][$key] = Hash::merge($drill['drill'][$key],$this->drill($value, false)); 
     } else { 
     $drill['drill'][$key] = $this->drill($value, false); 
     } 
    } 
    } else {  
    $drill['drill'][] = $value; 
    } 
} 
if($first){ 
    return $drill['drill']; 
} 
return $drill; 

}