Relational RESTful controllers routes

Sometimes it's better to place subresource actions in their own controller, especially when you have more than 2 subresource actions.


Resource collection(资源集)

In this case, you must first specify resource relations in special rest YML or XML collection:


# src/Acme/HelloBundle/Resources/config/users_routes.yml
    type:     rest
    resource: Acme\HelloBundle\Controller\UsersController
    type:     rest
    parent:   users
    resource: Acme\HelloBundle\Controller\CommentsController

<!-- src/Acme/HelloBundle/Resources/config/users_routes.xml -->
<?xml version="1.0" encoding="UTF-8" ?>
<routes xmlns=""
    <import id="users" type="rest" resource="Acme\HelloBundle\Controller\UsersController" />
    <import type="rest" parent="users" resource="Acme\HelloBundle\Controller\CommentsController" />

Notice parent: users option in the second case. This option specifies that the comments resourceis child of the users resource.

注意第二部分的 parent: users 选项。该选项指定了comments资源是user资源的子资源。

It is also necessary to add type: rest to the routing.yml file:

在 routing.yml 文件中, type: rest必须要添加:

# app/config/routing.yml
    type: rest
    resource: "@AcmeHelloBundle/Resources/config/users_routes.yml"

In this case, your UsersController MUST always have a single resource get... action:

在本例中,您的 UsersController 总是需要有单个资源 get...的Action:

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 Action现在看上去如下所示:

class CommentsController extends Controller
    public function postCommentVoteAction($slug, $id)
    {} // "post_user_comment_vote" [POST] /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.


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
    type:     rest
    resource: "@AcmeHelloBundle/Resources/config/users_routes.yml"

That's all. Note that it's important to use the type: rest param when including your application'srouting 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 missingthe 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:


[POST] /users/{slug}/comments/{id}/vote

will become the route with the name post_user_comment_vote.


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 routecollections provides a name_prefix (name-prefix for xml and @NamePrefix for annotations) parameter (you can use name_prefix only in a file loaded by the rest loader.):


# app/config/routing.yml
    type: rest  # Required for `RestYamlLoader` to process imported routes
    prefix: /api
    resource: "@AcmeHelloBundle/Resources/config/users_routes.yml"

# src/Acme/HelloBundle/Resources/config/users_routes.yml
    type:         rest
    resource:     "@AcmeHelloBundle\Controller\CommentsController"
    name_prefix:  api_ # Our precious parameter

With this configuration, route name would become:



Say NO to name collisions!