OK,
after some tweaking I got it, I had to extend 2 classes, I was not in the mood to analyse all methods in CActiveFinder and CJoinElement, so I changed all to that was private to protected.
here are the code, it could be a lot better with some more help, but here it goes:
after changing the methods and variables derivate a class from CActiveFinder
class CActiveFinderAgregate extends CActiveFinder {
public function __construct($model,$with)
{
$this->_builder=$model->getCommandBuilder();
$this->_joinTree=new CJoinElementAgregate($this,$model);
$this->buildJoinTree($this->_joinTree,$with);
}
public function query($criteria,$all=false)
{
$this->joinAll=$criteria->together===true;
$this->_joinTree->beforeFind(false);
if($criteria->alias!='')
{
$this->_joinTree->tableAlias=$criteria->alias;
$this->_joinTree->rawTableAlias=$this->_builder->getSchema()->quoteTableName($criteria->alias);
}
$this->_joinTree->find($criteria);
$result = $this->_joinTree->records;
$this->destroyJoinTree();
return $result;
}
protected function buildJoinTree($parent,$with,$options=null)
{
if($parent instanceof CStatElement)
throw new CDbException(Yii::t('yii','The STAT relation "{name}" cannot have child relations.',
array('{name}'=>$parent->relation->name)));
if(is_string($with))
{
if(($pos=strrpos($with,'.'))!==false)
{
$parent=$this->buildJoinTree($parent,substr($with,0,$pos));
$with=substr($with,$pos+1);
}
// named scope
$scopes=array();
if(($pos=strpos($with,':'))!==false)
{
$scopes=explode(':',substr($with,$pos+1));
$with=substr($with,0,$pos);
}
if(isset($parent->children[$with]) && $parent->children[$with]->master===null)
return $parent->children[$with];
if(($relation=$parent->model->getActiveRelation($with))===null)
throw new CDbException(Yii::t('yii','Relation "{name}" is not defined in active record class "{class}".',
array('{class}'=>get_class($parent->model), '{name}'=>$with)));
$relation=clone $relation;
$model=CActiveRecord::model($relation->className);
if($relation instanceof CActiveRelation)
{
$oldAlias=$model->getTableAlias(false,false);
$model->setTableAlias($relation->alias===null?$relation->name:$relation->alias);
}
if(($scope=$model->defaultScope())!==array())
$relation->mergeWith($scope,true);
if(!empty($options['scopes']))
$scopes=array_merge($scopes,(array)$options['scopes']); // no need complex merging, $scopes always in simle format
if($scopes!==array())
{
$scs=$model->scopes();
foreach($scopes as $k=>$v)
{
if(is_integer($k))
{
if(is_string($v))
{
if(isset($scs[$v]))
{
$relation->mergeWith($scs[$v],true);
continue;
}
$scope=$v;
$params=array();
}
else if(is_array($v))
{
$scope=key($v);
$params=current($v);
}
}
else if(is_string($k))
{
$scope=$k;
$params=$v;
}
if(method_exists($model,$scope))
{
$model->resetScope();
call_user_func_array(array($model,$scope),(array)$params);
$relation->mergeWith($model->getDbCriteria(),true);
}
else
throw new CDbException(Yii::t('yii','Active record class "{class}" does not have a scope named "{scope}".',
array('{class}'=>get_class($model), '{scope}'=>$scope)));
}
}
// dynamic options
if($options!==null)
$relation->mergeWith($options);
if($relation instanceof CActiveRelation)
$model->setTableAlias($oldAlias);
if($relation instanceof CStatRelation)
return new CStatElement($this,$relation,$parent);
else
{
if(isset($parent->children[$with]))
{
$element=$parent->children[$with];
$element->relation=$relation;
}
else
$element=new CJoinElementAgregate($this,$relation,$parent,++$this->_joinCount);
if(!empty($relation->through))
{
$slave=$this->buildJoinTree($parent,$relation->through,array('select'=>false));
$slave->master=$element;
$element->slave=$slave;
}
$parent->children[$with]=$element;
if(!empty($relation->with))
$this->buildJoinTree($element,$relation->with);
return $element;
}
}
// $with is an array, keys are relation name, values are relation spec
foreach($with as $key=>$value)
{
if(is_string($value)) // the value is a relation name
$this->buildJoinTree($parent,$value);
else if(is_string($key) && is_array($value))
$this->buildJoinTree($parent,$key,$value);
}
}
}
Note that on the construct for this new agregate I had to chance CJoinElement to CJoinElementAgregate, same thing had to do with buildJoinTree since it was the method that create the childs.
query method in CActiveFinderAgregate alse had to be tweaked since after the find we don’t get objects and they don’t have an afterFind method to run.
after that derivate CJoinElement:
class CJoinElementAgregate extends CJoinElement {
private $aliases = array();
public function runQuery($query) {
$command=$query->createCommand($this->_builder);
$this->aliases = $this->getAllAliases();
foreach($command->queryAll() as $row)
$this->populateRecord($query,$row);
}
public function getAllAliases() {
$onde = array();
$aliases = array_flip($this->_columnAliases);
$onde = array_merge($aliases, $onde);
foreach($this->children as $child) {
$onde = array_merge($child->getAllAliases(), $onde);
}
return $onde;
}
protected function populateRecord($query,$row)
{
$attributes=array();
foreach($row as $alias=>$value) {
if(isset($this->aliases[$alias]))
$attributes[$this->aliases[$alias]]=$value;
}
$this->records[] = $attributes;
}
}
since the query won’t return objects it won’t have an hierarchy I had to get all column alias back from all child to create the retuning object, that way I’ll have an array with indexed values with the same name as the objects.
and that’s all of it, to use simply:
$model = CActiveRecord::model('YourModel');
$finder=new CActiveFinderAgregate($model,$criteria->with);
$values = $finder->query($criteria,$all);
tyvm