Model类,集中整个应用的数据和业务逻辑——验证

  /**
     * Returns the attribute labels.
     * 返回属性的标签
     *
     * Attribute labels are mainly used for display purpose. For example, given an attribute
     * `firstName`, we can declare a label `First Name` which is more user-friendly and can
     * be displayed to end users.
     * 属性标签主要用于显示目的,例如给属性'firstName'一个‘First Name’标签,能够更友好的显示给最终用户
     *
     * By default an attribute label is generated using [[generateAttributeLabel()]].
     * This method allows you to explicitly specify attribute labels.
     * 默认调用[[generateAttributeLabel()]]方法生成标签
     * Note, in order to inherit labels defined in the parent class, a child class needs to
     * merge the parent labels with child labels using functions such as `array_merge()`.
     * 注意,为了继承父类的标签,之类需要调用`array_merge()`合并父类的标签
     *
     * @return array attribute labels (name => label)
     * @see generateAttributeLabel()
     */
    public function attributeLabels()
    {
        return [];
    }

    /**
     * Returns the attribute hints.
     * 返回属性提示
     * Attribute hints are mainly used for display purpose. For example, given an attribute
     * `isPublic`, we can declare a hint `Whether the post should be visible for not logged in users`,
     * which provides user-friendly description of the attribute meaning and can be displayed to end users.
     * 属性提示主要用于显示目的,例如给一个属性`isPublic`,我们能够设置一个 `是否显示给最终用户` 的提示,
     * Unlike label hint will not be generated, if its explicit declaration is omitted.
     *
     * Note, in order to inherit hints defined in the parent class, a child class needs to
     * merge the parent hints with child hints using functions such as `array_merge()`.
     *
     * @return array attribute hints (name => hint)
     * @since 2.0.4
     */
    public function attributeHints()
    {
        return [];
    }

    /**
     * Performs the data validation.
     * 执行数据验证
     *
     * This method executes the validation rules applicable to the current [[scenario]].
     * 该方法执行指定场景下的数据验证
     * The following criteria are used to determine whether a rule is currently applicable:
     * 下面的标准来确定一个规则是否适用:
     *
     * - the rule must be associated with the attributes relevant to the current scenario;
     *   规则必须与当前场景相关的属性关联
     * - the rules must be effective for the current scenario.
     *   规则必须是有效的当前场景
     *
     * This method will call [[beforeValidate()]] and [[afterValidate()]] before and
     * after the actual validation, respectively. If [[beforeValidate()]] returns false,
     * the validation will be cancelled and [[afterValidate()]] will not be called.
     * 该方法会调用[[beforeValidate()]] 和[[afterValidate()]]方法
     *
     * Errors found during the validation can be retrieved via [[getErrors()]],
     * [[getFirstErrors()]] and [[getFirstError()]].
     * 验证的错误信息可以通过[[getErrors()]],[[getFirstErrors()]]和 [[getFirstError()]].方法获取
     *
     * @param array $attributeNames list of attribute names that should be validated.
     * If this parameter is empty, it means any attribute listed in the applicable
     * validation rules should be validated.
     * @param boolean $clearErrors whether to call [[clearErrors()]] before performing validation
     * @return boolean whether the validation is successful without any error.
     * @throws InvalidParamException if the current scenario is unknown.
     */
    public function validate($attributeNames = null, $clearErrors = true)
    {
        if ($clearErrors) {
            //清除所有的错误信息
            $this->clearErrors();
        }

        if (!$this->beforeValidate()) {
            //如果beforeValidate()返回false,则终止执行,返回false
            return false;
        }
        //取得所有场景及与之对应的 active 属性的列表
        $scenarios = $this->scenarios();
        //取得当前使用场景
        $scenario = $this->getScenario();
        if (!isset($scenarios[$scenario])) {
            //判断是否在场景列表中
            throw new InvalidParamException("Unknown scenario: $scenario");
        }

        if ($attributeNames === null) {
            //属性名为空,返回所有的active属性
            $attributeNames = $this->activeAttributes();
        }

        foreach ($this->getActiveValidators() as $validator) {
            //返回当前场景下的validator,然后遍历验证
            $validator->validateAttributes($this, $attributeNames);
        }
        //调用后置方法afterValidate();
        $this->afterValidate();

        return !$this->hasErrors();
    }

    /**
     * This method is invoked before validation starts.
     * 在验证方法前调用,触发`beforeValidate`事件,用于验证前的初步检查
     * The default implementation raises a `beforeValidate` event.
     * You may override this method to do preliminary checks before validation.
     * Make sure the parent implementation is invoked so that the event can be raised.
     * @return boolean whether the validation should be executed. Defaults to true.
     * If false is returned, the validation will stop and the model is considered invalid.
     */
    public function beforeValidate()
    {
        $event = new ModelEvent;
        $this->trigger(self::EVENT_BEFORE_VALIDATE, $event);

        return $event->isValid;
    }

    /**
     * This method is invoked after validation ends.
     * 在验证方法后调用,触发`afterValidate`事件,用于验证后的处理
     * The default implementation raises an `afterValidate` event.
     * You may override this method to do postprocessing after validation.
     * Make sure the parent implementation is invoked so that the event can be raised.
     */
    public function afterValidate()
    {
        $this->trigger(self::EVENT_AFTER_VALIDATE);
    }

    /**
     * Returns all the validators declared in [[rules()]].
     * 返回在[[rules()]]中定义的所有validators
     *
     * This method differs from [[getActiveValidators()]] in that the latter
     * only returns the validators applicable to the current [[scenario]].
     * 该方法不同于[[getActiveValidators()]] ,后者只返回当前场景下的validator
     *
     * Because this method returns an ArrayObject object, you may
     * manipulate it by inserting or removing validators (useful in model behaviors).
     * 该方法返回ArrayObject对象,可以进行添加或删除操作,例如:
     * For example,
     *
     * ```php
     * $model->validators[] = $newValidator;
     * ```
     *
     * @return ArrayObject|\yii\validators\Validator[] all the validators declared in the model.
     */
    public function getValidators()
    {
        if ($this->_validators === null) {
            //_validators中没有值,则调用createValidators()创建Validator
            $this->_validators = $this->createValidators();
        }
        return $this->_validators;
    }

    /**
     * Returns the validators applicable to the current [[scenario]].
     * 返回当前场景下的validator
     * @param string $attribute the name of the attribute whose applicable validators should be returned.
     * If this is null, the validators for ALL attributes in the model will be returned.
     * @return \yii\validators\Validator[] the validators applicable to the current [[scenario]].
     */
    public function getActiveValidators($attribute = null)
    {
        $validators = [];
        //获取当前模型的使用场景
        $scenario = $this->getScenario();
        foreach ($this->getValidators() as $validator) {
            if ($validator->isActive($scenario) && ($attribute === null || in_array($attribute, $validator->attributes, true))) {
                //获取当前场景下的validator
                $validators[] = $validator;
            }
        }
        return $validators;
    }

    /**
     * Creates validator objects based on the validation rules specified in [[rules()]].
     * 通过[[rules()]]中指定的验证规则生成验证对象
     * Unlike [[getValidators()]], each time this method is called, a new list of validators will be returned.
     * @return ArrayObject validators
     * @throws InvalidConfigException if any validation rule configuration is invalid
     */
    public function createValidators()
    {
        //创建ArrayObject实例
        $validators = new ArrayObject;
        foreach ($this->rules() as $rule) {
            //遍历[[rules()]]
            if ($rule instanceof Validator) {
                //如果$rule是Validator的实例,则直接写入$validators中
                $validators->append($rule);
            } elseif (is_array($rule) && isset($rule[0], $rule[1])) { // attributes属性, validator type验证类型
                //否则,调用Validator::createValidator生成Validator的实例
                $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;
    }

    /**
     * Returns a value indicating whether the attribute is required.
     * 返回是否该属性值是required
     * This is determined by checking if the attribute is associated with a
     * [[\yii\validators\RequiredValidator|required]] validation rule in the
     * current [[scenario]].
     *
     * Note that when the validator has a conditional validation applied using
     * [[\yii\validators\RequiredValidator::$when|$when]] this method will return
     * `false` regardless of the `when` condition because it may be called be
     * before the model is loaded with data.
     *
     * @param string $attribute attribute name
     * @return boolean whether the attribute is required
     */
    public function isAttributeRequired($attribute)
    {
        foreach ($this->getActiveValidators($attribute) as $validator) {
            if ($validator instanceof RequiredValidator && $validator->when === null) {
                return true;
            }
        }
        return false;
    }

    /**
     * Returns a value indicating whether the attribute is safe for massive assignments.
     * 返回是否该属性值是批量操作安全的
     * @param string $attribute attribute name
     * @return boolean whether the attribute is safe for massive assignments
     * @see safeAttributes()
     */
    public function isAttributeSafe($attribute)
    {
        return in_array($attribute, $this->safeAttributes(), true);
    }

    /**
     * Returns a value indicating whether the attribute is active in the current scenario.
     * 返回是否该属性值是active
     * @param string $attribute attribute name
     * @return boolean whether the attribute is active in the current scenario
     * @see activeAttributes()
     */
    public function isAttributeActive($attribute)
    {
        return in_array($attribute, $this->activeAttributes(), true);
    }

    /**
     * Returns the text label for the specified attribute.
     * 返回指定属性的标签
     * @param string $attribute the attribute name
     * @return string the attribute label
     * @see generateAttributeLabel()
     * @see attributeLabels()
     */
    public function getAttributeLabel($attribute)
    {
        $labels = $this->attributeLabels();
        return isset($labels[$attribute]) ? $labels[$attribute] : $this->generateAttributeLabel($attribute);
    }

    /**
     * Returns the text hint for the specified attribute.
     * 返回指定属性的提示信息
     * @param string $attribute the attribute name
     * @return string the attribute hint
     * @see attributeHints()
     * @since 2.0.4
     */
    public function getAttributeHint($attribute)
    {
        $hints = $this->attributeHints();
        return isset($hints[$attribute]) ? $hints[$attribute] : '';
    }

    /**
     * Returns a value indicating whether there is any validation error.
     * 返回某个值是否有验证错误信息
     * @param string|null $attribute attribute name. Use null to check all attributes.
     * @return boolean whether there is any error.
     */
    public function hasErrors($attribute = null)
    {
        return $attribute === null ? !empty($this->_errors) : isset($this->_errors[$attribute]);
    }

    /**
     * Returns the errors for all attribute or a single attribute.
     * 返回全部或者某个属性的验证错误信息
     * @param string $attribute attribute name. Use null to retrieve errors for all attributes.
     * @property array An array of errors for all attributes. Empty array is returned if no error.
     * The result is a two-dimensional array. See [[getErrors()]] for detailed description.
     * @return array errors for all attributes or the specified attribute. Empty array is returned if no error.
     * Note that when returning errors for all attributes, the result is a two-dimensional array, like the following:
     * 错误信息的格式为二维数组,键名为属性值,键值为错误信息
     * ```php
     * [
     *     'username' => [
     *         'Username is required.',
     *         'Username must contain only word characters.',
     *     ],
     *     'email' => [
     *         'Email address is invalid.',
     *     ]
     * ]
     * ```
     *
     * @see getFirstErrors()
     * @see getFirstError()
     */
    public function getErrors($attribute = null)
    {
        if ($attribute === null) {
            return $this->_errors === null ? [] : $this->_errors;
        } else {
            return isset($this->_errors[$attribute]) ? $this->_errors[$attribute] : [];
        }
    }

    /**
     * Returns the first error of every attribute in the model.
     * 返回当前模型下每一个属性的第一条错误信息
     * @return array the first errors. The array keys are the attribute names, and the array
     * values are the corresponding error messages. An empty array will be returned if there is no error.
     * @see getErrors()
     * @see getFirstError()
     */
    public function getFirstErrors()
    {
        if (empty($this->_errors)) {
            return [];
        } else {
            $errors = [];
            foreach ($this->_errors as $name => $es) {
                if (!empty($es)) {
                    $errors[$name] = reset($es);
                }
            }

            return $errors;
        }
    }

    /**
     * Returns the first error of the specified attribute.
     * 返回指定属性的第一条错误信息
     * @param string $attribute attribute name.
     * @return string the error message. Null is returned if no error.
     * @see getErrors()
     * @see getFirstErrors()
     */
    public function getFirstError($attribute)
    {
        return isset($this->_errors[$attribute]) ? reset($this->_errors[$attribute]) : null;
    }

    /**
     * Adds a new error to the specified attribute.
     * 给指定的属性添加新的错误信息
     *
     * @param string $attribute attribute name
     * @param string $error new error message
     */
    public function addError($attribute, $error = '')
    {
        //将错误信息添加到errors数组中,键名为属性名[],键值为错误信息
        $this->_errors[$attribute][] = $error;
    }

    /**
     * Adds a list of errors.
     * 添加错误信息列表
     * @param array $items a list of errors. The array keys must be attribute names.
     * The array values should be error messages. If an attribute has multiple errors,
     * these errors must be given in terms of an array.
     * You may use the result of [[getErrors()]] as the value for this parameter.
     * @since 2.0.2
     */
    public function addErrors(array $items)
    {
        foreach ($items as $attribute => $errors) {
            if (is_array($errors)) {
                foreach ($errors as $error) {
                    $this->addError($attribute, $error);
                }
            } else {
                $this->addError($attribute, $errors);
            }
        }
    }

    /**
     * Removes errors for all attributes or a single attribute.
     * 清除所有或者指定属性的错误信息
     * @param string $attribute attribute name. Use null to remove errors for all attribute.
     */
    public function clearErrors($attribute = null)
    {
        if ($attribute === null) {
            $this->_errors = [];
        } else {
            unset($this->_errors[$attribute]);
        }
    }

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

  1. Yii源码阅读笔记(五)

    Object 是一个基础类,实现了属性的功能,其基本内容如下: namespace yii\base; use Yii; /** * Object is the base class that imp ...

  2. 重新整理 .net core 实践篇——— 权限源码阅读四十五]

    前言 简单介绍一下权限源码阅读一下. 正文 一直有人对授权这个事情上争论不休,有的人认为在输入账户密码给后台这个时候进行了授权,因为认为发送了一个身份令牌,令牌里面可能有些用户角色信息,认为这就是授权 ...

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

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

  4. Mina源码阅读笔记(五)—Mina对连接的操作IoSession

    IoSession是Mina管理两端的一个重要部分,也是Mina的核心,Session具有了生命周期的概念,它的生命周期和连接时紧密相关的,这点在后面的介绍中会涉及.另外,好像hibernate中也有 ...

  5. J.U.C并发框架源码阅读(十五)CopyOnWriteArrayList

    基于版本jdk1.7.0_80 java.util.concurrent.CopyOnWriteArrayList 代码如下 /* * Copyright (c) 2003, 2011, Oracle ...

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

    Container,用于动态地创建.注入依赖单元,映射依赖关系等功能,减少了许多代码量,降低代码耦合程度,提高项目的可维护性. namespace yii\di; use ReflectionClas ...

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

    Module类中剩余部分代码,通过控制器ID实例化当前模块的控制器,当前模块的Action方法的前置和后置方法: /** * This method is invoked right before a ...

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

    Instance类, 表示依赖注入容器或服务定位器中对某一个对象的引用 namespace yii\di; use Yii; use yii\base\InvalidConfigException; ...

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

    web/Application类的注释,继承base/Application类,针对web应用的一些处理: namespace yii\web; use Yii; use yii\base\Inval ...

随机推荐

  1. .NET的堆和栈01,基本概念、值类型内存分配

    当我们对.NET Framework的一些基本面了解之后,实际上,还是很有必要了解一些更底层的知识.比如.NET Framework是如何进行内存管理的,是如何垃圾回收的......这样,我们才能写出 ...

  2. CI框架获取post和get参数_CodeIgniter心得

    请参考:CI文档的输入类部分: $this->input->post() $this->input->get() ------------------------------- ...

  3. 设计模式学习之简单工厂(Simple Factory,创建型模式)(1)

    简单工厂(Simple Factory,创建型模式) 第一步: 比如我们要采集苹果和香蕉,那么我们需要创建一个Apple类和Banana类,里面各自有采集方法get(),然后通过main方法进行调用, ...

  4. Sublime Text 插件 & 使用技巧

    20 个强大的 Sublime Text 插件http://blog.jobbole.com/58725/ 12个不可不知的Sublime Text应用技巧和诀窍http://segmentfault ...

  5. 在linux上安装psycopg2出错--Error: pg_config executable not found.

    这个错误可能是因为缺少PGSQL的相关库吧. 网上有很多解决办法,我最终用以下方式解决: yum install postgresql postgresql-devel python-devel

  6. 谷歌开源项目Chromium的源码获取与项目构建(Win7+vs10/vs13)

    转自:http://blog.csdn.net/kuerjinjin/article/details/23563059 从12年那会儿开始获取源码和构建chromium项目都是按照那时候的官方要求用w ...

  7. android—获取网络数据

    取网络数据主要靠发交易(或者说请求,接口等),而这些交易由java中的网络通信,HttpURLConnection和HttpClient实现,以下是具体例子.   大家都知道,网络通信,发送请求有两种 ...

  8. LoadRunner字符串与参数的操作及转换技巧

    刚开始学LR时,经常搞不清楚变量和参数的区别与用法,最近在一次脚本编写中,整理出来的一些小技巧,与大家一起分享. //字符串复制 strcpy(str,"Hello ") ; // ...

  9. LightOJ1079 Just another Robbery(DP)

    题目大概是抢劫银行,每家银行都有一个收益和一个被抓的概率,求在被抓概率小于P的条件下能获得的最大收益. dp[i][j]表示抢劫前i家银行收益为j被抓的最小概率 dp[0][0]=0 dp[i][j] ...

  10. LightOJ1051 Good or Bad(DP)

    这题感觉做法应该挺多吧,数据规模那么小. 我用DP乱搞了.. dp0[i][j]表示字符串前i位能否组成末尾有连续j个元音字母 dp1[i][j]表示字符串前i位能否组成末尾有连续j个辅音字母 我的转 ...