zoukankan      html  css  js  c++  java
  • 学习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 the action with the given parameters.
         * 如果路径为空,该方法将使用[[defaultRoute]]
         * @param string $route the route that specifies the action.
         * @param array $params the parameters to be passed to the action
         * @return mixed the result of the action.
         * @throws InvalidRouteException if the requested route cannot be resolved into an action successfully
         */
        public function runAction($route, $params = [])
        {
            // 创建controller,获取controller的实例和action的ID
            $parts = $this->createController($route);
            if (is_array($parts)) {
                /* @var $controller Controller */
                list($controller, $actionID) = $parts;
                // 保留下app中绑定的controller
                $oldController = Yii::$app->controller;
                // 将当前controller绑定到app上
                Yii::$app->controller = $controller;
                $result = $controller->runAction($actionID, $params);
                // 还原会app之前的绑定的controller
                Yii::$app->controller = $oldController;
    
                return $result;
            } else {
                $id = $this->getUniqueId();
                throw new InvalidRouteException('Unable to resolve the request "' . ($id === '' ? $route : $id . '/' . $route) . '".');
            }
        }
    
        /**
         * 新建一个控制器实例基于给定的路线.
         *
         * 路线应该是相对于这个模块。该方法实现了以下算法
         * 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 [[modules]],
         *    call the module's `createController()` with the rest part of the route;
         * 3. If the first segment of the route is found in [[controllerMap]], create a controller
         *    based on the corresponding configuration found in [[controllerMap]];
         * 4. The given route is in the format of `abc/def/xyz`. Try either `abcDefController`
         *    or `abcdefXyzController` class within the [[controllerNamespace|controller namespace]].
         *
         * If any of the above steps resolves into a controller, it is returned together with the rest
         * part of the route which will be treated as the action ID. Otherwise, false will be returned.
         *
         * @param string $route the route consisting of module, controller and action IDs.
         * @return array|boolean If the controller is created successfully, it will be returned together
         * with the requested action ID. Otherwise false will be returned.
         * @throws InvalidConfigException if the controller class and its file do not match.
         */
        public function createController($route)
        {
            if ($route === '') {
                $route = $this->defaultRoute;
            }
    
            // double slashes or leading/ending slashes may cause substr problem
            // 如果有双斜线或者结束的斜线,可能会引起问题
            $route = trim($route, '/');
            if (strpos($route, '//') !== false) {
                return false;
            }
    
            if (strpos($route, '/') !== false) {
                // 如果存在斜线,就根据斜线分割route,并限制最多分割成两个
                list ($id, $route) = explode('/', $route, 2);
            } else {
                // 不存在,就直接赋值给$id
                $id = $route;
                $route = '';
            }
    
            // module and controller map take precedence
            if (isset($this->controllerMap[$id])) {
                // 如果controllerMap中存在相应的$id,就使用Yii::createObject去创建该controller的实例
                $controller = Yii::createObject($this->controllerMap[$id], [$id, $this]);
                return [$controller, $route];
            }
            // 根据id获取module
            $module = $this->getModule($id);
            if ($module !== null) {
                // 获取到module,就递归调用相应module的createController去创建controller的实例
                return $module->createController($route);
            }
    
            // 如果取到了module,就需要继续去取controller的ID
            // 再次根据斜线分割
            if (($pos = strrpos($route, '/')) !== false) {
                // 如果有斜线,就将module的ID和后面截取出的内容一起拼成ID
                $id .= '/' . substr($route, 0, $pos);
                // 剩余的赋给route
                $route = substr($route, $pos + 1);
            }
    
            // 然后根据ID去创建controller的实例
            $controller = $this->createControllerByID($id);
            // 未创建成功,并且route不为空
            if ($controller === null && $route !== '') {
                // 将route拼接到ID中,再次去创建controller出的实例
                $controller = $this->createControllerByID($id . '/' . $route);
                $route = '';
            }
    
            return $controller === null ? false : [$controller, $route];
        }
    
        /**
         * 创建一个控制器基于给定控制器ID.
         *
         * The controller ID is relative to this module. The controller class
         * should be namespaced under [[controllerNamespace]].
         *
         * Note that this method does not check [[modules]] or [[controllerMap]].
         *
         * @param string $id the controller ID
         * @return Controller the newly created controller instance, or null if the controller ID is invalid.
         * @throws InvalidConfigException if the controller class and its file name do not match.
         * This exception is only thrown when in debug mode.
         */
        public function createControllerByID($id)
        {
            // $id是controller的ID,但它前面可能带有module的ID,而且可能是多层module ID
            // 取到最右边的斜线位置,可以分离出controller的名字
            $pos = strrpos($id, '/');
            if ($pos === false) {
                // 没有斜线,$id就是controller的名字
                $prefix = '';
                $className = $id;
            } else {
                // 有斜线,斜线前的是module的ID,斜线后是controller的名字
                $prefix = substr($id, 0, $pos + 1);
                $className = substr($id, $pos + 1);
            }
    
            if (!preg_match('%^[a-z][a-z0-9\-_]*$%', $className)) {
                // 如果controller的名字不符合命名的规范,就返回null
                // 以小写字母开头,可以包含数字/小写字母/右斜线/中划线/下划线
                return null;
            }
            if ($prefix !== '' && !preg_match('%^[a-z0-9_/]+$%i', $prefix)) {
                // 如果module的ID不符合module的命名规范,就返回null
                // 可以包含数字/小写字母/左斜线/下划线
                return null;
            }
    
            // 先将-替换为空格,再将每个单词的首字母大写,再将空格替换为空字符串,最后拼接上'Controller',就拿到了类名(不带namespace)
            $className = str_replace(' ', '', ucwords(str_replace('-', ' ', $className))) . 'Controller';
            // 根据application和module中定义的controllerNamespace,拼出controller的类名,含namespace
            $className = ltrim($this->controllerNamespace . '\' . str_replace('/', '\', $prefix)  . $className, '\');
            if (strpos($className, '-') !== false || !class_exists($className)) {
                // 如果存在中划线或者类不存在,即返回null
                return null;
            }
    
            // is_subclass_of — 如果此对象是该类的子类,则返回 TRUE
            // 判断是不是'yiiaseController'的子类,是的话,就创建相应类的实例
            if (is_subclass_of($className, 'yiiaseController')) {
                return Yii::createObject($className, [$id, $this]);
            } elseif (YII_DEBUG) {
                throw new InvalidConfigException("Controller class must extend from \yii\base\Controller.");
            } else {
                return null;
            }
        }
  • 相关阅读:
    【数据库】事务,ACID,CAP和一致性
    线程,进程。多进程,多线程。并发,并行的区别
    mysql 集群 数据同步
    如何读取一个表的表类型,以及读取一个表中字段的类型.
    网络攻击技术开篇——SQL Injection
    MySQL数据库作发布系统的存储,一天五万条以上的增量,预计运维三年,怎么优化?
    程序员找工作那些事(一)幸存者偏差
    程序员
    preg_replace的一些细节
    HDU 1258 Sum It Up(dfs 巧妙去重)
  • 原文地址:https://www.cnblogs.com/xwzj/p/5415113.html
Copyright © 2011-2022 走看看