3

I have a yii2 GridView, as generated by gii CRUD.

I point my browser to /model/index. I do not include any search values in the GET string. But the GridView filter comes pre-populated with values. enter image description here

Even if I try to delete or replace these filter-values, the pre-populated values spring back.

I am noticing that these prepopulated-values come from the model's beforeValidate() method.

public function beforeValidate()
{
    if (parent::beforeValidate()) {
        if ($this->isNewRecord) {
            $this->created_at = time();
            $this->b_soft_deleted = 0;
        }
        $this->updated_at = time();
        return true;
    }           
    return false;
}

Evidently, the GridView Filter calls beforeValidate() and the uses these values for a filter...

  • Why is this happening?
  • What can I do to get a clean slate for filter values?

(Running yii2 2.0.10 on php 7.0.14)

update My Search Model is

<?php

namespace common\models\generated;

use Yii;
use yii\base\Model;
use yii\data\ActiveDataProvider;
use common\models\Article;

/**
 * ArticleSearch represents the model behind the search form about     `common\models\Article`.
 */
class ArticleSearch extends Article
{
/**
 * @inheritdoc
 */
public function rules()
{
    return [
        [['id', 'title', 'description', 'positive_keywords', 'negative_keywords'], 'safe'],
        [['created_at', 'updated_at', 'b_soft_deleted'], 'integer'],
    ];
}

/**
 * @inheritdoc
 */
public function scenarios()
{
    // bypass scenarios() implementation in the parent class
    return Model::scenarios();
}

/**
 * Creates data provider instance with search query applied
 *
 * @param array $params
 *
 * @return ActiveDataProvider
 */
public function search($params)
{
    $query = Article::find();

    // add conditions that should always apply here

    $dataProvider = new ActiveDataProvider([
        'query' => $query,
    ]);

    $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;
    }

    // grid filtering conditions
    $query->andFilterWhere([
        'created_at' => $this->created_at,
        'updated_at' => $this->updated_at,
        'b_soft_deleted' => $this->b_soft_deleted,
    ]);

    $query->andFilterWhere(['like', 'id', $this->id])
        ->andFilterWhere(['like', 'title', $this->title])
        ->andFilterWhere(['like', 'description', $this->description])
        ->andFilterWhere(['like', 'positive_keywords', $this->positive_keywords])
        ->andFilterWhere(['like', 'negative_keywords', $this->negative_keywords]);

    return $dataProvider;
}

}

Ivo Renkema
  • 2,188
  • 1
  • 29
  • 40

2 Answers2

6

You are setting attributes in beforeValidate() which are applied when $this->validate() is called (no matter the validation result).

You need to move this set somewhere else or...

If I'm guessing correctly you do set created_at and updated_at because these fields are marked as not null in your database and because of that gii generated required rules for them.
The proper way of dealing with such attributes is to remove the required rule for them and add yii\behaviors\TimestampBehavior that takes care of setting them on model save step.
This way you don't see validation errors for the model and don't have to set these manually and database columns are filled properly.

And this whole GridView problem is gone.

Bizley
  • 17,392
  • 5
  • 49
  • 59
1

Based on Bizley solution, we also may not use TimestampBehavior, just we should cancel the required and then place that logic in beforeSave. This is more general solution if you would like to do any logic or creating some pre-made values.

Community
  • 1
  • 1
SaidbakR
  • 13,303
  • 20
  • 101
  • 195