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, '')

Теперь, когда у вас есть расчетная формула, вам нужно выполнить следующие шаги:

  1. Добавьте столбец для чтения и записи в вашу модель, чтобы получить вычисленный столбец
  2. Создать CDbCriteria которая объединяет две таблицы и включает вычисляемый столбец
  3. Создать CSort описывает, как рассчитанный столбец должен влиять на порядок записи
  4. Создать CActiveDataProvider который использует эти критерии и параметры сортировки
  5. Поток поставщика данных на ваш 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 также позволяет передавать столбцы в виде массива, что позволяет обойти эту проблему. Я обновил код выше, чтобы соответствовать.

Для всех, кому любопытно, код обидчика - это.

Другие вопросы по тегам