Я написал функцию, подобную содержанию, для выполнения глубоких запросов.
Данные возвращаются в том же формате, который вы ожидаете от содержимого.
Это может быть полезно, если вам нужно добавить дополнительные критерии поиска к подуровням вашего запроса.
Короче говоря, эта функция позволяет вам углубляться до нужного уровня без возврата всего лишнего мусора, но дает вам дополнительный контроль над тем, что происходит между вызовами.
Containable - это круто, но он не вызывает поведения и другие функции, которые вам могут понадобиться вызывать между ними.
Пример: мне нужно запускать фильтр acl для возвращаемых данных после каждого вызова. Не удалось найти способ сделать это с помощьюableable.
Теперь легко добавить дополнительные вызовы функций в начало и конец этого сценария в качестве действий до и после вызова.
Просто подключите его к своей модели приложений и наблюдайте, как происходит волшебство.
Вот пример того, как будет выглядеть вызов:
$options = ['conditions'=>['User.id'=>9]];
$options['drill'] => ['Relation1', 'Relation2'=>['drill'=>['Subrelation1', 'Subrelation2'=>['drill'=>['ThirdLevelRelation']]]]];
$this->request('find', $options);
Вот как можно добавить опции в отношения sub.
$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;
}