学习yii2.0框架阅读代码(八)

vendor/yiisoft/yii2/base/Model.php(续

    /**
     * 设置属性值
     * @param array $values attribute values (name => value) to be assigned to the model.
     * @param boolean $safeOnly whether the assignments should only be done to the safe attributes.
     * 一个安全属性是与一个验证规则在当前的[[情况]]。
     * @see safeAttributes()
     * @see attributes()
     */
    public function setAttributes($values, $safeOnly = true)
    {
        // 必须是个数组
        if (is_array($values)) {
            // array_flip — 交换数组中的键和值
            // 将属性放到了 key 上
            // 默认取 safeAttributes 中的属性
            $attributes = array_flip($safeOnly ? $this->safeAttributes() : $this->attributes());
            foreach ($values as $name => $value) {
                if (isset($attributes[$name])) {
                    // 如果存在该属性,就直接赋值
                    $this->$name = $value;
                } elseif ($safeOnly) {
                    // 如果不存在,而且是 safeOnly 的话,就触发一下 onUnsafeAttribute 方法
                    $this->onUnsafeAttribute($name, $value);
                }
            }
        }
    }

    /**
     * This method is invoked when an unsafe attribute is being massively assigned.
     * The default implementation will log a warning message if YII_DEBUG is on.
     * It does nothing otherwise.
     * @param string $name the unsafe attribute name
     * @param mixed $value the attribute value
     */
    public function onUnsafeAttribute($name, $value)
    {
        if (YII_DEBUG) {
            // 如果是调试状态,就打 log 记录下,没有成功设置的不安全的属性
            Yii::trace("Failed to set unsafe attribute ‘$name‘ in ‘" . get_class($this) . "‘.", __METHOD__);
        }
    }

    /**
     * Returns the scenario that this model is used in.
     *
     * Scenario affects how validation is performed and which attributes can
     * be massively assigned.
     *
     * @return string the scenario that this model is in. Defaults to [[SCENARIO_DEFAULT]].
     */
    public function getScenario()
    {
        // 获取当前的场景
        return $this->_scenario;
    }

    /**
     * Sets the scenario for the model.
     * Note that this method does not check if the scenario exists or not.
     * The method [[validate()]] will perform this check.
     * @param string $value the scenario that this model is in.
     */
    public function setScenario($value)
    {
        // 设置当前的场景
        $this->_scenario = $value;
    }

    /**
     * Returns the attribute names that are safe to be massively assigned in the current scenario.
     * @return string[] safe attribute names
     */
    public function safeAttributes()
    {
        // 获取当前的场景
        $scenario = $this->getScenario();
        // 获取所有场景及其属性
        $scenarios = $this->scenarios();
        if (!isset($scenarios[$scenario])) {
            // 场景不存在,就返回空
            return [];
        }
        $attributes = [];
        foreach ($scenarios[$scenario] as $attribute) {
            // 将开头不是!的属性才会放入到 safeAttributes 中, 即以!开头的属性不会被放到 safeAttributes 中
            if ($attribute[0] !== ‘!‘) {
                $attributes[] = $attribute;
            }
        }

        return $attributes;
    }

    /**
     * Returns the attribute names that are subject to validation in the current scenario.
     * @return string[] safe attribute names
     */
    public function activeAttributes()
    {
        // 同上
        $scenario = $this->getScenario();
        $scenarios = $this->scenarios();
        if (!isset($scenarios[$scenario])) {
            return [];
        }
        // 获取当前场景中的所有属性
        $attributes = $scenarios[$scenario];
        foreach ($attributes as $i => $attribute) {
            // 如果属性名以!开头,就把!截取掉
            // !开头的属性来自rules,加!能够使规则(即 validator)生效,但却能够不出现在 safeAttributes 中
            if ($attribute[0] === ‘!‘) {
                $attributes[$i] = substr($attribute, 1);
            }
        }

        return $attributes;
    }

    /**
     * Populates the model with the data from end user.
     * The data to be loaded is `$data[formName]`, where `formName` refers to the value of [[formName()]].
     * If [[formName()]] is empty, the whole `$data` array will be used to populate the model.
     * The data being populated is subject to the safety check by [[setAttributes()]].
     * 加载数据到所在的 model 中
     * @param array $data the data array. This is usually `$_POST` or `$_GET`, but can also be any valid array
     * supplied by end user.
     * @param string $formName the form name to be used for loading the data into the model.
     * If not set, [[formName()]] will be used.
     * @return boolean whether the model is successfully populated with some data.
     */
    public function load($data, $formName = null)
    {
        // 如果存在 yii 的 form,就使用该 form,否则就拿到所在类的名称(不含 namespace)
        $scope = $formName === null ? $this->formName() : $formName;
        if ($scope === ‘‘ && !empty($data)) {
            // 如果 $scope 为空字符串,且 $data不为空,就设置属性
            // 即 $formName 为空字符串,且 $data不为空
            $this->setAttributes($data);

            return true;
        } elseif (isset($data[$scope])) {
            // 否则,必须存在 $data[$scope],使用 $data[$scope] 去设置属性
            $this->setAttributes($data[$scope]);

            return true;
        } else {
            return false;
        }
    }

    /**
     * Populates a set of models with the data from end user.
     * 加载数据到所在的 model 的集合中
     * This method is mainly used to collect tabular data input.
     * The data to be loaded for each model is `$data[formName][index]`, where `formName`
     * refers to the value of [[formName()]], and `index` the index of the model in the `$models` array.
     * If [[formName()]] is empty, `$data[index]` will be used to populate each model.
     * The data being populated to each model is subject to the safety check by [[setAttributes()]].
     * @param array $models the models to be populated. Note that all models should have the same class.
     * @param array $data the data array. This is usually `$_POST` or `$_GET`, but can also be any valid array
     * supplied by end user.
     * @param string $formName the form name to be used for loading the data into the models.
     * If not set, it will use the [[formName()]] value of the first model in `$models`.
     * This parameter is available since version 2.0.1.
     * @return boolean whether at least one of the models is successfully populated.
     */
    public static function loadMultiple($models, $data, $formName = null)
    {
        if ($formName === null) {
            /* @var $first Model */
            // reset — 将数组的内部指针指向第一个单元
            $first = reset($models);
            if ($first === false) {
                // 不存在就返回 false
                return false;
            }
            // 拿到所在类的名称(不含 namespace)
            $formName = $first->formName();
        }

        $success = false;
        // 遍历 $models,一个个 load 数据
        foreach ($models as $i => $model) {
            /* @var $model Model */
            if ($formName == ‘‘) {
                if (!empty($data[$i])) {
                    // 数据不为空,就 load 到相应的 model 中
                    $model->load($data[$i], ‘‘);
                    $success = true;
                }
            } elseif (!empty($data[$formName][$i])) {
                // 存在 $formName,且数据不为空,就 load 到相应的 model 中
                $model->load($data[$formName][$i], ‘‘);
                $success = true;
            }
        }

        return $success;
    }

时间: 2024-10-05 07:41:06

学习yii2.0框架阅读代码(八)的相关文章

学习yii2.0框架阅读代码(十八)

vendor/yiisoft/yii2/base/Module. php /** * 返回一个ID,惟一标识此模块在所有模块在当前应用程序. * @return string the unique ID of the module. */ public function getUniqueId() { //如果该模块是一个应用程序,将返回一个空字符串. return $this->module ? ltrim($this->module->getUniqueId() . '/' . $t

学习yii2.0框架阅读代码(四)

阅读 BaseYii Yii的辅助类核心框架 别名相关(续) //用一个真实的路径注册一个别名 public static function setAlias($alias, $path) { if (strncmp($alias, '@', 1)) { // 如果不是以 @ 开头,就将 @ 拼到开头 $alias = '@' . $alias; } // 获取 / 在 $alias 中首次出现的位置 $pos = strpos($alias, '/'); // 如果 / 不存在,$root 就

学习yii2.0框架阅读代码(十七)

vendor/yiisoft/yii2/base/Module. 模块类 每个模块都有一个继承yii\base\Module的模块类,该类文件直接放在模块的yii\base\Module::basePath目录下, 并且能被自动加载.当一个模块被访问,和应用主题实例类似会创建该模块类唯一实例,模块实例用来帮模块内代码共享数据和组件 class Module extends ServiceLocator { /** * @event 在执行ActionEvent方法时触发事件 * 你可以设置[[A

学习yii2.0框架阅读代码(三)

阅读 BaseYii Yii的辅助类核心框架 别名相关 <?php namespace yii; //定义命名空间,昨天修改了一天.. use yii\base\InvalidConfigException; use yii\base\InvalidParamException; use yii\base\UnknownClassException; use yii\log\Logger; use yii\di\Container; //获取应用程序开始时间 defined('YII_BEGIN

学习yii2.0框架阅读代码(十一)

vendor/yiisoft/yii2/base/Module. php(续) /** * 该方法解析指定的路线和创建相应的子模块(s),控制器和行动 * This method parses the specified route and creates the corresponding child module(s), controller and action * instances. It then calls [[Controller::runAction()]] to run th

学习yii2.0框架阅读代码(十五)

行为是 yii\base\Behavior 或其子类的实例.行为,也称为mixins,可以无须改变类继承关系即可增强一个已有的 yii\base\Component 类功能.当行为附加到组件后,它将“注入”它的方法和属性到组件,然后可以像访问组件内定义的方法和属性一样访问它们.此外,行为通过组件能响应被触发的事件,从而自定义或调整组件正常执行的代码. <?php namespace yii\base; /** * 行为是所有行为类的基类. * * 一个行为可以用来增强现有的功能组件,无需修改其代

学习yii2.0框架阅读代码(七)

vendor/yiisoft/yii2/base/Model.php <?php /** * @link http://www.yiiframework.com/ * @copyright Copyright (c) 2008 Yii Software LLC * @license http://www.yiiframework.com/license/ */ namespace yii\base; use Yii; use ArrayAccess; use ArrayObject; use A

学习yii2.0框架阅读代码(六)

vendor/yiisoft/yii2/base/ArrayableTrait. <?php /** * @link http://www.yiiframework.com/ * @copyright Copyright (c) 2008 Yii Software LLC * @license http://www.yiiframework.com/license/ */ namespace yii\base; use Yii; use yii\helpers\ArrayHelper; use

学习yii2.0框架阅读代码(二十)

vendor/yiisoft/yii2/base/Module. php(续) /** * 新建一个控制器实例基于给定的路线. * * 路线应该是相对于这个模块.该方法实现了以下算法 * to resolve the given route: * * 1. If the route is empty, use [[defaultRoute]]; * 2. If the first segment of the route is a valid module ID as declared in [