Yii2的场景如何理解

1.关于场景(scenarios)这个问题,开始搜了很多文章,看了其实有点容易被误导,所以我推荐可以的话可以看一看源码。

2.直接先给结论:

在大多数情况下,是不需要重写 scenarios() 的。通过配置 rules() 来改变 scenarios() 的返回值,而不是直接手动覆盖 sceanrios().覆盖带来的一个明显的弊端是:你的精力被分散到了两个方法内(rules() 和 scenarios()).

3.推荐文章如下:

yiichina.com/question/3042?sort=desc 

4.你可以把scenarios源码复制到子类当中进行修改观看这个scenarios()是怎么工作的。

step1.这是我的rules()函数:

public function rules()
    {
        return [
            [['user_id', 'create_time'], 'integer'],
            [['content', 'picture_url'], 'string', 'max' => 128],
            [['user_id'], 'exist', 'skipOnError' => true, 'targetClass' => User::className(), 'targetAttribute' => ['user_id' => 'id']],
            [['imageFile'],'file','skipOnEmpty'=>false,'extensions'=>'png,jpg','on'=> 
             ['create']],
        ];
    }

 

step2. 我把scenarios()源码复制到了子类当中,方便修改:class Friend extends \yii\db\ActiveRecord{ }

class Friend extends \yii\db\ActiveRecord
{
 /***/
public function scenarios()
    {
        $scenarios = [self::SCENARIO_DEFAULT => []];
        foreach ($this->getValidators() as $validator) {
            foreach ($validator->on as $scenario) {
                $scenarios[$scenario] = [];
            }
            foreach ($validator->except as $scenario) {
                $scenarios[$scenario] = [];
            }
        }
        $names = array_keys($scenarios);
        
        //这四句是我自己调试的内容
        echo "第一步把rules()中所有场景都找出来:";
        echo "<pre>";     
        print_r($names);
        echo "<br><br>";

        foreach ($this->getValidators() as $validator) {
            if (empty($validator->on) && empty($validator->except)) {
                foreach ($names as $name) {
                    foreach ($validator->attributes as $attribute) {
                        $scenarios[$name][$attribute] = true;
                    }
                }
            } elseif (empty($validator->on)) {
                foreach ($names as $name) {
                    if (!in_array($name, $validator->except, true)) {
                        foreach ($validator->attributes as $attribute) {
                            $scenarios[$name][$attribute] = true;
                        }
                    }
                }
            } else {
                foreach ($validator->on as $name) {
                    foreach ($validator->attributes as $attribute) {
                        $scenarios[$name][$attribute] = true;
                    }
                }
            }
        }



        foreach ($scenarios as $scenario => $attributes) {
            if (!empty($attributes)) {
                $scenarios[$scenario] = array_keys($attributes);
            }
        }

        //这五句是我自己调试的内容
        echo "第二步把每个场景的的内容都对应上去:";
        echo "<pre>";     //第二步把每个场景的的内容都对应上去
        print_r($scenarios);
        echo "<br><br>";
        exit(0);

        return $scenarios;
    }
}

结果输出如下:

虽然代码里面有很多个foreach,其实你可以理解为就干了上面两件事。

第一步,找出rules()中所有的场景,也就是'on'=>['场景'],default是默认场景。

第二步,把场景对映的验证属性添加到数组里面;

如果一个属性,不开启 on 的话,就默认属于每一个场景。这句话很重要。你可以发现,上面 imageFile开启了 'on'=>['create']

所以default场景就不会去验证imageFile属性,所以我在创建一条新内容的地方调用create场景:

这时候就回去验证照片有没有上传;

而我更新的时候不设置场景,会采用默认场景,所以你可以发现默认场景里面不需要验证imageFile这一项的属性,所以直接更改文字内容就可以了,不会因为没有上传照片而无法通过验证。 

 

 

 

 

 

 

 

 

 

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章