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这一项的属性,所以直接更改文字内容就可以了,不会因为没有上传照片而无法通过验证。