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