Yii2 GridView implement Filter and Sort for Values

2019-02-26 13:45发布

问题:

I have 3 Tables:

CREATE TABLE tabCve
(
    intCveID INTEGER NOT NULL AUTO_INCREMENT,
    strNumber VARCHAR(20) NOT NULL,
    fltScore FLOAT(0),
    strDescription TEXT,
    datImported DATETIME NOT NULL DEFAULT NOW(),
    intCvePhaseID INTEGER,
    intCveTypeID INTEGER,
    PRIMARY KEY (intCveID),
    KEY (intCvePhaseID),
    KEY (intCveTypeID)

) ;


CREATE TABLE tabProgress
(
    intProgressID INTEGER NOT NULL AUTO_INCREMENT,
    intProgressCveID INTEGER NOT NULL,
    intProgressUserID INTEGER NOT NULL,
    intProgressStateID INTEGER NOT NULL,
    intProgressCategoryID INTEGER,
    datCreated DATETIME NOT NULL,
    PRIMARY KEY (intProgressID),
    KEY (intProgressCategoryID),
    KEY (intProgressCveID),
    KEY (intProgressStateID),
    KEY (intProgressUserID)

) ;

CREATE TABLE tabCategory
(
    intCategoryID INTEGER NOT NULL AUTO_INCREMENT,
    strCategory VARCHAR(50) NOT NULL,
    PRIMARY KEY (intCategoryID)

) ;

I have created a CRUD with Gii for tabCve. I was successfull in implementing filter and sort functions for fields in referenced tables like intCvePhaseID

Now I would like to implement this for tabCategory via tabProgress the relation between tabCve and tabProgress is 1 to 1.

How do I have to implement it in my SearchModel?

What I did so far:

In the Model:

public function getProgress()
{
    return $this->hasOne(TabProgress::className(),['intProgressCveID' => 'intCveID'])->with(['category']);
}   

public function getCategory()
{
    return $this->hasOne(TabCategory::className(),['intCategoryID' => 'intProgressCategoryID']);
}

In the SearchModel:

public function search($params) { $query = TabCve::find();

$dataProvider = new ActiveDataProvider([
    'query' => $query,
    'sort'=> ['defaultOrder' => ['strNumber' => 'DESC']],
]);

$query->select(["intCveID","strNumber","fltScore","strDescription","datImported","intCvePhaseID","intCveTypeID",'progress.intProgressCategoryID']);
$query->joinWith("phase");
$query->joinWith("type");
$query->joinWith("progress");
$query->Where(['not like', 'strDescription', '** RESERVED **%', false]);
$query->andWhere(['not like', 'strDescription', '** REJECT **%', false]);
//$query->andWhere(["intProgressID" => null]);

$this->load($params);

if (!$this->validate()) {
    // uncomment the following line if you do not want to return any records when validation fails
    // $query->where('0=1');
    return $dataProvider;
}

$query->andFilterWhere([
    'intCveID' => $this->intCveID,
    'fltScore' => $this->fltScore,
    'datImported' => $this->datImported,
]);

$query->andFilterWhere(['like', 'strNumber', $this->strNumber])
    ->andFilterWhere(['like', 'strDescription', $this->strDescription])
    ->andFilterWhere(['like','tabPhase.strPhase', $this->intCvePhaseID])
    ->andFilterWhere(['like','datImported',$this->datImported])
    ->andFilterWhere(['like','tabType.strType', $this->intCveTypeID])
    ->andFilterWhere(['like','tabProgress.tabCategory.strCategory', $this->intCveTypeID])
    ;
return $dataProvider;
}

How do I have to implement the fields in these lines:

$query->select(["intCveID","strNumber","fltScore","strDescription","datImported","intCvePhaseID","intCveTypeID",'progress.intProgressCategoryID']);

and:

->andFilterWhere(['like','tabProgress.tabCategory.strCategory', $this->intCveTypeID])

回答1:

In your seachModel you need public var for filter ..

not need select because this are provide by find.. and is better rearrange the code below

$query->select(["intCveID","strNumber","fltScore","strDescription","datImported","intCvePhaseID","intCveTypeID",'progress.intProgressCategoryID']);
$query->joinWith("phase");
$query->joinWith("type");
$query->joinWith("progress");
$query->Where(['not like', 'strDescription', '** RESERVED **%', false]);
$query->andWhere(['not like', 'strDescription', '** REJECT **%', false]);

in another way like suggested in this doc

http://www.yiiframework.com/wiki/621/filter-sort-by-calculated-related-fields-in-gridview-yii-2-0/

http://www.yiiframework.com/wiki/653/displaying-sorting-and-filtering-model-relations-on-a-gridview/

For

->andFilterWhere(['like','tabProgress.tabCategory.strCategory', 
        $this->intCveTypeID])

the samples provide in the link above suggest the use of getter for retrieve the column you need and the use of this getter also in andFilterWhere

this way :

in your Model you already have a

public function getCategory()
{
    return $this->hasOne(TabCategory::className(),
     ['intCategoryID' =>   'intProgressCategoryID']);
}

then you can buil a getter for for strCategory

public function getStr_category() {
    return $this->category->strCategory;
}

at this point you can retrieve the data in you modelSearch with

->andFilterWhere(['like','str_category', $this->intCveTypeID])


回答2:

visit a complete tutorial about this question in :

http://www.yiiframework.com/wiki/851/yii2-gridview-sorting-and-searching-with-a-junction-table-column-many-to-many-relationship/

according to this tutorial you should : 1. set your related table attribute as public in search model like this :

public $groupname;

2 . include attribute in the rules :

    public function rules() {
        return [
            [['id', 'gender', 'status', 'sentstatus'], 'integer'],
            [['groupname', 'addeddate', 'updateddate'], 'safe'],
        ];
    }
  1. change default query to following code in function search() in search model :

    public function search($params) {
    $query = Contacts::find()->innerJoinWith('groups', true);
    
    
  2. and in andfilterwhere add wanted attribute . like this :

    $query->andFilterWhere(['like', 'firstname', $this->firstname])
                   ... 
                    ->andFilterWhere(['like', 'groupname', $this->groupname]);
    

in your view class and in Gridview your wanted column should like this :

'columns' => [
                ...
            [
                'attribute' => 'tags',
                'format' => 'raw',
                'value' => function ($data) {
                    $groups= '';
                    foreach ($data->groups as $group) {
                        $groups .= '<a href="/group/' . $group->id . '">' .
                        $group->group_name . '</a> | ';
                    }
                    return $groups;
         },
        'filter' => ArrayHelper::map(group::find()->asArray()->all(), 'group_name','group_name'),
                ],

and if table relation is hasOne() you should read this tutorial :

http://www.yiiframework.com/wiki/653/displaying-sorting-and-filtering-model-relations-on-a-gridview/