RESTful 资源处理

表述性状态转移(REST)是一种用于分布式应用程序的架构风格,首先由 Roy Fielding 在他的 2000 年博士论文 《Architectural Styles and the Design of Network-based Software Architectures》 中描述。这可能有点枯燥,你可能会发现 Martin Fowler 的 《Richardson 成熟度模型》 是一个更温和的介绍。

REST 的解释和误解的方式比大多数软件体系结构都要多,可以说你在体系结构中采用的 Roy Fielding 原则越多,你的应用程序就越被认为是“RESTful”。

CodeIgniter 通过其资源路由和 ResourceController 可以轻松创建资源的 RESTful API。

资源路由

你可以使用 resource() 方法快速为单个资源创建一组 RESTful 路由。这将创建用于完整 CRUD 操作的 5 个最常用的路由:创建新资源、更新现有资源、列出所有资源、显示单个资源和删除单个资源。第一个参数是资源名称:

<?php

$routes->resource('photos');

// Equivalent to the following:
$routes->get('photos/new', 'Photos::new');
$routes->post('photos', 'Photos::create');
$routes->get('photos', 'Photos::index');
$routes->get('photos/(:segment)', 'Photos::show/$1');
$routes->get('photos/(:segment)/edit', 'Photos::edit/$1');
$routes->put('photos/(:segment)', 'Photos::update/$1');
$routes->patch('photos/(:segment)', 'Photos::update/$1');
$routes->delete('photos/(:segment)', 'Photos::delete/$1');

备注

上面的顺序是为了清晰起见,而实际创建路由的顺序在 RouteCollection 中确保了正确的路由解析

重要

路由按指定顺序匹配,因此如果你在上方有一个资源 photos,然后有一个 get ‘photos/poll’,资源线的 show 操作的路由将在 get 线之前匹配。要解决此问题,请将 get 行移动到资源行之上,以便先匹配它。

第二个参数接受可以用于修改生成的路由的选项数组。虽然这些路由面向 API 使用,其中允许更多方法,但你可以传入 websafe 选项,使其生成适用于 HTML 表单的 update 和 delete 方法:

<?php

$routes->resource('photos', ['websafe' => 1]);

// The following equivalent routes are created:
$routes->post('photos/(:segment)/delete', 'Photos::delete/$1');
$routes->post('photos/(:segment)', 'Photos::update/$1');

更改使用的控制器

你可以通过使用应该使用的控制器的名称传递 controller 选项来指定应该使用的控制器:

<?php

$routes->resource('photos', ['controller' => 'Gallery']);
// Would create routes like:
$routes->get('photos', '\App\Controllers\Gallery::index');
<?php

$routes->resource('photos', ['controller' => '\App\Gallery']);
// Would create routes like:
$routes->get('photos', '\App\Gallery::index');
<?php

use App\Controllers\Gallery;

$routes->resource('photos', ['namespace' => '', 'controller' => Gallery::class]);
// Would create routes like:
$routes->get('photos', '\App\Controllers\Gallery::index');

也可参考 控制器的命名空间

更改使用的占位符

默认情况下,当需要资源 ID 时,会使用 (:segment) 占位符。你可以通过传递 placeholder 选项及要使用的新字符串来更改此占位符:

<?php

$routes->resource('photos', ['placeholder' => '(:num)']);

// Generates routes like:
$routes->get('photos/(:num)', 'Photos::show/$1');

限制生成的路由

你可以使用 only 选项限制生成的路由。这应该是 数组以逗号分隔的方法名列表,应该创建这些方法。仅将创建与这些方法之一匹配的路由。其余的会被忽略:

<?php

$routes->resource('photos', ['only' => ['index', 'show']]);

否则,你可以使用 except 选项删除未使用的路由。这也应该是 数组以逗号分隔的方法名列表。此选项在 only 之后运行:

<?php

$routes->resource('photos', ['except' => 'new,edit']);

有效的方法是:indexshowcreateupdateneweditdelete

ResourceController

ResourceController 为你的 RESTful API 提供了一个方便的起点,其方法对应于上面的资源路由。

扩展它,覆盖 modelNameformat 属性,然后实现你想要处理的那些方法:

<?php

namespace App\Controllers;

use CodeIgniter\RESTful\ResourceController;

class Photos extends ResourceController
{
    protected $modelName = 'App\Models\Photos';
    protected $format    = 'json';

    public function index()
    {
        return $this->respond($this->model->findAll());
    }

    // ...
}

路由如下:

<?php

$routes->resource('photos');

Presenter 路由

你可以使用 presenter() 方法快速创建与资源控制器对齐的表示控制器。 这将创建对应于上面的资源控制器方法的路由,这些方法会为你的资源返回视图, 或处理来自这些视图的表单提交。

这不是必需的,因为表示可以通过常规控制器处理 - 这只是为了方便。 其用法与资源路由类似:

<?php

$routes->presenter('photos');

// Equivalent to the following:
$routes->get('photos/new', 'Photos::new');
$routes->post('photos/create', 'Photos::create');
$routes->post('photos', 'Photos::create');   // alias
$routes->get('photos', 'Photos::index');
$routes->get('photos/show/(:segment)', 'Photos::show/$1');
$routes->get('photos/(:segment)', 'Photos::show/$1');  // alias
$routes->get('photos/edit/(:segment)', 'Photos::edit/$1');
$routes->post('photos/update/(:segment)', 'Photos::update/$1');
$routes->get('photos/remove/(:segment)', 'Photos::remove/$1');
$routes->post('photos/delete/(:segment)', 'Photos::delete/$1');

备注

上面的顺序是为了清晰起见,而实际创建路由的顺序在 RouteCollection 中确保了正确的路由解析

你不会为资源和表示控制器都有 photos 路由。 你需要加以区分,例如:

<?php

$routes->resource('api/photo');
$routes->presenter('admin/photos');

第二个参数接受可以用于修改生成的路由的选项数组。

更改使用的控制器

你可以通过使用应该使用的控制器的名称传递 controller 选项来指定应该使用的控制器:

<?php

$routes->presenter('photos', ['controller' => 'Gallery']);
// Would create routes like:
$routes->get('photos', '\App\Controllers\Gallery::index');
<?php

$routes->presenter('photos', ['controller' => '\App\Gallery']);
// Would create routes like:
$routes->get('photos', '\App\Gallery::index');
<?php

use App\Controllers\Gallery;

$routes->presenter('photos', ['namespace' => '', 'controller' => Gallery::class]);
// Would create routes like:
$routes->get('photos', '\App\Controllers\Gallery::index');

也可参考 控制器的命名空间

更改使用的占位符

默认情况下,当需要资源 ID 时,会使用 (:segment) 占位符。你可以通过传递 placeholder 选项及要使用的新字符串来更改此占位符:

<?php

$routes->presenter('photos', ['placeholder' => '(:num)']);

// Generates routes like:
$routes->get('photos/(:num)', 'Photos::show/$1');

限制生成的路由

你可以使用 only 选项限制生成的路由。这应该是 数组以逗号分隔的方法名列表,应该创建这些方法。仅将创建与这些方法之一匹配的路由。其余的会被忽略:

<?php

$routes->presenter('photos', ['only' => ['index', 'show']]);

否则,你可以使用 except 选项删除未使用的路由。这也应该是 数组以逗号分隔的方法名列表。此选项在 only 之后运行:

<?php

$routes->presenter('photos', ['except' => 'new,edit']);

有效的方法是:indexshownewcreateeditupdateremovedelete

ResourcePresenter

ResourcePresenter 为呈现资源视图以及处理这些视图中的表单数据提供了一个方便的起点,其方法与上面的资源路由对齐。

扩展它,重写 modelName 属性,然后实现你想要处理的方法:

<?php

namespace App\Controllers;

use CodeIgniter\RESTful\ResourcePresenter;

class Photos extends ResourcePresenter
{
    protected $modelName = 'App\Models\Photos';

    public function index()
    {
        return view('templates/list', $this->model->findAll());
    }

    // ...
}

路由如下:

<?php

$routes->presenter('photos');

Presenter/Controller 对比

此表比较了 resource()presenter() 创建的默认路由及其相应的 Controller 函数。

操作

方法

控制器路由

表示器路由

控制器函数

表示器函数

New

GET

photos/new

photos/new

new()

new()

Create

POST

photos

photos

create()

create()

Create(别名)

POST

photos/create

create()

List

GET

photos

photos

index()

index()

Show

GET

photos/(:segment)

photos/(:segment)

show($id = null)

show($id = null)

Show(别名)

GET

photos/show/(:segment)

show($id = null)

Edit

GET

photos/(:segment)/edit

photos/edit/(:segment)

edit($id = null)

edit($id = null)

Update

PUT/PATCH

photos/(:segment)

update($id = null)

Update(网页安全)

POST

photos/(:segment)

photos/update/(:segment)

update($id = null)

update($id = null)

Remove

GET

photos/remove/(:segment)

remove($id = null)

Delete

DELETE

photos/(:segment)

delete($id = null)

Delete(网页安全)

POST

photos/delete/(:segment)

delete($id = null)

delete($id = null)