在 PHP 界有很多开发框架, yii 是其中一个比较优秀的框架。很多人都说 yii 比较复杂,先上手可以学习 ci 、 cakephp 什么的,其实我倒不这么认为, PHP 现在的框架一般整体的思路都差不多,都号称 MVC 那一套,其实关于是不是 MVC ,怎么个 MVC 法,这个话题太大,坑太深,不谈。其实,也就是说大家抽象的方式都类似,所以如果是要将 PHP 作为工具实用,而非研究,那就还是直接从牛人的肩膀上开始吧。当然,除了 yii 我另外还推荐 Laravel 框架。我个人感觉 php 的框架到这个地步就算是开始平稳了吧( yaf 另论)。总而言之,这些是废话,对于 PHP 这种,生而为 web ,死而为 web 的语言,实用、简单是根本。什么 dirty 不 dirty 、优雅不优雅的,非我等鼠辈所能 hold 住。
回到正题,现在我们利用 yii 框架来实现一个 REST 风格的调用接口。说到 REST ,现在大多的所谓 REST 风格,没有达到真正 REST 定义的那样,不过面向实用我们不必拘泥这些概念上的问题,如果有看官觉得觉得实现不够 REST 敬请拍砖,具体问题我们可以具体讨论。
首先做一下接口的 URL 规划,假设我们要面对的资源是 item ,现在我们暴露5个接口供其他应用调用,分别是:
对于所有 item 列表调用: GET /rest/item
对于某个 item 信息调用: GET /rest/item/(\d+)
创建一个 item: POST /rest/item
更新一个 item: PUT /rest/item/(\d+)
删除一个 item: DELETE /rest/item/(\d+)
然后根据规划在主配置里注册路由:
1
2
3
4
5
6
7
8
9
10
11
|
'urlManager'
=>
array
(
'urlFormat'
=>
'path'
,
'rules'
=>
array
(
// REST routers
array
(
'rest/list'
,
'pattern'
=>
'rest/item'
,
'verb'
=>
'GET'
),
array
(
'rest/view'
,
'pattern'
=>
'rest/item/'
,
'verb'
=>
'GET'
),
array
(
'rest/create'
,
'pattern'
=>
'rest/item'
,
'verb'
=>
'POST'
),
array
(
'rest/update'
,
'pattern'
=>
'rest/item/'
,
'verb'
=>
'PUT'
),
array
(
'rest/delete'
,
'pattern'
=>
'rest/item/'
,
'verb'
=>
'DELETE'
),
),
),
|
这里需要吐槽一下官方文档,路由配置这块基本什么说明都没写,比如rules数组中的配置数组,里的各种参数含义,比如verb,利用这个参数就能好好的绑定路由,不必再到controller里进行判断了。只有api参考里有些关于属性和方法的说明,主要信息来源还得靠在 Google 中自行寻觅。
然后开始编写 REST 的 Controller,安装 yii 框架的约定,我们建立 protected/controllers/RestController.php ,文件内容结构如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
|
class
RestController
extends
Controller
{
// Actions
public
function
actionList()
{
}
public
function
actionView()
{
}
public
function
actionCreate()
{
}
public
function
actionUpdate()
{
}
public
function
actionDelete()
{
}
// Assistant Functions
private
function
_sendResponse()
{
}
private
function
_getStatusCodeMessage()
{
}
}
|
获取 item 列表的方法:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
public
function
actionList()
{
$items
= Item::model()->findAll();
if
(
empty
(
$items
))
{
$this
->_sendResponse(200,
'No items'
);
}
else
{
$rows
=
array
();
foreach
(
$items
as
$item
)
$rows
[] =
$item
->attributes;
$this
->_sendResponse(200, CJSON::encode(
$rows
));
}
}
|
获取某一 item 的方法:
1
2
3
4
5
6
7
8
9
10
|
public
function
actionView()
{
if
(!isset(
$_GET
[
'id'
]))
$this
->_sendResponse(500,
'Item ID is missing'
);
$item
= Item::model()->findByPk(
$_GET
[
'id'
]);
if
(
is_null
(
$item
))
$this
->_sendResponse(404,
'No Item found'
);
else
$this
->_sendResponse(200, CJSON::encode(
$item
));
}
|
新建一个 Item 的方法:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
public
function
actionCreate()
{
$item
=
new
Item;
foreach
(
$_POST
as
$var
=>
$value
)
{
if
(
$item
->hasAttribute(
$var
))
$item
->
$var
=
$value
;
else
$this
->_sendResponse(500,
'Parameter Error'
);
}
if
(
$item
->save())
$this
->_sendResponse(200, CJSON::encode(
$item
));
else
$this
->_sendResponse(500,
'Could not Create Item'
);
}
|
更新一个 item 的方法:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
public
function
actionUpdate()
{
//获取 put 方法所带来的 json 数据
$json
=
file_get_contents
(
'php://input'
);
$put_vars
= CJSON::decode(
$json
,true);
$item
= Item::model()->findByPk(
$_GET
[
'id'
]);
if
(
is_null
(
$item
))
$this
->_sendResponse(400,
'No Item found'
);
foreach
(
$put_vars
as
$var
=>
$value
)
{
if
(
$item
->hasAttribute(
$var
))
$item
->
$var
=
$value
;
else
$this
->_sendResponse(500,
'Parameter Error'
);
}
if
(
$item
->save())
$this
->_sendResponse(200, CJSON::encode(
$item
));
else
$this
->_sendResponse(500,
'Could not Update Item'
);
}
|
删除某一 item 的方法:
1
2
3
4
5
6
7
8
9
10
|
public
function
actionDelete()
{
$item
= Item::model()->findByPk(
$_GET
[
'id'
]);
if
(
is_null
)
$this
->_sendResponse(400,
'No Item found'
);
if
(
$item
->
delete
())
$this
->_sendResponse(200,
'Delete Success'
);
else
$this
->_sendResponse(500,
'Could not Delete Item'
);
}
|
辅助方法。
返回响应的方法:
1
2
3
4
5
6
7
8
|
private
function
_sendResponse(
$status
= 200,
$body
=
''
,
$content_type
=
'text/html'
)
{
$status_header
=
'HTTP/1.1 '
.
$status
.
' '
.
$this
->_getStatusCodeMessage(
$status
);
header(
$status_header
);
header(
'Content-type: '
.
$content_type
);
echo
$body
;
Yii::app()->
end
();
}
|
获取 http 状态码的方法:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
private
function
_getStatusCodeMessage(
$status
)
{
$codes
= Array(
200 =>
'OK'
,
400 =>
'Bad Request'
,
401 =>
'Unauthorized'
,
402 =>
'Payment Required'
,
403 =>
'Forbidden'
,
404 =>
'Not Found'
,
500 =>
'Internal Server Error'
,
501 =>
'Not Implemented'
,
);
return
(isset(
$codes
[
$status
])) ?
$codes
[
$status
] :
''
;
}
|
这样我们就用 yii 框架实现了一个简单的对应某个 model 的 REST 风格的 json 调用接口。这里只实现了一些大框架的东西,具体到验证,数据的再组织都没有涉及。不过使用框架的好处就是程序组织都已经有人帮你考虑好了,按照框架的开发方式,再加上一些需要的功能是很方便的。