承接上一篇博文,我们继续CI restful改造之旅。
在第一篇博文里面简单介绍了CI的一些加载机制,在此基础上我们要对CI进行改造了。与其说是改造不如说是增加一个控制器处理层。
我们知道CI的控制器基类在system/core/CodeIginter.php里面加载,控制器基类主要做了两个事情
1.加载各种核心类为控制器属性
2.提供一个控制器实例化方法
class CI_Controller {
/**
* Reference to the CI singleton
* @var object
*/
private static $instance;
/**
* Class constructor
* @return void
* 加载各种核心类为属性
*/
public function __construct()
{
self::$instance =& $this;
// Assign all the class objects that were instantiated by the
// bootstrap file (CodeIgniter.php) to local class variables
// so that CI can run as one big super object.
foreach (is_loaded() as $var => $class)
{
$this->$var =& load_class($class);
}
$this->load =& load_class('Loader', 'core');
$this->load->initialize();
log_message('info', 'Controller Class Initialized');
}
// --------------------------------------------------------------------
/**
* Get the CI singleton
* @static
* @return object
* 提供一个获取控制器实例化的方法
*/
public static function &get_instance()
{
return self::$instance;
}
}
通常我们在application/controller中增加控制器都要继承这个基类才能正常运行。
为了在不改变CI核心类的基础上对框架进行改造,我们选择扩展这个核心类,并不修改它。
基于以上目的,我选择在CI_Controller与应用控制器之前增加一个中间层,这样我们在application/core/下新增一个文件叫rest.php
defined('BASEPATH') OR exit('No direct script access allowed');
/**
* restful 核心类
* @class rest
* extends CI_Controller
*/
class rest extends CI_Controller{
/**
* 构造函数
*/
public function __construct()
{
parent::__construct();
}
}
首先,我们需要继承CI_Controller以获得CI核心类的访问权限(注意:parent::__construct();这句一定要加上,因为涉及到CI加载核心类文件)。
到目前为止,我们已经迈出了改造的第一步,但不论从哪个角度看我们添加的这个中间层都不像一个restful风格的处理层。别着急!我们马上进一步改进它。
我们知道restful风格强调面向资源操作。对于同一个资源,比如user表,我们可能有增删改查四种操作,按照以往的经验,我们可能会添加四个url, 而且 我猜想大家可能会像下面这样设计(因为我就是这样设计的,:-))——
get_user 获取用户信息
insert_user 添加用户信息
update_user 修改用户信息
delete_user 删除用户信息
但现在我觉得这样设计有一些麻烦,每一个表都要添加四个url,好烦,有没有一个url解决所有问题呢?
答案当然是有,restful风格就帮我们提供了解决思路。
restful 通过http请求方法区分不同操作,这样我们就可以只请求同一个url,通过不同的请求方法达到区分增删改查的方式,是不是很方便。
还是刚才的例子——user表,我们可以这样设计
user
GET方法 获取用户信息
POST方法 添加用户信息
PUT方法 修改用户信息
DELETE方法 删除用户信息
了解了这些,我们来看看刚添加的这个中间层该如何修改?
defined('BASEPATH') OR exit('No direct script access allowed');
/**
* restful 核心类
* @class rest
* extends CI_Controller
*/
class rest extends CI_Controller{
//请求对象
private $request;
/**
* 构造函数
*/
public function __construct()
{
parent::__construct();
$this->request = new stdClass();
$this->request->method = $this->which_method();
}
/**
* 路由分配函数
*/
public function _remap($method)
{
if(method_exists($this, $method.'_'.$this->request->method)){
call_user_func_array(array($this, $method.'_'.$this->request->method), array());
}else{
show_404();
}
}
/**
* 解析http请求方式
*/
protected function which_method()
{
$method = NULL;
if(empty($method))
{
$method = $this->input->method();
}
return $method;
}
}
在上面的代码中,我们增加了两个方法和一个属性,分别为_remap()、which_method 和 $request
他们各自的作用如下:
**_remap($method) ** CI内部方法,作用控制器重定向。
在控制器中重写此方法后,那么无论 URI 中包含什么参数时都会调用该方法。
具体使用规范请查阅CI官方文档https://codeigniter.org.cn/user_guide/general/controllers.html?highlight=_remap
我们使用_remap() 来重新定义路由规则。
** which_method() **用来识别HTTP请求方式,这里我们使用了CI内部的Input输入类提供的method方法来获取HTTP请求方式并返回。
**$request **属性用来记录HTTP请求方式 方便全局调用,这里我们使用了PHP保留对象stdClass,它没有具体含义,关于stdClass的使用方法请查阅官方文档,这里不作过多讲解。
到此我们的中间层初建模型,让我们来试试怎么使用它。
首先,我们在system/CodeIgnite.php 中添加一行,用来初始化我们的中间层
//找到 &get_instance() 在其下面添加
if (file_exists(APPPATH.'core/rest.php'))
{
require_once APPPATH.'core/rest.php';
}
之后,我们在application/controller中添加一个控制器User.php
defined('BASEPATH') OR exit('No direct script access allowed');
/*
* restful 核心类
* @class rest
* extends CI_Controller
*/
class user extends rest{//注意此处要继承我们的中间层
/*
* 构造函数
*/
public function __construct()
{
parent::__construct();//注意此处要执行父类构造方法
}
public function user_get()
{
echo '执行了get方法';
}
public function user_post()
{
echo '执行了post方法';
}
public function user_put()
{
echo '执行了put方法';
}
public function user_delete()
{
echo '执行了delete方法';
}
}
到此,我们可以访问URL http://host/user/user 试试我们的改造成果了。
现在我们已经可以正确的分配路由了,下一篇我们增加一些请求参数处理已经返回格式化方面的内容。
具体项目代码请参考 https://github.com/lifeofmine/CI_RESTFUL/blob/master/front/application/core/MY_restful.php