RESTful CodeIgniter

浏览量:346 | 分类:PHP | 发布日期:2012-02-15

今天学习RESTful时发现的文章:

使用CodeIgniter框架,为你的web应用程序建立RESTful API服务,并演示如何让创建的API和其他RESTful风格的webservices

我们提供了相关的基础框架示例程序下载,以方便本文的接下来的讨论。下载地址在:http://github.com/philsturgeon/codeigniter-restserver,如下图,只需要点download sources或者使用 Git clone 一份下来就可以进行测试了

这里有五个示例,其中每个示例的链接都是以RESETful的形式给出的,下面我们分析其含义。注意这些都是由application/controller/example_api.php这个控制器产生的,我们分析下这些相关的URL,可以看到这种形式很象CodeIgniter中的MVC架构的链接,但要注意到,传统的CodeIgniter中的有点不同,在链接的最后一部分,我们称为Resource资源。有一点RESTful知识的朋友可能知道,在RESTful中,把要操作的对象都叫资源,而且对资源是通过HTTP方式进行相关操作,比如增加,删除,编辑和查询

// 在 application/config/routes.php 后面(或合适位置)加上这一行
map_resources('users');

///////////////////////////////////////////////////////////////////////////////
// 如果你不需要自定义额外的 url 规则,请无视下面的代码。。。
///////////////////////////////////////////////////////////////////////////////

// custom action handles GET request
map_resources('GET', 'users/(:id)/custom_action', 'users/custom_action/$1'); 

// some other custom action mappings...
// custom action handles PUT request
//map_resources('PUT', 'users/(:id)/custom_action', 'sync_sessions/custom_action/$1');

// custom action handles all requests (GET, POST, PUT, DELETE)
//map_resources('users/(:id)/custom_action', 'sync_sessions/custom_action/$1');

然后 controller 里就可以像 Rails 一样啦(除了 new, 因为 php 语言的限制,没办法 ):

class Users extends Controller
{

    function Users()
    {
        parent::Controller();   
    }

    // GET /users
    function index()
    {
        echo __METHOD__ . "
\n" . $_SERVER['REQUEST_METHOD'] . " /users\n"; } // GET /users/12345 function show($id) { echo __METHOD__ . "
\n" . $_SERVER['REQUEST_METHOD'] . " /users/{$id}\n"; } // GET /users/new // I have to use new_form as method name because "new" is a keyword in php function new_form() { echo __METHOD__ . "
\n" . $_SERVER['REQUEST_METHOD'] . " /users/new\n"; } // GET /users/12345/edit function edit($id) { echo __METHOD__ . "
\n" . $_SERVER['REQUEST_METHOD'] . " /users/{$id}/edit\n"; } // POST /users function create() { echo __METHOD__ . "
\n" . $_SERVER['REQUEST_METHOD'] . " /users\n"; } // PUT /users/12345 function update($id) { echo __METHOD__ . "
\n" . $_SERVER['REQUEST_METHOD'] . " /users/{$id}\n"; } // DELETE /users/12345 function delete($id) { echo __METHOD__ . "
\n" . $_SERVER['REQUEST_METHOD'] . " /users/{$id}\n"; } // GET /users/12345/custom_action function custom_action($id) { echo __METHOD__ . "
\n" . $_SERVER['REQUEST_METHOD'] . " /users/{$id}/custom_action\n"; } }

看到这里如果你感兴趣的话,可以继续往下看怎么实现了。其实非常简单,只有一个 MY_Router.php 文件,不到 100 行的代码(不计算空行和注释的话)。安装也很简单:只需要把这个 MY_Router.php 放到 application/libraries 目录下就万事大吉了。 代码逻辑我就不一一解释了,里面有注释,逻辑也简单,相信每个人都能看懂。

/**
 * RESTful-CodeIgniter
 *
 * A RESTful url router library for CodeIgniter
 *
 * @author      ZHENJiNG LiANG (liangzhenjing_N_O_S_P_A_M@gmail.com)
 * @license     BSD license
 * @link        http://liang.eu/web-dev/php/restful-style-url-in-codeigniter
 */

///////////////////////////////////////////////////////////////////////////////
// NOTE: 
// This Library added two macros:
// :id as [^/]+ in order to match non-numeric id field,
// :uuid to match UUID (aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee)
//
// :any and :num remain the same
// See code below for details
// You can change at will
///////////////////////////////////////////////////////////////////////////////

///////////////////////////////////////////////////////////////////////////
// map_resources()                              --> Return all routes
// map_resources($controller_name)              --> Map default restful routes
// map_resources($method, $pattern, $replace)   --> Add a custom route
///////////////////////////////////////////////////////////////////////////
function map_resources()
{
    static $routes = array();

    $arg_num = func_num_args();
    if(0 == $arg_num)
    {
        return $routes;
    }
    elseif(1 == $arg_num)
    {
        // map_resources($controller_name)   --> return all routes
        $controller = func_get_arg(0);

        // Generate RESTful url match patterns
        $routes['GET']["{$controller}"]             = "{$controller}/index";
        $routes['GET']["{$controller}/new"]         = "{$controller}/new_form";
        $routes['GET']["{$controller}/(:id)"]       = "{$controller}/show/$1";
        $routes['GET']["{$controller}/(:id)/edit"]  = "{$controller}/edit/$1";

        $routes['POST']["{$controller}"]            = "{$controller}/create";
        $routes['PUT' ]["{$controller}/(:id)"]      = "{$controller}/update/$1";
        $routes['DELETE']["{$controller}/(:id)"]    = "{$controller}/delete/$1";
    }
    elseif(2 == $arg_num)
    {
        // Custom url routing
        $args    = func_get_args();
        $pattern = $args[0];
        $replace = $args[1];

        $routes['GET'][$pattern]    = $replace;
        $routes['POST'][$pattern]   = $replace;
        $routes['PUT'][$pattern]    = $replace;
        $routes['POST'][$pattern]   = $replace;
    }
    elseif(3 == $arg_num)
    {
        // Custom url routing
        $args    = func_get_args();
        $method  = $args[0];
        $pattern = $args[1];
        $replace = $args[2];

        $routes[$method][$pattern] = $replace;
    }
}

///////////////////////////////////////////////////////////////////////////
// RESTful style url router
///////////////////////////////////////////////////////////////////////////
class MY_Router extends CI_Router
{
    function MY_Router()
    {
        // HACK: support overridding REQUEST_METHOD by posting a _method parameter
        if($_SERVER['REQUEST_METHOD'] == 'POST' && isset($_POST['_method']))
        {
            $_SERVER['REQUEST_METHOD'] = strtoupper($_POST['_method']);
        }
        elseif(isset($_SERVER['HTTP_X_HTTP_METHOD_OVERRIDE']))
        {
            $_SERVER['REQUEST_METHOD'] = strtoupper($_SERVER['HTTP_X_HTTP_METHOD_OVERRIDE']);
        }

        parent::CI_Router();
    }

    // Overrides CI_Router::_parse_routes. 
    // RESTful style url matching
    function _parse_routes()
    {
        $rest_routes = map_resources();

        // we do this for performence
        if (empty($rest_routes) && count($this->routes) == 1)
        {
            $this->_set_request($this->uri->segments);
            return;
        }

        // also this...
        $uri = implode('/', $this->uri->segments);
        if (isset($this->routes[$uri]))
        {
            $this->_set_request(explode('/', $this->routes[$uri]));
            return;
        }

        // RESTful url matching...
        $request_method = $_SERVER['REQUEST_METHOD'];
        $routes = (isset($rest_routes[$request_method]) && $rest_routes[$request_method]) ? $rest_routes[$request_method] : array();
        foreach($routes as $pattern => $replace)
        {
            $pattern = str_replace(':id',   '[^/]+',  $pattern); // use this to match non-numeric id field
            $pattern = str_replace(':any',  '.+',     $pattern);
            $pattern = str_replace(':num',  '[0-9]+', $pattern);
            $pattern = str_replace(':uuid', '[a-zA-Z0-9]{8}(-[a-zA-Z0-9]{4}){3}-[a-zA-Z0-9]{12}', $pattern);

            // Does the RegEx match?
            if (preg_match("#^{$pattern}$#", $uri))
            {
                // Do we have a back-reference?
                if (strpos($replace, '$') !== FALSE && strpos($pattern, '(') !== FALSE)
                {
                    $replace = preg_replace("#^{$pattern}$#", $replace, $uri);
                }

                // we are done
                $this->_set_request(explode('/', $replace));
                return;
            }
        }

        // if non of the rules match, then go on...
        parent::_parse_routes();
    }
}

本文转自 :http://liang.eu/ 博客

上一篇: jQuery事件绑定子元素继承问题

下一篇: git日常操作

评论