Codeigniter 3 拓展HMVC

在Codeiniter(如下統稱CI) 2.X版本中,咱們就經過拓展核心類庫實現了HMVC,可是一樣的代碼,拿到CI 3中,就頗有可能很差用了。php

###拓展核心類庫方式git

官方的文檔對拓展核心類有詳細的說明:安全

你定義的類必須繼承自父類。 你的類名和文件名必須以 MY_ 開頭。(這是可配置的,見下文) 舉個例子,要擴展原始的 Input 類,你須要新建一個文件 application/core/MY_Input.php,而後像下面這樣定義你的類:app

class MY_Input extends CI_Input {

}

CI 控制器加載的過程很簡單,官方文檔有圖以下:ide

輸入圖片說明 咱們能夠看到,在控制器開始加載看,CI是作了Routing(路由)和Security(安全)的操做的,因此,咱們須要重寫,或者說,在CI拓展咱們想要的功能,好比:HMVCcodeigniter

###2.0中擴展ui

在2.0版本中,筆者曾適用過Jens Segers開源的HMVC模塊,代碼的實現就是對Routee和Loader進行了重寫。 Jens Segers的主頁 核心的代碼以下:this

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中的加載器,否則會找不到文件。.net

###CI 3 HMVC拓展 到了CI3中,上述方法已經很差用了,CI 3 對路由有了更多的考慮,在初始化路由時,就進行了解析。假設寫MY_Ruter類,必需要重寫3個方法: CI 2 Router構造debug

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()方式尋找首字母大寫的類名,必定要注意。

相關文章
相關標籤/搜索