Codeigniter 3 拓展HMVC

Stella981
• 阅读 280

在Codeiniter(以下统称CI) 2.X版本中,我们就通过拓展核心类库实现了HMVC,但是同样的代码,拿到CI 3中,就很有可能不好用了。

###拓展核心类库方式

官方的文档对拓展核心类有详细的说明:

你定义的类必须继承自父类。 你的类名和文件名必须以 MY_ 开头。(这是可配置的,见下文) 举个例子,要扩展原始的 Input 类,你需要新建一个文件 application/core/MY_Input.php,然后像下面这样定义你的类:

class MY_Input extends CI_Input {

}

CI 控制器加载的过程很简单,官方文档有图如下:

Codeigniter 3 拓展HMVC 我们可以看到,在控制器开始加载看,CI是做了Routing(路由)和Security(安全)的操作的,所以,我们需要重写,或者说,在CI拓展我们想要的功能,比如:HMVC

###2.0中扩展

在2.0版本中,笔者曾适用过Jens Segers开源的HMVC模块,代码的实现就是对Routee和Loader进行了重写。 Jens Segers的主页 核心的代码如下:

            if (is_dir($source = $location . $module . '/controllers/')) {
                $this->module = $module;
                $this->directory = $relative . $module . '/controllers/';
                
                // 根目录下的模块?
                if ($directory && is_file($source . $directory . '.php')) {
                    $this->class = $directory;
                    return array_slice($segments, 1);
                }
                
                // 子模块?
                if ($directory && is_dir($source . $directory . '/')) {
                    $source = $source . $directory . '/';
                    $this->directory .= $directory . '/';
                    
                    // 子控制器?
                    if (is_file($source . $directory . '.php')) {
                        return array_slice($segments, 1);
                    }
                    
                    // 子文件夹包含有默认控制器?
                    if (is_file($source . $this->default_controller . '.php')) {
                        $segments[1] = $this->default_controller;
                        return array_slice($segments, 1);
                    }
                    
                    // 子文件夹中的控制器? 
                    if ($controller && is_file($source . $controller . '.php')) {
                        return array_slice($segments, 2);
                    }
                }
                
                // 控制器和文件夹名一样?
                if (is_file($source . $module . '.php')) {
                    return $segments;
                }
                
                // 适用默认的控制器?
                if (is_file($source . $this->default_controller . '.php')) {
                    $segments[0] = $this->default_controller;
                    return $segments;
                }
            }

很简单的拓展 就能实现HMVC模式了,同样的,还得重写Loader中的加载器,不然会找不到文件。

###CI 3 HMVC拓展 到了CI3中,上述方法已经不好用了,CI 3 对路由有了更多的考虑,在初始化路由时,就进行了解析。假设写MY_Ruter类,必须要重写3个方法: CI 2 Router构造

    function __construct()
    {
        $this->config =& load_class('Config', 'core');
        $this->uri =& load_class('URI', 'core');
        log_message('debug', "Router Class Initialized");
    }

CI 3 Router构造

public function __construct($routing = NULL)
    {
        $this->config =& load_class('Config', 'core');
        $this->uri =& load_class('URI', 'core');

        $this->enable_query_strings = ( ! is_cli() && $this->config->item('enable_query_strings') === TRUE);

        
        is_array($routing) && isset($routing['directory']) && $this->set_directory($routing['directory']);
        
        $this->_set_routing();

        
        if (is_array($routing))
        {
            empty($routing['controller']) OR $this->set_class($routing['controller']);
            empty($routing['function'])   OR $this->set_method($routing['function']);
        }

        log_message('info', 'Router Class Initialized');
    }

可以看到,在CI3的构造方法中就已经对URL进行解析,方法的调用过程为: _set_routing() -> _validate_request() -> _parse_routes() -> _set_request() 那我们为了要实现HMVC,这几个方法是必然要按照我们自己的方法实现的。 _validate_request 中 我们加入部分验证,即可达到简单的HMVC

 if (is_dir($source = $relative . $module . '/controllers/')) {
                $this->module = $module;
                $this->directory =  '../'.$location.$module . '/controllers/';


                // 如果 有 application/$module/controollers/$directory.php 文件
                if ($directory && is_file($source . ucfirst($directory) . '.php')) {
                    return array_slice($segments, 1);
                }

                //如果application/$module/$directory 是一个文件夹
                if ($directory && is_dir($source . $directory . '/')) {
                    $source = $source . $directory . '/';
                    $this->directory .= $directory . '/';
                    //  index.php/$modules/$directory/$controller
                    //如果包含 控制器  $controller
                    if ($controller && is_file($source . ucfirst($controller) . '.php')) {
                        return array_slice($segments, 2);
                    }

                    //如果有默认控制器
                    if (is_file($source . $this->default_controller . '.php')) {
                        $segments[1] = $this->default_controller;
                        return array_slice($segments, 1);
                    }

                    //如果有 application/$module/$directory.php
                    if (is_file($source . $directory . '.php')) {
                        return array_slice($segments, 1);
                    }
                }

                //如果有 application/$module/$module.php  
                if (is_file($source . $module . '.php')) {
                    return $segments;
                }

                // 默认控制器
                if (is_file($source . $this->default_controller . '.php')) {
                    $segments[0] = $this->default_controller;
                    return $segments;
                }
            }

为了让CI_ROUTER知道我们模块拓展的位置,我们在配置文件中加入选项,并在CI_ROUTER的构造器中加入如下代码:

$locations = $this->config->item('modules_locations');

        if (!$locations) {
            $locations = array('modules/');
        } else if (!is_array($locations)) {
            $locations = array($locations);
        }

        $this->config->set_item('modules_locations', $locations);

操作完以上步骤,就可以实现大部分HMVC的拓展了。 本文代码:https://git.oschina.net/liwenlong/Codeigniter-3-HMVC.git 说明:CI3中对控制器大小写由严格的控制了,为了符合CI3的一贯规则,所以我们使用了ucfirst()方式寻找首字母大写的类名,一定要注意。

点赞
收藏
评论区
推荐文章
刚刚好 刚刚好
4个月前
css问题
1、在IOS中图片不显示(给图片加了圆角或者img没有父级)<div<imgsrc""/</divdiv{width:20px;height:20px;borderradius:20px;overflow:h
Jacquelyn38 Jacquelyn38
1年前
你不可不知的JS面试题(第二期)
1、什么是继承?子类可以使用父类的所有功能,并且对功能进行扩展。新增方法改用方法(1)、ES6使用extends子类继承父类的方法。// 父类    class A        constructor(name)            this.name name;                getNa
blmius blmius
1年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
晴空闲云 晴空闲云
4个月前
css中box-sizing解放盒子实际宽高计算
我们知道传统的盒子模型,如果增加内边距padding和边框border,那么会撑大整个盒子,造成盒子的宽度不好计算,在实务中特别不方便。boxsizing可以设置盒模型的方式,可以很好的设置固定宽高的盒模型。盒子宽高计算假如我们设置如下盒子:宽度和高度均为200px,那么这会这个盒子实际的宽高就都是200px。但是当我们设置这个盒子的边框和内间距的时候,那
Java Record 的一些思考 - 默认方法使用以及基于预编译生成相关字节码的底层实现
快速上手Record类我们先举一个简单例子,声明一个用户Record。publicrecordUser(longid,Stringname,intage)这样编写代码之后,Record类默认包含的元素和方法实现包括:1.record头指定的组成元素(intid,Stringname,intage),并且,这些元素都是f
艾木酱 艾木酱
3个月前
快速入门|使用MemFire Cloud构建React Native应用程序
MemFireCloud是一款提供云数据库,用户可以创建云数据库,并对数据库进行管理,还可以对数据库进行备份操作。它还提供后端即服务,用户可以在1分钟内新建一个应用,使用自动生成的API和SDK,访问云数据库、对象存储、用户认证与授权等功能,可专
Stella981 Stella981
1年前
PHP中的stdClass是什么?
请定义什么是stdClass。1楼stdClass是另一个很棒的PHP功能。您可以创建一个匿名PHP类。让我们来看一个例子。$pagenewstdClass();$pagename'Home';$pagestatus1;现在,您认为您还有另一个类,该类将使
Stella981 Stella981
1年前
Mixin研究之一
如何利用Mixin对已定义的类进行方法和属性扩展起因类已经定义明确,但希望在创建实例时拓展实例的功能,这种情况下怎么办?目的实现一种机制,能够根据一定的规则,在实例创建时动态的拓展实例的功能(方法和属性);实现1.动态的拓展类的方法和属性,这样所有实例
Stella981 Stella981
1年前
Mybatis别名的配置使用
之前,我们在sql映射xml文件中的引用实体类时,需要写上实体类的全类名(包名类名),如下<! 创建用户(Create)   <insert id"addUser" parameterType"me.gacl.domain.User"    insert into users(name,
helloworld_28799839 helloworld_28799839
4个月前
常用知识整理
Javascript判断对象是否为空jsObject.keys(myObject).length0经常使用的三元运算我们经常遇到处理表格列状态字段如status的时候可以用到vue
helloworld_34035044 helloworld_34035044
6个月前
皕杰报表之UUID
​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为