This bundle provides various tools to rapidly develop RESTful API's & applications with Symfony2.
这个Bundle提供各种工具来使Symfony2能够快速开发Rest风格的API和应用程序。
Its currently under development so key pieces that are planned are still missing.
它当前正在开发,因此其关键部分仍在规划中,并不明了。
For now the Bundle provides a view layer to enable output format agnostic Controllers,
which includes the ability to handle redirects differently based on a service container
aware Serializer service that can lazy load encoders and normalizers.
现在该Bundle提供一个视图层可以使输出格式与控制器无关,控制器有着处理不同重定向的功能,而该功能基于知道序列化服务可以延迟加载编码和正规化的服务容器。
Furthermore a custom route loader can be used to when following a method
naming convention to automatically provide routes for multiple actions by simply
configuring the name of a controller.
此外,通过简单配置控制器名,一个自定义路由加载器可以遵循方法的命名约定去自动提供多操作路由。
It also has support for RESTful decoding of HTTP request body and Accept headers
as well as a custom Exception controller that assists in using appropriate HTTP
status codes.
它也支持HTTP请求包体和Accept头的REST风格解码,以及使用适当HTTP状态码的自定义异常控制器。
Eventually the bundle will also provide normalizers for form and validator instances as
well as provide a solution to generation end user documentation describing the REST API.
最后,Bundle也为表单和验证器实例提供正规化,以及提供生成描述REST API最终用户文档的解决方案。
Installation
安装
============
1. Add this bundle to your project as a Git submodule:
1. 将该Bundle当作Git子模组添加到您项目中:
$ git submodule add git://github.com/FriendsOfSymfony/FOSRestBundle.git vendor/bundles/FOS/FOSRestBundle
译者注:如果使用deps文件的话,可以添加以下语句:
[FOSRestBundle]
git=git://github.com/FriendsOfSymfony/FOSRestBundle.git
target=/bundles/FOS/RestBundle
2. 将FOS名称空间添加到您的自动加载器中:
// app/autoload.php
$loader->registerNamespaces(array(
'FOS' => __DIR__.'/../vendor/bundles',
// your other namespaces
));
3. 将该Bundle添加到您应用程序内核中:
// application/ApplicationKernel.php
public function registerBundles()
{
return array(
// ...
new FOS\RestBundle\FOSRestBundle(),
// ...
);
}
Examples
示例
========
The LiipHelloBundle provides several examples for the RestBundle:
LiipHelloBundle为RestBundle提供了几个例子:
https://github.com/liip/HelloBundle
There is also a fork of the Symfony2 Standard Edition that is configured to show the LiipHelloBundle examples:
还有一个Symfony2标准版的派生版本,配置用于显示LiipHelloBundle示例:
https://github.com/lsmith77/symfony-standard/tree/techtalk
Configuration
配置
=============
Basic configuration
基本配置
-------------------
The RestBundle allows adapting several classes it uses. Alternatively entire
services may be adapted. In the following examples the default Json encoder class
is modified and a custom serializer service is configured:
RestBundle允许调整它所用的类。此外,整个服务也可以调整。在下列例子中将改变缺省的Json编码类,并配置自定义的序列化服务:
# app/config.yml
fos_rest:
classes:
json: MyProject\MyBundle\Serializer\Encoder\JsonEncoder
services:
serializer: my.serializer
Note the service for the RSS encoder needs to be defined in a custom bundle:
注意RSS编码的服务需要在自定义Bundle中定义
<service id="my.encoder.rss" class="MyProject\MyBundle\Serializer\Encoder\RSSEncoder" />
View support
视图支持
------------
Registering a custom encoder requires modifying your configuration options.
Following is an example adding support for a custom RSS encoder while removing
support for xml.
注册自定义编码器需要修改您的配置选项。下列例子添加对自定义RSS编码器的支持,同时取消到XML的支持。
When using View::setResourceRoute() the default behavior of forcing
a redirect to the route for html is disabled.
当使用View::setResourceRoute()时强制重定向到html路由的缺省行为将被禁用。
The default JSON encoder class is modified and a custom serializer service
is configured.
缺省的JSON编码器类被修改,自定义的序列化服务被配置。
The a default normalizer is registered with the ``fos_rest.get_set_method_normalizer``.
缺省的正规化通过``fos_rest.get_set_method_normalizer``来注册。
Also a default key for any form instances inside view parameters is set to ``form``.
视图中所有表单实例的缺省关键词都被设为``form``。
Finally the HTTP response status code for failed validation is set to ``400``:
最后HTTP响应的状态码因为验证失败被设为``400``:
# app/config.yml
fos_rest:
formats:
rss: my.encoder.rss
xml: false
force_redirects:
html: false
normalizers:
- "fos_rest.get_set_method_normalizer"
default_form_key: form
failed_validation: HTTP_BAD_REQUEST
Listener support
监听器支持
----------------
To enable the Request body decoding, Request format and the Response flash message listener
simply adapt your configuration as follows:
为了启用请求体解码,请求格式和响应“闪”消息监听器简单适配您的配置,如下所示:
# app/config.yml
fos_rest:
format_listener: true
body_listener: true
flash_message_listener: true
In the behavior of the format listener can be configured in a more granular fashion.
Below you can see the defaults in case ``format_listener`` is set to true as above:
格式监听器的行为可以进行更细化地配置。下面您可以看到``format_listener``象上面一样被缺省设置为true:
# app/config.yml
fos_rest:
format_listener:
default_priorities:
- html
- "*/*"
fallback_format: html
In the behavior of the flash message listener can be configured in a more granular fashion.
Below you can see the defaults in case ``flash_message_listener`` is set to true as above:
“闪”消息监听器的行为也可以进行更细化地配置。下面您可以看到``flash_message_listener``象上面一样被缺省设置为true:
# app/config.yml
fos_rest:
flash_message_listener:
name: flashes
path: /
domain: ~
secure: false
httpOnly: true
You may also specify a ``default_format`` that the routing loader will use for
the ``_format`` parameter if none is specified.
您也可以指定``default_format``,这样路由加载器将在``_format``参数被设为none时使用。
# app/config.yml
fos_rest:
routing_loader:
default_format: json
Note that setting ``default_priorities`` to a non empty array enables Accept header negotiations.
Also note in case for example more complex Accept header negotiations are required, the user should
either set a custom ``FormatListener`` class or register their own "onKernelController" event.
注意将``default_priorities``设置为一个非空数组可以启动Accept头协商。更值得注意的是,要求更复杂的Accept头协商的例子,用户设置自定义的``FormatListener``类或注册它们自己的"onKernelController"事件。
# app/config.yml
fos_rest:
classes:
format_listener: MyProject\MyBundle\Controller\FormatListener
Note see the section about the view support in regards to how to register/unregister
encoders for specific formats as the request body decoding uses encoders for decoding.
注意参阅视图支持一节关于如何为特定格式注册/注销编码器,用于请求包体解码该格式。
SensioFrameworkExtraBundle support
SensioFrameworkExtraBundle支持
----------------------------------
This requires adding the SensioFrameworkExtraBundle to you vendors:
这要求将SensioFrameworkExtraBundle添加到您的vendors中:
$ git submodule add git://github.com/sensio/SensioFrameworkExtraBundle.git vendor/bundles/Sensio/Bundle/FrameworkExtraBundle
Make sure to disable view annotations in the SensioFrameworkExtraBundle config,
enable or disable any of the other features depending on your needs:
确保在SensioFrameworkExtraBundle配置中禁用视图注释功能,其它功能按您所需启动或禁用:
# app/config.yml
sensio_framework_extra:
view: { annotations: false }
router: { annotations: true }
Finally enable the SensioFrameworkExtraBundle listener in the RestBundle:
最后在RestBundle中启动SensioFrameworkExtraBundle监听器:
# app/config.yml
fos_rest:
frameworkextra_bundle: true
JMSSerializerBundle support
JMSSerializerBundle支持
---------------------------
Note: Temporarily please use this fork https://github.com/lsmith77/SerializerBundle/tree/use_core
注意:暂时请使用这个分支https://github.com/lsmith77/SerializerBundle/tree/use_core
This requires adding the JMSSerializerBundle to you vendors:
这要求将JMSSerializerBundle添加到您的vendors中:
$ git submodule add git://github.com/schmittjoh/SerializerBundle.git vendor/bundles/JMS/SerializerBundle
Finally enable the JMSSerializerBundle support in the RestBundle:
最后在RestBundle中启动JMSSerializerBundle支持:
# app/config.yml
fos_rest:
serializer_bundle: true
When using JMSSerializerBundle the ``normalizers`` config option is ignored as in this case
annotations should be used to register specific normalizers for a given class.
当使用JMSSerializerBundle,``normalizers``配置选项将被忽略,因为在这种情况下,注释将用于为指定类注册特定的normalizers。
ExceptionController support
ExceptionController支持
---------------------------
The RestBundle view layer aware ExceptionController is enabled as follows:
RestBundle视图层知道ExceptionController被启动,如下所示:
# app/config.yml
framework:
exception_controller: "FOS\RestBundle\Controller\ExceptionController::showAction"
To map Exception classes to HTTP response status codes an ``exception_map`` may be configured,
where the keys match a fully qualified class name and the values are either an integer HTTP response
status code or a string matching a class constant of the ``FOS\RestBundle\Response\Codes`` class:
要将Exception类映射到HTTP响应状态码,需要配置``exception_map``,其中键匹配全限定类名,值是集成HTTP响应状态码或符合``FOS\RestBundle\Response\Codes``类内容的字符串。
# app/config.yml
fos_rest:
exception:
codes:
"Symfony\Component\Routing\Matcher\Exception\NotFoundException": 404
"Doctrine\ORM\OptimisticLockException": HTTP_CONFLICT
messages:
"Acme\HelloBundle\Exception\MyExceptionWithASafeMessage": true
Routing
路由
=======
The RestBundle provides custom route loaders to help in defining REST friendly routes.
RestBundle提供自定义路由加载器去帮助定义REST风格的路由。
Single RESTful controller routes
单个REST风格的控制器路由
--------------------------------
# app/config/routing.yml
users:
type: rest
resource: Acme\HelloBundle\Controller\UsersController
This will tell Symfony2 to automatically generate proper REST routes from your `UsersController` action names.
Notice `type: rest` option. It's required so that the RestBundle can find which routes are supported.
这将告诉Symfony2从您`UsersController`的动作名中自动生成适当的REST路由。
请注意`type: rest`选项,这样RestBundle可以找到哪个路由被支持。
## Define resource actions
class UsersController extends Controller
{
public function getUsersAction()
{} // `get_users` [GET] /users
public function newUsersAction()
{} // `new_users` [GET] /users/new
public function postUsersAction()
{} // `post_users` [POST] /users
public function patchUsersAction()
{} // `patch_users` [PATCH] /users
public function getUserAction($slug)
{} // `get_user` [GET] /users/{slug}
public function editUserAction($slug)
{} // `edit_user` [GET] /users/{slug}/edit
public function putUserAction($slug)
{} // `put_user` [PUT] /users/{slug}
public function patchUserAction($slug)
{} // `patch_user` [PATCH] /users/{slug}
public function lockUserAction($slug)
{} // `lock_user` [PUT] /users/{slug}/lock
public function banUserAction($slug, $id)
{} // `ban_user` [PUT] /users/{slug}/ban
public function removeUserAction($slug)
{} // `remove_user` [GET] /users/{slug}/remove
public function deleteUserAction($slug)
{} // `delete_user` [DELETE] /users/{slug}
public function getUserCommentsAction($slug)
{} // `get_user_comments` [GET] /users/{slug}/comments
public function newUserCommentsAction($slug)
{} // `new_user_comments` [GET] /users/{slug}/comments/new
public function postUserCommentsAction($slug)
{} // `post_user_comments` [POST] /users/{slug}/comments
public function getUserCommentAction($slug, $id)
{} // `get_user_comment` [GET] /users/{slug}/comments/{id}
public function editUserCommentAction($slug, $id)
{} // `edit_user_comment` [GET] /users/{slug}/comments/{id}/edit
public function putUserCommentAction($slug, $id)
{} // `put_user_comment` [PUT] /users/{slug}/comments/{id}
public function voteUserCommentAction($slug, $id)
{} // `vote_user_comment` [PUT] /users/{slug}/comments/{id}/vote
public function removeUserCommentAction($slug, $id)
{} // `remove_user_comment` [GET] /users/{slug}/comments/{id}/remove
public function deleteUserCommentAction($slug, $id)
{} // `delete_user_comment` [DELETE] /users/{slug}/comments/{id}
}
That's all. All your resource (`UsersController`) actions will get mapped to the proper routes
as shown in the comments in the above example. Here are a few things to note:
就这样,正如上面示例中注释所显示的那样,所有您的资源(`UsersController`)动作将被映射到适当的路由。
### REST Actions
### REST动作
There are 5 actions that have special meaning in regards to REST and have the following behavior:
对REST来说有5个动作是有着特殊含义的:
* **get** - this action accepts *GET* requests to the url */resources* and returns all resources for this type. Shown as
`UsersController::getUsersAction()` above. This action also accepts *GET* requests to the url */resources/{id}* and
returns a single resource for this type. Shown as `UsersController::getUserAction()` above.
* **get** - 该动作接收到URL:*/resources*的*GET*请求,并为该类型返回所有的资源。正如上例`UsersController::getUsersAction()`所示。该动作也接受到URL:*/resources/{id}*的*GET*请求并为该类型返回单个资源。
* **post** - this action accepts *POST* requests to the url */resources* and creates a new resource of this type. Shown
as `UsersController::postUsersAction()` above.
* **post** - 该动作接收到URL:*/resources*的*POST*请求,并创建该类型的响应。正如上例`UsersController::postUsersAction()`所示。
* **put** - this action accepts *PUT* requests to the url */resources/{id}* and updates a single resource for this type.
Shown as `UsersController::putUserAction()` above.
* **put** - 该动作接收到URL:*/resources/{id}*的*PUT*请求,并更新该类型的单个资源。正如上例`UsersController::putUserAction()`所示。
* **delete** - this action accepts *DELETE* requests to the url */resources/{id}* and deltes a single resource for this
type. Shown as `UsersController::deleteUserAction()` above.
* **delete** - 该动作接收到URL:*/resources/{id}*的*DELETE*请求,并删除该类型的单个资源。正如上例 `UsersController::deleteUserAction()`所示。
* **patch** - this action accepts *PATCH* requests to the url */resources* and is supposed to partially modify collection
of resources (e.g. apply batch modifications to subset of resources). Shown as `UsersController::patchUsersAction()` above.
This action also accepts *PATCH* requests to the url */resources/{id}* and is supposed to partially modify the resource.
Shown as `UsersController::patchUserAction()` above.
* **patch** -该动作接收到URL:*/resources*的 *PATCH* 请求,并假定被部分修改资源集(如:对资源的子集应用批处理)。正如上例`UsersController::patchUsersAction()` 所示。该动作还接受到URL:*/resources/{id}*的*PATCH*请求,并假定部分修改了该资源。正如上例`UsersController::patchUserAction()` 所示。
### Conventional Actions
### 常规动作
HATEOAS, or Hypermedia as the Engine of Application State, is an aspect of REST which allows clients to interact with the
REST service with hypertext - most commonly through an HTML page. There are 3 Conventional Action routings that are
supported by this bundle:
HATEOAS或超媒体作为应用程序状态引擎,是REST(允许客户通过超文本,通常是HTML页,与REST服务交互)的一个方面,本Bundle支持有3个常规动作路由:
* **new** - A hypermedia representation that acts as the engine to *POST*. Typically this is a form that allows the client
to *POST* a new resource. Shown as `UsersController::newUsersAction()` above.
* **new** - 一个超媒体表现充当*POST*引擎。典型地,允许客户端去*POST*一个新资源的表单。正如上例`UsersController::newUsersAction()`所示。
* **edit** - A hypermedia representation that acts as the engine to *PUT*. Typically this is a form that allows the client
to *PUT*, or update, an existing resource. Shown as `UsersController::editUserAction()` above.
* **edit** - 一个超媒体表现充当*PUT*引擎。典型地,允许客户端去*PUT*或更新一个已存在的资源。正如上例 `UsersController::editUserAction()`所示。
* **remove** - A hypermedia representation that acts as the engine to *DELETE*. Typically this is a form that allows the
client to *DELETE* an existing resource. Commonly a confirmation form. Shown as `UsersController::removeUserAction()` above.
* **remove** - A hypermedia representation that acts as the engine to *DELETE*. 一个超媒体表现充当*DELETE*引擎。典型地,允许客户端去*DELETE*一个已存在的资源。正如上例`UsersController::removeUserAction()`所示。
### Custom PUT Actions
### 自定义PUT动作
All actions that do not match the ones listed in the sections above will register as a *PUT* action. In the controller
shown above, these actions are `UsersController::lockUserAction()` and `UsersController::banUserAction()`. You could
just as easily create a method called `UsersController::promoteUserAction()` which would take a *PUT* request to the url
*/users/{slug}/promote*. This allows for easy updating of aspects of a resource, without having to deal with the
resource as a whole at the standard *PUT* endpoint.
所有不能匹配本节上述列表中的动作将作为*PUT*动作注册。如上面控制器展示的`UsersController::lockUserAction()`和`UsersController::banUserAction()`那样。您可以很容易地创建一个名为`UsersController::promoteUserAction()`的方法,它将*PUT*请求发送到URL:*/users/{slug}/promote*。这样可以很容易地更新资源的某些方面,而无须将其作为标准*PUT*终端的整体进行处理。
### Sub-Resource Actions
### 子资源动作
Of course it's possible and common to have sub or child resources. They are easily defined within the same controller by
following the naming convention - as seen in the example above with
`UsersController::getUserCommentsAction()`. This is a good strategy to follow when the child resource needs the parent
resource's ID in order to look up itself.
当然,拥有子资源是常见的。它们可以很容易地在同一控制器中通过`ResourceController::actionResourceSubResource()`来定义,正如上面示例中`UsersController::getUserCommentsAction()`一样。在子资源需要父资源ID查找自身时这是一个很好的策略。
Relational RESTful controllers routes
关系REST风格控制器路由
-------------------------------------
Sometimes it's better to place subresource actions in their own controller, especially when
you have more than 2 subresource actions.
有时,将子资源动作放在它们自己的控制器中会更好。尤其是当您拥有2个以上子资源的动作时。
## Resource collection
## 资源集
In this case, you must first specify resource relations in special rest YML or XML collection:
在这种情况下,您必须首先指定在特定的REST风格的YML或XML集中的资源关系:
# src/Acme/HelloBundle/Resources/config/users_routes.yml
users:
type: rest
resource: "@AcmeHello\Controller\UsersController"
comments:
type: rest
parent: users
resource: "@AcmeHello\Controller\CommentsController"
Notice `parent: users` option in the second case. This option specifies that the comments resource
is child of the users resource. In this case, your `UsersController` MUST always have a single
resource `get...` action:
注意第二部分的`parent: users`选项。该选项指定了comments资源是users资源的子资源。在这种情况下,您的`UsersController`必须总是拥有单个资源`get...`动作:
class UsersController extends Controller
{
public function getUserAction($slug)
{} // `get_user` [GET] /users/{slug}
...
}
It's used to determine the parent collection name. Controller name itself not used in routes
auto-generation process and can be any name you like.
它常用于确定父资源集名。控制器名自身并不用于路由自动协商过程,它可以是您想要的任何名字。
## Define child resource controller
## 定义子资源控制器
`CommentsController` actions now will looks like:
`CommentsController`动作现在看上去象:
class CommentsController extends Controller
{
public function voteCommentAction($slug, $id)
{} // `vote_user_comment` [PUT] /users/{slug}/comments/{id}/vote
public function getCommentsAction($slug)
{} // `get_user_comments` [GET] /users/{slug}/comments
public function getCommentAction($slug, $id)
{} // `get_user_comment` [GET] /users/{slug}/comments/{id}
public function deleteCommentAction($slug, $id)
{} // `delete_user_comment` [DELETE] /users/{slug}/comments/{id}
public function newCommentsAction($slug)
{} // `new_user_comments` [GET] /users/{slug}/comments/new
public function editCommentAction($slug, $id)
{} // `edit_user_comment` [GET] /users/{slug}/comments/{id}/edit
public function removeCommentAction($slug, $id)
{} // `remove_user_comment` [GET] /users/{slug}/comments/{id}/remove
}
Notice, we got rid of the `User` part in action names. That is because the RestBundle routing
already knows, that `CommentsController::...` is child resources of `UsersController::getUser()`
resource.
注意,我们摆脱了动作名中的`User`部分。那是因为RestBundle路由已经知道,`CommentsController::...`是`UsersController::getUser()`资源的子资源。
## Include resource collections in application routing
## 在应用程序路由中包含资源集
Last step is mapping of your collection routes into the application `routing.yml`:
最后一步是将您的集合路由映射放入应用程序的`routing.yml`文件中:
# app/config/routing.yml
users:
type: rest
resource: "@AcmeHello/Resources/config/users_routes.yml"
That's all. Note that it's important to use the `type: rest` param when including your application's
routing file. Without it, rest routes will still work but resource collections will fail. If you get an
exception that contains `...routing loader does not support given key: "parent"...` then you are most likely missing
the `type: rest` param in your application level routes include.
就是这样。注意当包含您应用程序路由文件时使用`type: rest`参数是重要的。没有它,REST路由仍然可以工作,但资源集将失败。如果您得到了一个内容为`...routing loader does not support given key: "parent"...`的异常,那么您最有可能在您的应用程序级别的路由中没有包含`type: rest`参数。
## Routes naming
## 路由命名
RestBundle uses REST paths to generate route name. This means, that URL:
RestBundle使用REST风格的路径来生成路由名。这就意味着,URL:
[PUT] /users/{slug}/comments/{id}/vote
will become the route with the name:
的路由名为:
vote_user_comment
For further examples, see comments of controllers in the code above.
更多示例,参见上例代码中控制器的注释部分。
### Naming collisions
### 命名冲突
Sometimes, routes auto-naming will lead to route names collisions, so RestBundle route
collections provides a `name_prefix` (`name-prefix` for xml and @NamePrefix for
annotations) parameter:
有时,路由自动命名会导致路由名冲突,因此RestBundle路由集提供了`name_prefix`(在XML中是`name_prefix`而注释中则是@NamePrefix)参数:
# src/Acme/HelloBundle/Resources/config/users_routes.yml
comments:
type: rest
resource: "@AcmeHello\Controller\CommentsController"
name_prefix: api_
With this configuration, route name would become:
通过上述配置,路由名就会变成:
api_vote_user_comment
Say NO to name collisions!
对命名冲突说不吧!
本文转自 firehare 51CTO博客,原文链接:http://blog.51cto.com/firehare/596869,如需转载请自行联系原作者