How to Define Route Requirements
Edit this pageWarning: You are browsing the documentation for Symfony 4.2, which is no longer maintained.
Read the updated version of this page for Symfony 6.3 (the current stable version).
How to Define Route Requirements
Route requirements can be used to make a specific route
only match under specific conditions. The simplest example involves restricting
a routing {wildcard}
to only match some regular expression:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
// src/Controller/BlogController.php
namespace App\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\Routing\Annotation\Route;
class BlogController extends AbstractController
{
/**
* @Route("/blog/{page}", name="blog_list", requirements={"page"="\d+"})
*/
public function list($page)
{
// ...
}
}
1 2 3 4 5 6
# config/routes.yaml
blog_list:
path: /blog/{page}
controller: App\Controller\BlogController::list
requirements:
page: '\d+'
1 2 3 4 5 6 7 8 9 10 11 12 13
<!-- config/routes.xml -->
<?xml version="1.0" encoding="UTF-8" ?>
<routes xmlns="http://symfony.com/schema/routing"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://symfony.com/schema/routing
https://symfony.com/schema/routing/routing-1.0.xsd">
<route id="blog_list" path="/blog/{page}" controller="App\Controller\BlogController::list">
<requirement key="page">\d+</requirement>
</route>
<!-- ... -->
</routes>
1 2 3 4 5 6 7 8 9 10 11 12 13
// config/routes.php
use App\Controller\BlogController;
use Symfony\Component\Routing\Loader\Configurator\RoutingConfigurator;
return function (RoutingConfigurator $routes) {
$routes->add('blog_list', '/blog/{page}')
->controller([BlogController::class, 'list'])
->requirements([
'page' => '\d+',
])
;
// ...
};
Thanks to the \d+
requirement (i.e. a "digit" of any length), /blog/2
will
match this route but /blog/some-string
will not match.
Earlier Routes Always Win
Why would you ever care about requirements? If a request matches two routes, then the first route always wins. By adding requirements to the first route, you can make each route match in just the right situations. See Routing for an example.
Since the parameter requirements are regular expressions, the complexity and flexibility of each requirement is entirely up to you. Suppose the homepage of your application is available in two different languages, based on the URL:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
// src/Controller/MainController.php
// ...
class MainController extends AbstractController
{
/**
* @Route("/{_locale}", defaults={"_locale"="en"}, requirements={
* "_locale"="en|fr"
* })
*/
public function homepage($_locale)
{
// ...
}
}
1 2 3 4 5 6 7
# config/routes.yaml
homepage:
path: /{_locale}
controller: App\Controller\MainController::homepage
defaults: { _locale: en }
requirements:
_locale: en|fr
1 2 3 4 5 6 7 8 9 10 11 12
<!-- config/routes.xml -->
<?xml version="1.0" encoding="UTF-8" ?>
<routes xmlns="http://symfony.com/schema/routing"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://symfony.com/schema/routing
https://symfony.com/schema/routing/routing-1.0.xsd">
<route id="homepage" path="/{_locale}" controller="App\Controller\MainController::homepage">
<default key="_locale">en</default>
<requirement key="_locale">en|fr</requirement>
</route>
</routes>
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
// config/routes.php
use App\Controller\MainController;
use Symfony\Component\Routing\Loader\Configurator\RoutingConfigurator;
return function (RoutingConfigurator $routes) {
$routes->add('homepage', '/{_locale}')
->controller([MainController::class, 'homepage'])
->defaults([
'_locale' => 'en',
])
->requirements([
'_locale' => 'en|fr',
])
;
};
For incoming requests, the {_locale}
portion of the URL is matched against
the regular expression (en|fr)
.
Path | Parameters |
---|---|
/ |
{_locale} = "en" |
/en |
{_locale} = "en" |
/fr |
{_locale} = "fr" |
/es |
won't match this route |
Note
You can enable UTF-8 route matching by setting the utf8
option when
declaring or importing routes. This will make e.g. a .
in requirements
match any UTF-8 characters instead of just a single byte.
Tip
The route requirements can also include container parameters, as explained in this article. This comes in handy when the regular expression is very complex and used repeatedly in your application.
Adding HTTP Method Requirements
In addition to the URL, you can also match on the method of the incoming request (i.e. GET, HEAD, POST, PUT, DELETE). Suppose you create an API for your blog and you have 2 routes: One for displaying a post (on a GET or HEAD request) and one for updating a post (on a PUT request). This can be accomplished with the following route configuration:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
// src/Controller/BlogApiController.php
namespace App\Controller;
// ...
class BlogApiController extends AbstractController
{
/**
* @Route("/api/posts/{id}", methods={"GET","HEAD"})
*/
public function show($id)
{
// ... return a JSON response with the post
}
/**
* @Route("/api/posts/{id}", methods={"PUT"})
*/
public function edit($id)
{
// ... edit a post
}
}
1 2 3 4 5 6 7 8 9 10
# config/routes.yaml
api_post_show:
path: /api/posts/{id}
controller: App\Controller\BlogApiController::show
methods: GET|HEAD
api_post_edit:
path: /api/posts/{id}
controller: App\Controller\BlogApiController::edit
methods: PUT
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
<!-- config/routes.xml -->
<?xml version="1.0" encoding="UTF-8" ?>
<routes xmlns="http://symfony.com/schema/routing"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://symfony.com/schema/routing
https://symfony.com/schema/routing/routing-1.0.xsd">
<route id="api_post_show"
path="/api/posts/{id}"
controller="App\Controller\BlogApiController::show"
methods="GET|HEAD"/>
<route id="api_post_edit"
path="/api/posts/{id}"
controller="App\Controller\BlogApiController::edit"
methods="PUT"/>
</routes>
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
// config/routes.php
use App\Controller\BlogApiController;
use Symfony\Component\Routing\Loader\Configurator\RoutingConfigurator;
return function (RoutingConfigurator $routes) {
$routes->add('api_post_show', '/api/posts/{id}')
->controller([BlogApiController::class, 'show'])
->methods(['GET', 'HEAD'])
;
$routes->add('api_post_edit', '/api/posts/{id}')
->controller([BlogApiController::class, 'edit'])
->methods(['PUT'])
;
// or use collection
$api = $routes->collection('api_post_')
->prefix('/api/posts/{id}')
;
$api->add('show')
->controller([BlogApiController::class, 'show'])
->methods(['GET', 'HEAD'])
;
$api->add('edit')
->controller([BlogApiController::class, 'edit'])
->methods(['PUT'])
;
};
Despite the fact that these two routes have identical paths
(/api/posts/{id}
), the first route will match only GET or HEAD requests and
the second route will match only PUT requests. This means that you can display
and edit the post with the same URL, while using distinct controllers for the
two actions.
Note
If no methods
are specified, the route will match on all methods.
Tip
If you're using HTML forms and HTTP methods other than GET
and POST
,
you'll need to include a _method
parameter to fake the HTTP method. See
How to Change the Action and Method of a Form for more information.
Adding a Host Requirement
You can also match on the HTTP host of the incoming request. For more information, see How to Match a Route Based on the Host in the Routing component documentation.
Adding Dynamic Requirements with Expressions
For really complex requirements, you can use dynamic expressions to match any information on the request. See How to Restrict Route Matching through Conditions.