【问题标题】:How to fetch deep associations with CakePHP's find operations?如何获取与 CakePHP 的查找操作的深度关联?
【发布时间】:2012-03-11 14:46:15
【问题描述】:

我正在构建一个包含三个模型的网站:StoreStoreReviewUser。该网站列出了商店,用户可以查看商店。因此,我的Store 模型可以有很多StoreReview 行,每个StoreReview 行属于一个User 行。

我的问题是:在获取所有 Store 行时,我怎样才能同时获取相关的 User 以及 StoreReview 行?目前我正在使用:

<?php
class StoresController extends AppController {

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

但这只会返回“StoreReview”行。因为User 行更深,所以我不确定如何获取它;我检查了 CakePHP 的文档并在 Google 上搜索过,但 CakePHP 最近重新调整了他们的文档站点,我的 Google 搜索网站上的示例不起作用。

提前谢谢你。

【问题讨论】:

    标签: cakephp cakephp-2.0 cakephp-model


    【解决方案1】:

    有两种方法。可以增加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');
    

    更多信息:

    【讨论】:

    • 啊,当然!谢谢!我忘记将 Containable 行为附加到我的模型中。我已经这样做了,而且一切正常。进一步证明为什么你不应该在周日编码 ;)
    【解决方案2】:

    我写了一个类似于containable的函数来做深度查询。

    返回的数据格式与可包含的格式相同。

    如果您需要向查询的子级别添加额外的搜索条件,这可能会很有用。

    简而言之,该函数允许您钻取任意深度,而不会返回所有多余的垃圾,但可以让您更好地控制调用之间发生的事情。

    Containable 很棒,但不会调用行为和您可能需要在其间调用的其他函数。

    示例:我需要在每次调用后对返回的数据运行 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'=>[....] ]];
    

    这里是:(PS.php5.4+如果使用旧版本的php,你可以替换数组语法)

      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);
                          }
                        }
                      }
                    } 
                  }
                }
              }
            }
          }
        }
      }
    

    写了一个辅助函数,让调用这个函数更简洁:

    查询现在看起来像这样:

    $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;
    

    }

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多