yii — фильтрация в CGridView для полей с релейшенами

CGridView позволяет быстро добавить фильтр для колонки c релейшеном. Но тут есть несколько нюансов.

Предположим у нас есть абстрактное поле «field_id» которое ссылается на табличку с моделями «WorkModel» через релейшен с именем «RelationsField».

Самый простой способ добавить фильтр: добавить в описание колонки ключ filter c данными.

array(
    'name' => 'field_id',
    'value'=> 'empty($data->RelationsField) ? "" : $data->RelationsField->name',
    'filter'=> CHtml::activeDropDownList( $model, 'field_id',
        CHtml::listData(WorkModel::model()->findAll(),'id','name')),
),

Все хорошо только справочник может быть очень большой.
Страниц погружается долго. Особенно на ajax заметно.
Самый простой способ убрать фильтр и фильтровать на уровне получения CActiveDataProvider
Если пользователь ввел цифру то фильтруем по id, а иначе по релейшену

public function search()
{
    ...
    if(is_numeric($this->field_id)){
        $criteria->compare('field_id',$this->field_id);
    }
    else{
        $criteria->with[] = 'RelationsField';
        $criteria->compare('RelationsField.name', $this->field_id, true);
    }
}

Или вариант с хэлпер функцией:

/**
 * Условие поиска для поля с релешенном:
 *  - Если начинается с решетки #ЦИФРА то ищем сразу по полю
 *  - Иначе ищем по релейшену
 * @param CDbCriteria $criteria     Критерий
 * @param CActiveRecord $model      фильтр модель. Обычно $this
 * @param string $attr              Атрибут модели
 * @param string $relations         Релейшен в котором ищем если текст
 * @param string|null $attrRelations  Поле релейшена. Если не указано то считаем что оно указано в $relations
 */
public static function CriteriaSearchRelations($criteria, $model, $attr, $relations, $attrRelations = null){
    $value = trim($model->$attr);
    $isId = strpos($value, '#') == 0 && is_numeric(ltrim($value,'#'));

    if($isId){
        $value = ltrim($value,'#');
        $criteria->compare($attr, $value);
    }
    else{
        if(empty($attrRelations)){
            $pos = strrpos($relations,'.');
            $attrRelations = substr($relations, $pos + 1);
            $relations = substr($relations, 0, $pos);
        }

        $criteria->with[] = $relations;
        $criteria->compare("$relations.$attrRelations", $value, true);
    }
}

public function search()
{
    ...
 HelperDirectory::CriteriaSearchRelations($criteria, $this, 'field_id', 'RelationsField.name');
}

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *