yii2 load 时不加载非验证字段

第一步:数据发送到后台后,通过 $data = YII::$app->request->post() (假如是post请求)
$model = new User();
调用$model->load()把接受的数据 $data 载入对象中

第二步:
看load方法 (vendor\yiisoft\yii2\base\Model.php)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
   public function load($data, $formName = null)
    {
        $scope = $formName === null ? $this->formName() : $formName;
        if ($scope === '' && !empty($data)) {
            $this->setAttributes($data);
 
            return true;
        } elseif (isset($data[$scope])) {
            $this->setAttributes($data[$scope]);
 
            return true;
        }
        return false;
    }

第三步:
其中$data是我们第一步中传入的数据($data);$formName 是表单的name
1.当$formName 为空时 通过$this->formName() 获取
看formName()方法:

1
2
3
4
5
    public function formName()
    {
        $reflector = new ReflectionClass($this);
        return $reflector->getShortName();
    }

该方法通过反射获取到当前模型的名称(不带命名空间)

第四步:
如果$data 中存在 $scope 作为键值的数据,则 调用$this->setAttributes($data);否则返回false (也就是载入失败)

第五步:
看 $this->setAttributes($data)

1
2
3
4
5
6
7
8
9
10
11
12
13
    public function setAttributes($values, $safeOnly = true)
    {
        if (is_array($values)) {
            $attributes = array_flip($safeOnly ? $this->safeAttributes() : $this->attributes());
            foreach ($values as $name => $value) {
                if (isset($attributes[$name])) {
                    $this->$name = $value;
                } elseif ($safeOnly) {
                    $this->onUnsafeAttribute($name, $value);
                }
            }
        }
    }

从第四步可以看出,$safeOnly使用的是默认值 true;
此时如果$data是一个字符串,那么返回也是载入成功,其实模型($model)并没有做改变
如果$data是一个非空数组 ,将进一步获取$attributes,因为$safeOnly是true 所以三元运算符走 $this->safeAttributes()
看:$this->safeAttributes()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
 
    public function safeAttributes()
    {
        $scenario = $this->getScenario();
        $scenarios = $this->scenarios();
        if (!isset($scenarios[$scenario])) {
            return [];
        }
        $attributes = [];
        foreach ($scenarios[$scenario] as $attribute) {
 
            if ($attribute[0] !== '!' && !in_array('!' . $attribute, $scenarios[$scenario])) {
                $attributes[] = $attribute;
            }
        }
 
        return $attributes;
    }

$scenario = $this->getScenario(); //获取到当前场景
$scenarios = $this->scenarios(); //获取所有场景 ,每一个场景中包含的是rules中的字段 ,这也就是为啥没有设置的时候无法载入的问题
看一下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
 
    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);
 
        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);
            }
        }
 
        return $scenarios;
    }

通过跟踪 $this->getValidators() 找到:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
    public function createValidators()
    {
        $validators = new ArrayObject;
        foreach ($this->rules() as $rule) {
            if ($rule instanceof Validator) {
                $validators->append($rule);
            } elseif (is_array($rule) && isset($rule[0], $rule[1])) { // attributes, validator type
                $validator = Validator::createValidator($rule[1], $this, (array) $rule[0], array_slice($rule, 2));
                $validators->append($validator);
            } else {
                throw new InvalidConfigException('Invalid validation rule: a rule must specify both attribute names and validator type.');
            }
        }
        return $validators;
    }

而:$this->rules() 返回的就是当前实例化的模型中 rules 方法

解决方法:
1.在rules中声明需要载入的字段
2.载入后用$this->字段=值

未经允许不得转载:开心乐窝-乐在其中 » yii2 load 时不加载非验证字段

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

微信扫一扫打赏