最近在使用场景的时候碰到一些不解的问题,我简单模拟下: 我新建一张表info,有name和age2个字段 模型代码:ios
public function rules() { return [ [['age'], 'integer'], [['name'], 'string', 'max' => 22], ['name','required','message'=>'姓名不能为空','on'=>['add','update']], ['age','required','message'=>'年龄不能为空','on'=>'add'], ['age','isMath','on'=>'add'] ]; } public function scenarios() { return [ 'add' => ['age','name'], 'update'=>['name'] ]; }
当我进行编辑操做的时候,使用$model->scenario = 'update';也就是使用update场景,出现的结果是:name改变了age居然没有更改,我把代码修改下数据库
public function scenarios() { return [ 'add' => ['age','name'], 'update'=>['name','age'] //这里加个age ]; }
这个时候正常修改了name和age字段数组
还有就是我不重写scenarios()方法,也是正常执行验证的框架
因此有2个问题: 1.重写scenarios()方法,具体应该在何时? 2.上面代码加个age和不加age区别是什么?在update场景下我只验证name字段,age只在add场景下,可是在update场景下'update'=>['name']没有写age就不能修改age字段?????yii
答:ui
默认状况下,scenarios() 返回的是一个关系数组,键是模型中全部可用的场景,值是场景对应的 active attributes 列表。active attributes 有两个特色:code
$model->load() && $model->save()
保存数据时只保存 active attributes;在你的例子中,把 'age' 从 update 场景中移除意味着 age 再也不是 active attribute, 这就是为何对 age 的修改没有写入数据库的缘由。get
默认的 scenarios() 过程(以你的例子中声明的规则为例)string
scenarios() 会进行两次遍历操做。首先遍历 rules 中声明的规则,把全部可用的场景找出来,并初始化数组,以你的例子中的 rules 为例,值为:io
[ 'default' => [], // 框架自带的默认场景 'add' => [], 'update' => [], ]
第二次遍历时,对每一个 rule 中声明的 attributes “对号入座”,若是 rule 中不带 'on' 属性,表示该属性所属的规则适用于全部场景(例如 [['age'], 'integer']
), 会将 'age' 追加到全部场景的 active attibutes 列表中;若是指定了场景值,仅在对应的场景下的active attributes 内追加。
通过这两次遍历,scenarios() 最终返回的值将是:
[ 'default' => ['age', 'name'], 'add' => ['age', 'name'], 'update' => ['age', 'name'], ]
能够看到, 'age' 在每一个场景中都是 active attribute, 这就是为何在你不重写 scenarios() 的状况下,对 age 的修改也能保存的缘由。
了解了这个过程,个人理解是:在大多数状况下,是不须要重写 scenarios() 的,经过配置 rules() 来改变 scenarios() 的返回值,而不是直接手动覆盖 sceanrios(). 覆盖带来的一个明显的弊端是:你的精力被分散到了两个方法内(rules() 和 scenarios()),假设未来你的 info 表又新增了一列,在 rules() 追加新的规则的同时,你还要修改重写后的 scenarios(), 把新增长的列追加进去使其成为 active attribute,不然就会出现新增列的数据没法存入数据库。使用默认的 scenarios() 的话,只须要将精力放在 rules() 上便可。