• 原文出处:FOSRestBundle自带的index.rst
  • 原文作者:FriendsOfSymfony
  • 授权许可:创作共用协议
  • 翻译人员:FireHare
  • 校对人员:FireHare
  • 适用版本:Symfony 2
  • 文章状态:草译阶段

RestBundle
==========

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中定义

   

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!
对命名冲突说不吧!