Yii добавить фильтр к виртуальному атрибуту в CGridView и сделать его сортируемым
У меня есть следующие модели:
User
со столбцами {id,user_name,password,user_type}
Admin
со столбцами {id,user_id,full_name,..... и т. д.}
Editor
со столбцами {id, user_id, full_name,... и т. д.}
и отношенияUser
: 'admin' => array(self::HAS_ONE, 'Admin', 'user_id'),'editor' => array(self::HAS_ONE, 'Editor', 'user_id'),
Admin
: 'user' => array(self::BELONGS_TO, 'User', 'user_id'),
Editor
: 'user' => array(self::BELONGS_TO, 'User', 'user_id'),
Теперь я настроил виртуальный атрибут fullName
в User
Модель как ниже
public function getFullName()
{
if($this->user_type=='admin')
return $this->admin->full_name;
else if($this->user_type=='editor')
return $this->editor->full_name;
}
Я могу показать виртуальный атрибут, fullName
в сетке, но как мне добавить фильтр к атрибуту и сделать его сортируемым в сетке?
УПАДТЕ 1:
Я обновил функцию поиска моделей () в соответствии с ответом @Jon, как показано ниже
public function search()
{
$criteria=new CDbCriteria;
$criteria->select=array('*','COALESCE( editor.full_name,admin.first_name, \'\') AS calculatedName');
$criteria->with=array('editor','admin');
$criteria->compare('calculatedName',$this->calculatedName,true);
$criteria->compare('email',$this->email,true);
$criteria->compare('user_type',$this->user_type);
return new CActiveDataProvider($this, array(
'criteria'=>$criteria,
));
}
Имена как администраторов, так и редакторов правильно отображаются в сетке. Но когда я делаю поиск через фильтр, возникает следующее исключение,
CDbCommand failed to execute the SQL statement: SQLSTATE[42S22]: Column not found: 1054 Unknown column 'calculatedName' in 'where clause'. The SQL statement executed was: SELECT COUNT(DISTINCT `t`.`id`) FROM `user` `t` LEFT OUTER JOIN `editor` `editor` ON (`editor`.`user_id`=`t`.`id`) LEFT OUTER JOIN `admin` `admin` ON (`admin`.`user_id`=`t`.`id`) WHERE (calculatedName LIKE :ycp0) (C:\xampplite\htdocs\yii\framework\db\CDbCommand.php:528)</p><pre>#0 C:\xampplite\htdocs\yii\framework\db\CDbCommand.php(425):
Как я могу избавиться от этого?
ОБНОВЛЕНИЕ 2: Моя ошибка. Он отлично работает, когда я изменил строку
$criteria->compare('calculatedName',$this->calculatedName,true);
в
$criteria->compare('COALESCE( editor.full_name,admin.first_name, \'\')',$this->calculatedName,true);
и кстати спасибо @Jon.
1 ответ
То, что вы пытаетесь сделать здесь, это эффективно добавить вычисляемый столбец в набор результатов. Представьте себе, что в запросе SQL, который используется для получения результатов, вы будете Admin
а также Editor
столы, так Admin.full_name
а также Editor.full_name
это два столбца, которые будут участвовать в расчете желаемого значения.
Так как хотя бы один Admin.full_name
а также Editor.full_name
всегда будет NULL
формула для расчета окончательного значения будет
COALESCE(Admin.full_name, Editor.full_name, '')
Теперь, когда у вас есть расчетная формула, вам нужно выполнить следующие шаги:
- Добавьте столбец для чтения и записи в вашу модель, чтобы получить вычисленный столбец
- Создать
CDbCriteria
которая объединяет две таблицы и включает вычисляемый столбец - Создать
CSort
описывает, как рассчитанный столбец должен влиять на порядок записи - Создать
CActiveDataProvider
который использует эти критерии и параметры сортировки - Поток поставщика данных на ваш
CGridView
Итак, сначала добавьте публичное свойство в модель:
public $calculatedName;
А потом:
$criteria = new CDbCriteria(array(
'select' => array(
'*',
'COALESCE(Admin.full_name, Editor.full_name, \'\') AS calculatedName',
),
'with' => array('Admin', 'Editor'),
// other options here
));
$sort = new CSort;
$sort->attributes = array(
'calculatedName' => array(
'asc' => 'COALESCE(Admin.full_name, Editor.full_name, \'\')',
'desc' => 'COALESCE(Admin.full_name, Editor.full_name, \'\') DESC',
),
// other sort order definitions here
);
$dataProvider = new CActiveDataProvider('User', array(
'criteria' => $criteria,
'sort' => $sort,
));
И, наконец, использовать $dataProvider
заполнить вашу сетку; использование calculatedName
как имя столбца.
Извиняюсь, если я неправильно понял некоторые детали, поскольку я фактически не управлял этим.
Обновление: оказывается, что Yii не нравится, если вы укажете CDbCriteria.select
в виде строки, и эта строка содержит запятые, не используемые для разделения столбцов (например, запятые, используемые для разделения аргументов COALESCE
). благодарно CDbCriteria
также позволяет передавать столбцы в виде массива, что позволяет обойти эту проблему. Я обновил код выше, чтобы соответствовать.
Для всех, кому любопытно, код обидчика - это.