REST

    尽管还有其它解决方法,REST 是一个很棒的方法,为你在应用程序中创建的逻辑提供容易的访问方式。这是简单的、通常基于 XML 的(我们谈论是简单的 XML,完全不象 SOAP 信封(envelope)那么复杂),依赖于 HTTP 标头(headers)信息来提供指令。在 CakePHP 中通过 REST 提供 API 很简单。

    开始使用 REST 最快捷的方法,只需在 app/Config 目录中的 routes.php 文件中添加几行。Router 对象带有一个 方法,用来为控制器的 REST 访问设置一些默认的路由。确保 mapResources() 方法出现在require CAKE . 'Config' . DS . 'routes.php'; 和其它会改变路由的路由。如果要允许以 REST 方式访问菜单(recipe)数据库,就要象下面这样:

    第一行为简单的 REST 访问建立一些默认路由,而 parseExtensions() 方法指定想要的结果格式(例如 xml、json、rss)。这些路由能够辨识 HTTP 请求的方法(Method)。

    CakePHP 的 Router 类使用一些不同的指标来检测使用的 HTTP 方法。下面按优先顺序排列:

    • The _method POST variable
    • The X_HTTP_METHOD_OVERRIDE
    • The REQUESTMETHOD header
      __method
      POST 变量有助于使用浏览器(或者任何其它可以容易地 POST 的工具)作为REST 客户端。只需设置 _method 为要模拟的 HTTP 请求方法的名称。

    一旦路由器设置好,映射 REST 请求到某些控制器动作(controller action),我们就可以继续创建控制器动作内的逻辑。基本的控制器可以象这样:

    1. // Controller/RecipesController.php
    2. class RecipesController extends AppController {
    3.  
    4. public $components = array('RequestHandler');
    5.  
    6. public function index() {
    7. $recipes = $this->Recipe->find('all');
    8. $this->set(array(
    9. 'recipes' => $recipes,
    10. '_serialize' => array('recipes')
    11. ));
    12. }
    13.  
    14. public function view($id) {
    15. $recipe = $this->Recipe->findById($id);
    16. $this->set(array(
    17. 'recipe' => $recipe,
    18. '_serialize' => array('recipe')
    19. ));
    20.  
    21. public function add() {
    22. $this->Recipe->create();
    23. if ($this->Recipe->save($this->request->data)) {
    24. $message = 'Saved';
    25. } else {
    26. $message = 'Error';
    27. }
    28. $this->set(array(
    29. 'message' => $message,
    30. '_serialize' => array('message')
    31. ));
    32. }
    33.  
    34. public function edit($id) {
    35. $this->Recipe->id = $id;
    36. if ($this->Recipe->save($this->request->data)) {
    37. $message = 'Saved';
    38. } else {
    39. $message = 'Error';
    40. }
    41. $this->set(array(
    42. 'message' => $message,
    43. '_serialize' => array('message')
    44. ));
    45. }
    46. public function delete($id) {
    47. if ($this->Recipe->delete($id)) {
    48. $message = 'Deleted';
    49. } else {
    50. $message = 'Error';
    51. }
    52. $this->set(array(
    53. 'message' => $message,
    54. '_serialize' => array('message')
    55. ));
    56. }
    57. }

    如果要在数据转换为 XML 之前对其进行改动,就不要定义 _serialize 视图变量,而是使用视图文件。把 RecipesController 控制器的 REST 视图放在 目录中。也可以使用 Xml 类,在这些视图中进行快捷的 XML 输出。index 视图可以象下面这样:

    当使用 parseExtensions() 方法提供一个特定的内容类型时,CakePHP 会自动寻找匹配类型的视图助件。因为使用 XML 为内容类型,没有内置的助件,不过如果你要创建一个,就会在这些视图中自动加载以供使用。

    最终渲染的 XML 会象这样:

    1. <recipes>
    2. <recipe id="234" created="2008-06-13" modified="2008-06-14">
    3. <author id="23423" first_name="Billy" last_name="Bob"></author>
    4. <comment id="245" body="Yummy yummmy"></comment>
    5. </recipe>
    6. <recipe id="3247" created="2008-06-15" modified="2008-06-15">
    7. <author id="625" first_name="Nate" last_name="Johnson"></author>
    8. <comment id="654" body="This is a comment for this tasty dish."></comment>
    9. </recipe>
    10. </recipes>

    创建 edit 动作的逻辑有一点复杂,但也不算太复杂。既然是提供输出 XML 的 API,选择接受 XML 就很自然。不用担心,RequestHandler 和 类使事情容易得多。如果 POST 或 PUT 请求有 XML 内容类型(content-type),那么输入就会经过 CakePHP 的 Xml 类,数据的数组形式就会赋值给$this->request->data。因为这个特性,并行处理 XML 和 POST 数据是无缝的:无需改动控制器或模型代码。所有需要的数据都会在 $this->request->data 中。

    通常 REST 应用程序不但以多种数据格式输出内容,而且也接受不同格式的数据。在CakePHP 中, 有助于实现这一点。默认情况下,它会解码任何接收到的任何 POST/PUT 请求的 JSON/XML 输入数据,在$this->request->data 中提供该数据的数组版本。如果需要,也可以用RequestHandler::addInputType() 连入其它格式的反序列化。

    如果默认的 REST 路由对应用程序不适用,可以用 Router::resourceMap()方法改变。该方法让你可以设置 方法设置的默认路由。在使用该方法时需要设置 所有 要使用的默认值:

    修改了默认的 resource map,以后对 mapResources() 的调用就会使用新值。

    如果 创建的默认路由仍然不适用,可以用Router::connect() 方法定义一组自定义 REST 路由。connect() 方法让你可以为一个给定的网址定义一些不同的选项。欲知详情,请参考 一节。

    2.5 新版功能.

    你可以为 Router::mapResources() 方法在 $options 数组中指定connectOptions 键,来提供 方法使用的自定义设置:

    1. Router::mapResources('books', array(
    2. 'connectOptions' => array(
    3. 'routeClass' => 'ApiRoute',
    4. )