动态模型DynamicModel类,用于实现模型内数据验证:

namespace yii\base;

use yii\validators\Validator;

/**
 * DynamicModel is a model class primarily used to support ad hoc data validation.
 * DynamicModel是一种主要用于支持ad hoc数据验证模型类
 *
 * The typical usage of DynamicModel is as follows,
 * 典型用法如下:
 *
 * ```php
 * public function actionSearch($name, $email)
 * {
 *     $model = DynamicModel::validateData(compact('name', 'email'), [
 *         [['name', 'email'], 'string', 'max' => 128],
 *         ['email', 'email'],
 *     ]);
 *     if ($model->hasErrors()) {
 *         // validation fails
 *     } else {
 *         // validation succeeds
 *     }
 * }
 * ```
 *
 * The above example shows how to validate `$name` and `$email` with the help of DynamicModel.
 * 上面的例子演示了如何用DynamicModel验证用户名`$name`和邮箱`$email`
 * The [[validateData()]] method creates an instance of DynamicModel, defines the attributes
 * using the given data (`name` and `email` in this example), and then calls [[Model::validate()]].
 * yii\base\DynamicModel::validateData() 方法会创建一个 DynamicModel 的实例对象
 * 并通过给定数据定义模型特性(以 name 和email 为例),之后用给定规则调用 yii\base\Model::validate() 方法。
 *
 * You can check the validation result by [[hasErrors()]], like you do with a normal model.
 * 可以通过[[hasErrors()]]方法获取验证结果
 * You may also access the dynamic attributes defined through the model instance, e.g.,
 * `$model->name` and `$model->email`.
 *
 * Alternatively, you may use the following more "classic" syntax to perform ad-hoc data validation:
 * 除此之外呢,你也可以用如下的更加“传统”的语法来执行临时数据验证:
 *
 * ```php
 * $model = new DynamicModel(compact('name', 'email'));
 * $model->addRule(['name', 'email'], 'string', ['max' => 128])
 *     ->addRule('email', 'email')
 *     ->validate();
 * ```
 *
 * DynamicModel implements the above ad-hoc data validation feature by supporting the so-called
 * "dynamic attributes". It basically allows an attribute to be defined dynamically through its constructor
 * or [[defineAttribute()]].
 *
 * @author Qiang Xue <qiang.xue@gmail.com>
 * @since 2.0
 */
class DynamicModel extends Model
{
    /**
     * @var array 动态模型内动态属性
     */
    private $_attributes = [];

    /**
     * Constructors.
     * 构造函数,用于将传入的属性赋值给_attributes,便于使用
     * @param array $attributes the dynamic attributes (name-value pairs, or names) being defined
     * @param array $config the configuration array to be applied to this object.
     */
    public function __construct(array $attributes = [], $config = [])
    {
        foreach ($attributes as $name => $value) {//遍历传入的属性
            if (is_int($name)) {//如果$name是整型,说明只传入了属性名,将属性名写入_attributes
                $this->_attributes[$value] = null;
            } else {//否则,按键值对的形式写入
                $this->_attributes[$name] = $value;
            }
        }
        parent::__construct($config);//调用父类方法配置对象
    }

    /**
     * @inheritdoc  重写父类的__get方法,实现从_attributes中取值
     */
    public function __get($name)
    {
        if (array_key_exists($name, $this->_attributes)) {//如果传入的$name在_attributes中存在,则从_attributes中取值
            return $this->_attributes[$name];
        } else {//否则调用父类的__get方法取属性值
            return parent::__get($name);
        }
    }

    /**
     * @inheritdoc 重写父类的__set方法,实现给_attributes设置值
     */
    public function __set($name, $value)
    {
        if (array_key_exists($name, $this->_attributes)) {//如果传入的$name在_attributes中存在,则将动态属性$name的值设置为$value
            $this->_attributes[$name] = $value;
        } else {//否则调用父类的__set方法设置动态属性值
            parent::__set($name, $value);
        }
    }

    /**
     * @inheritdoc 同上,重写父类的__isset方法,实现判断_attributes中是否设置$name值
     */
    public function __isset($name)
    {
        if (array_key_exists($name, $this->_attributes)) {
            return isset($this->_attributes[$name]);
        } else {
            return parent::__isset($name);
        }
    }

    /**
     * @inheritdoc 同上,重写父类的__unset方法,实现注销_attributes中的$name动态属性值
     */
    public function __unset($name)
    {
        if (array_key_exists($name, $this->_attributes)) {
            unset($this->_attributes[$name]);
        } else {
            parent::__unset($name);
        }
    }

    /**
     * Defines an attribute.
     * 用于定义DynamicModel 的动态属性的方法
     * @param string $name the attribute name
     * @param mixed $value the attribute value
     */
    public function defineAttribute($name, $value = null)
    {
        $this->_attributes[$name] = $value;
    }

    /**
     * Undefines an attribute.
     * 用于注销DynamicModel 的动态属性的方法
     * @param string $name the attribute name
     */
    public function undefineAttribute($name)
    {
        unset($this->_attributes[$name]);
    }

    /**
     * Adds a validation rule to this model.
     * 添加验证规则
     * You can also directly manipulate [[validators]] to add or remove validation rules.
     * 可以直接调用[[validators]]来添加或者删除验证规则,本方法提供了一个短方法
     * This method provides a shortcut.
     * @param string|array $attributes the attribute(s) to be validated by the rule
     * @param mixed $validator the validator for the rule.This can be a built-in validator name,
     * a method name of the model class, an anonymous function, or a validator class name.
     * @param array $options the options (name-value pairs) to be applied to the validator
     * @return $this the model itself
     */
    public function addRule($attributes, $validator, $options = [])
    {
        $validators = $this->getValidators();//返回所有的验证规则对象
        //生成Validator对象,并且插入 $validators中
        $validators->append(Validator::createValidator($validator, $this, (array) $attributes, $options));

        return $this;
    }

    /**
     * Validates the given data with the specified validation rules.
     * 通过指定的规则验证给定的数据
     * This method will create a DynamicModel instance, populate it with the data to be validated,
     * create the specified validation rules, and then validate the data using these rules.
     * @param array $data the data (name-value pairs) to be validated
     * @param array $rules the validation rules. Please refer to [[Model::rules()]] on the format of this parameter.
     * @return static the model instance that contains the data being validated
     * @throws InvalidConfigException if a validation rule is not specified correctly.
     */
    public static function validateData(array $data, $rules = [])
    {
        /* @var $model DynamicModel */
        /* new static 用于实例化调用类  new self 用于实例化代码书写的那个类*/
        $model = new static($data);//实例化调用类,将$data赋值给_attributes
        if (!empty($rules)) {
            $validators = $model->getValidators();//获取所有定义的验证规则对象
            foreach ($rules as $rule) {//遍历传入的验证规则
                if ($rule instanceof Validator) {//如果$rule是Validator的实例,则添加到$validators中
                    $validators->append($rule);
                } elseif (is_array($rule) && isset($rule[0], $rule[1])) { // attributes, validator type
                   //如果$rule是数组,则判断动态属性和验证类型是否存在,存在怎创建Validator对象,添加到$validators中
                    $validator = Validator::createValidator($rule[1], $model, (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.');
                }
            }
        }

        $model->validate();//执行验证

        return $model;
    }

    /**
     * @inheritdoc //返回所有的动态属性
     */
    public function attributes()
    {
        return array_keys($this->_attributes);
    }
}

Yii源码阅读笔记(二十九)的更多相关文章

  1. Yii源码阅读笔记(十九)

    View中渲染view视图文件的前置和后置方法,以及渲染动态内容的方法: /** * @return string|boolean the view file currently being rend ...

  2. Yii源码阅读笔记(十二)

    Action类,控制器中方法的基类: namespace yii\base; use Yii; /** * Action is the base class for all controller ac ...

  3. Yii源码阅读笔记(十八)

    View中的查找视图文件方法和渲染文件方法 /** * Finds the view file based on the given view name. * 通过view文件名查找view文件 * ...

  4. Yii源码阅读笔记(十五)

    Model类,集中整个应用的数据和业务逻辑——验证 /** * Returns the attribute labels. * 返回属性的标签 * * Attribute labels are mai ...

  5. Yii源码阅读笔记(十六)

    Model类,集中整个应用的数据和业务逻辑—— /** * Generates a user friendly attribute label based on the give attribute ...

  6. Yii源码阅读笔记(十四)

    Model类,集中整个应用的数据和业务逻辑——场景.属性和标签: /** * Returns a list of scenarios and the corresponding active attr ...

  7. Yii源码阅读笔记(十)

    控制器类,所有控制器的基类,用于调用模型和布局,输出到视图 namespace yii\base; use Yii; /** * Controller is the base class for cl ...

  8. Yii源码阅读笔记(一)

    今天开始阅读yii2的源码,想深入了解一下yii框架的工作原理,同时学习一下优秀的编码规范和风格.在此记录一下阅读中的小心得. 每个框架都有一个入口文件,首先从入口文件开始,yii2的入口文件位于we ...

  9. werkzeug源码阅读笔记(二) 下

    wsgi.py----第二部分 pop_path_info()函数 先测试一下这个函数的作用: >>> from werkzeug.wsgi import pop_path_info ...

  10. werkzeug源码阅读笔记(二) 上

    因为第一部分是关于初始化的部分的,我就没有发布出来~ wsgi.py----第一部分 在分析这个模块之前, 需要了解一下WSGI, 大致了解了之后再继续~ get_current_url()函数 很明 ...

随机推荐

  1. js简版图片左右切换功能

    function leftMove(obj,direction,lis){ var num = 0; var liWidth = lis[0].offsetWidth; setInterval(fun ...

  2. vs2010 安装MVC 3.0

    下载链接如下: MVC 3安装包:http://www.microsoft.com/downloads/zh-cn/details.aspx?familyid=d2928bc1-f48c-4e95-a ...

  3. Python基础4- 字符串

    Python字符串是由数字.字母.下划线组成的一串字符,我们可以使用引号来创建字符串.如:str = 'Helloworld'在Python中没有char类型,单个字符也作为string使用; Pyt ...

  4. WPF拖放功能实现zz

    写在前面:本文为即兴而作,因此难免有疏漏和词不达意的地方.在这里,非常期望您提供评论,分享您的想法和建议. 这是一篇介绍如何在WPF中实现拖放功能的短文. 首先要读者清楚的一件事情是:拖放主要分为拖放 ...

  5. 学习编写Windows Live Writer插件

    1.参考链接 参考:http://www.cnblogs.com/liulun/archive/2009/05/27/1491116.html Live Writer API参考:http://msd ...

  6. SPFA 的两个优化

    From NOCOW SPFA算法有两个优化算法 SLF 和 LLL: SLF:Small Label First 策略,设要加入的节点是j,队首元素为i,若dist(j)<dist(i),则将 ...

  7. Android 魅族等SmartBar适配

    通过反射获取是否含有SmartBar: /** * 判断是否有SmartBar */ private boolean hasSmartBar() { // SP存储是否显示SmartBar if (! ...

  8. [Leetcode] Recover Binary Search Tree

    Two elements of a binary search tree (BST) are swapped by mistake. Recover the tree without changing ...

  9. 20161007 NOIP 模拟赛 T1 解题报告

    排序 3.1 题意描述 众所周知,熟练掌握至少一种排序算法是参加NOIP的必备技能.常见的排序算法有冒泡 排序.归并排序.快速排序.奇偶排序.猴子排序.梳排序.鸡尾酒排序.臭皮匠排序等. 在这里,介绍 ...

  10. CF 346B. Lucky Common Subsequence(DP+KMP)

    这题确实很棒..又是无想法..其实是AC自动机+DP的感觉,但是只有一个串,用kmp就行了. dp[i][j][k],k代表前缀为virus[k]的状态,len表示其他所有状态串,处理出Ac[len] ...