I’ve managed to make it work. After adding sort parameter to my dataprovider in model, sorting started throwing errors but it made links for my added columns. When I inspected errors - it told me whats wrong - sorting tried to add table alias to my added columns, which is bad, because they are not part of the table. To solve it I got to comment a bit of code which pastes table alias into order in class CSort:
public function getOrderBy()
{
$directions=$this->getDirections();
if(empty($directions))
return is_string($this->defaultOrder) ? $this->defaultOrder : '';
else
{
if($this->modelClass!==null)
$schema=CActiveRecord::model($this->modelClass)->getDbConnection()->getSchema();
$orders=array();
foreach($directions as $attribute=>$descending)
{
$definition=$this->resolveAttribute($attribute);
if(is_array($definition))
{
if($descending)
$orders[]=isset($definition['desc']) ? $definition['desc'] : $attribute.' DESC';
else
$orders[]=isset($definition['asc']) ? $definition['asc'] : $attribute;
}
else if($definition!==false)
{
$attribute=$definition;
if(isset($schema))
{
if(($pos=strpos($attribute,'.'))!==false)
$attribute=$schema->quoteTableName(substr($attribute,0,$pos)).'.'.$schema->quoteColumnName(substr($attribute,$pos+1));
else
$attribute=/*CActiveRecord::model($this->modelClass)->getTableAlias(true).'.'.*/$schema->quoteColumnName($attribute);
}
$orders[]=$descending?$attribute.' DESC':$attribute;
}
}
return implode(', ',$orders);
}
}
so the problem was in line:
$attribute=CActiveRecord::model($this->modelClass)->getTableAlias(true).'.'.$schema->quoteColumnName($attribute);
And here is what needs to be added in Search() function in model class:
$sort = new CSort;
$sort->attributes = array('col1', 'col2', 'col3', /* ect... */ 'added_col1', 'added_col2');
return new CActiveDataProvider(get_class($this), array(
'criteria'=>$criteria, 'pagination' => $pagination, 'sort'=>$sort,
));
As far as I’ve done few tests it seems to work while operating on single table where table alias is not required, but this is just temporary solution because there are most likely cases when it won’t work as it should be.
[EDIT:]
After more investigation I’ve come to better solution, which is checking if attribute is actually in table columns and if it is then we can add table alias, in other case it goes w/o table alias. To do it I needed new field in CSort called $tableName, which is $model->tableName(), and then I can build query to get table columns like in CMysqlSchema->findColumns():
private function isColumnPartOfTable($schema, $columnName)
{
if ($this->tableName !== null)
{
$sql='SHOW COLUMNS FROM '.$schema->quoteTableName($this->tableName);
try
{
$tableColumns=Yii::app()->db->createCommand($sql)->queryAll();
}
catch(Exception $e)
{
return false;
}
foreach ($tableColumns as $column)
{
if ($column['Field'] == $columnName)
{
return true;
}
}
}
return false;
}
and then changed:
$attribute=CActiveRecord::model($this->modelClass)->getTableAlias(true).'.'.$schema->quoteColumnName($attribute);
to:
if ($this->isColumnPartOfTable($schema, $attribute))
{
$attribute=CActiveRecord::model($this->modelClass)->getTableAlias(true).'.'.$schema->quoteColumnName($attribute);
}
else
{
$attribute=$schema->quoteColumnName($attribute);
}
and another change in CSort is:
public function __construct($modelClass=null, $tableName=null)
{
$this->modelClass=$modelClass;
$this->tableName= $tableName;
}
This solution seems to work for me on single table and with joined tables.