我写了一个类似于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;
}