Relational RESTful controllers routes
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:
1 2 3 4 5 6 7 8 9 10 11 | # src/Acme/HelloBundle/Resources/config/users_routes.yml
users:
type: rest
host: hostname.example.com
resource: Acme\HelloBundle\Controller\UsersController
comments:
type: rest
host: hostname.example.com
parent: users
resource: Acme\HelloBundle\Controller\CommentsController
|
1 2 3 4 5 6 7 8 9 10 | <!-- src/Acme/HelloBundle/Resources/config/users_routes.xml -->
<?xml version="1.0" encoding="UTF-8" ?>
<routes xmlns="http://friendsofsymfony.github.com/schema/rest"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://friendsofsymfony.github.com/schema/rest https://raw.github.com/FriendsOfSymfony/FOSRestBundle/master/Resources/config/schema/routing/rest_routing-1.0.xsd">
<import id="users" type="rest" resource="Acme\HelloBundle\Controller\UsersController" host="hostname.example.com" />
<import type="rest" parent="users" resource="Acme\HelloBundle\Controller\CommentsController" host="hostname.example.com" />
</routes>
|
Notice parent: users
option in the second case. This option specifies that
the comments resource is child of the users resource.
It is also necessary to add type: rest
to the routes.yaml
file:
1 2 3 4 | acme_hello:
type: rest
host: hostname.example.com
resource: "@AcmeHelloBundle/Resources/config/users_routes.yml"
|
In this case, your UsersController
MUST always have a single resource
get...
action:
1 2 3 4 5 6 7 8 9 10 11 | <?php
namespace AppBundle\Controller;
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 is not used in routes auto-generation process and can be any name you like.
Define child resource controller¶
CommentsController
actions now will looks like:
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 27 | <?php
namespace AppBundle\Controller;
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 routes.yaml
:
1 2 3 | users:
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’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.
Routes naming¶
RestBundle uses REST paths to generate route name. This means, that URL:
1 | [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
route collections 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.):
1 2 3 4 5 | # config/routes.yaml
users:
type: rest # Required for ``RestYamlLoader`` to process imported routes
prefix: /api
resource: "@AcmeHelloBundle/Resources/config/users_routes.yml"
|
1 2 3 4 5 | # src/Acme/HelloBundle/Resources/config/users_routes.yml
comments:
type: rest
resource: "@AcmeHelloBundle/Controller/CommentsController"
name_prefix: api_ # Our precious parameter
|
With this configuration, route name would become:
1 | api_vote_user_comment
|
Say NO to name collisions!
That was it!
This work, including the code samples, is licensed under a Creative Commons BY-SA 3.0 license.