CI3设置子目录控制器为默认控制器的解决办法
在框架中配置文件多目录、前后台应该是个很常见的事情。像一般的php框架(CI、Tp等)采用都是单一入口模式,或许有人会直接在框架根目录新建文件admin.php,然后改变框架app结构,以达到访问不同入口文件名获得不同资源的效果。那么在CI中一样可以这样做,不过个人觉得这种方法太浪费资源(占用了几十k的资源吧)。于是在‘求学问道’的途中,终于得到了比较完美的解决方法。
业务需求
- 环境:codeigniter 3
- 需求:在CI3中实现前后台的效果。例:
地址栏输入xxx.com默认访问前台主页,输入xxx.com/admin访问后台
所遇问题
依照惯例,我们会在框架中的config/route.php
路由配置文件中配置我们的前后台访问路径:
// path => application/config/route.php
$route['admin'] = 'admin/admin'; //后台路径
$route['default_controller'] = 'home/home'; // 默认前台路径
$route['404_override'] = '';
$route['translate_uri_dashes'] = FALSE;
一般来说,我们这样配置是没问题的,但是有一个条件就是在CI3以下的版本中是没任何问题。但是目前的框架版本是CI3,所以就会出现找不到资源文件的情况。
源码追踪system/core/Route.php
修改_set_default_controller方法如下:
protected function _set_default_controller()
{
if (empty($this->default_controller))
{
show_error('Unable to determine what should be displayed. A default route has not been specified in the routing file.');
}
/**
* if里为自己修改的部分
* 1.截取default_controller为数组
* 2.如果default_controller_arr大于3 表示是默认控制器过来的
* 3.赋值相应的变量
*/
$default_controller_arr = explode('/', $this->default_controller);
if(count($default_controller_arr) == 3) {
// 赋值控制器所在目录
$this->directory = trim($default_controller_arr[0], '/') . '/';
// 赋值控制器名
$class = $default_controller_arr[1];
// 因为这里计划约定默认控制器输入完整uri 即目录名/控制器名/方法名的形式
// 所以方法名这里一定不为空
$method = $default_controller_arr[2];
}else {
// Is the method being specified?
if (sscanf($this->default_controller, '%[^/]/%s', $class, $method) !== 2)
{
$method = 'index';
}
}
if ( ! file_exists(APPPATH.'controllers/'.$this->directory.ucfirst($class).'.php'))
{
// This will trigger 404 later
return;
}
$this->set_class($class);
$this->set_method($method);
// Assign routed segments, index starting from 1
$this->uri->rsegments = array(
1 => $class,
2 => $method
);
log_message('debug', 'No URI present. Default controller set.');
}
虽说这样修改测试成功了,但是觉得并不是最好的解决办法(修改源码一般是最后的解决手段),于是求助codeigniter
中国的官方微信群的小伙伴,在群里和Hex(手动@Hex)老大讨论了一下这个功能的解决方案,最终在他的帮助下得到了比较完美的解决方法,就是要在application/core
里新建一个自己的扩展路由类MY_Router.php
,然后定义自己的_set_default_controller
方法,代码如下,顺便贴上自己上面设想的解决方法:
<?php
defined('BASEPATH') OR exit('No direct script access allowed');
class MY_Router extends CI_Router {
/**
* 个人认为比较完美解决问题的方法
*/
protected function _set_default_controller() {
if (empty($this->default_controller)) {
show_error('Unable to determine what should be displayed. A default route has not been specified in the routing file.');
}
if (sscanf($this->default_controller, '%[^/]/%s', $class, $method) !== 2) {
$method = 'index';
}
/**
* 1.判断目录是否存在
* 2.如果存在 调用设置控制器目录方法 详细参考system/core/Route.php set_directory方法
* 3.接着再把method拆分 赋值给$class $method $method为空则设置为index
*/
if( is_dir(APPPATH.'controllers/'.$class) ) {
// Set the class as the directory
$this->set_directory($class);
// $method is the class
$class = $method;
// Re check for slash if method has been set
if (sscanf($method, '%[^/]/%s', $class, $method) !== 2) {
$method = 'index';
}
}
if ( ! file_exists(APPPATH.'controllers/'.$this->directory.ucfirst($class).'.php')) {
// This will trigger 404 later
return;
}
$this->set_class($class);
$this->set_method($method);
// Assign routed segments, index starting from 1
$this->uri->rsegments = array(
1 => $class,
2 => $method
);
log_message('debug', 'No URI present. Default controller set.');
}
/**
* @author 命中水、
* @date(2017-8-7)
*
* 使用这个方法时 把这个方法名和上面的方法名调换一下
* application/config/route.php default_controller的值写uri全称(目录名/控制器名/方法名) 即可
* 因为最终Route.php路由类库调用的还是_set_default_controller方法
*/
protected function _set_default_controller_me() {
if (empty($this->default_controller))
{
show_error('Unable to determine what should be displayed. A default route has not been specified in the routing file.');
}
/**
* if里为自己修改的部分
* 1.截取default_controller为数组
* 2.如果default_controller_arr大于3 表示是默认控制器过来的
* 3.赋值相应的变量
*/
$default_controller_arr = explode('/', $this->default_controller);
if(count($default_controller_arr) == 3) {
// 赋值控制器目录
$this->directory = trim($default_controller_arr[0], '/') . '/';
// 赋值控制器名
$class = $default_controller_arr[1];
// 因为这里计划约定默认控制器输入完整uri 即目录名/控制器名/方法名的形式
// 所以方法名这里一定不为空
$method = $default_controller_arr[2];
}else {
if (sscanf($this->default_controller, '%[^/]/%s', $class, $method) !== 2)
{
$method = 'index';
}
}
if ( ! file_exists(APPPATH.'controllers/'.$this->directory.ucfirst($class).'.php'))
{
// This will trigger 404 later
return;
}
$this->set_class($class);
$this->set_method($method);
// Assign routed segments, index starting from 1
$this->uri->rsegments = array(
1 => $class,
2 => $method
);
log_message('debug', 'No URI present. Default controller set.');
}
}
以上代码比较完美的那个,亲测有效!!!(自己的这个简单测试了一下,也可以使用)
本作品采用 知识共享署名-相同方式共享 4.0 国际许可协议 进行许可。