Routing
Routing is how Symfony decides which controller method should handle an incoming URL. The modern way to define a route is a PHP 8 attribute placed directly above the controller method it belongs to — no separate routing file to keep in sync with your code.
Attribute-Based Routing
The #[Route(...)] attribute sits right on top of the method it maps to, so the URL
and the code that handles it live in the same place:
<?php
namespace App\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\Routing\Annotation\Route;
class ArticleController extends AbstractController
{
#[Route('/articles/{id<\d+>}', name: 'article_show')]
public function show(int $id)
{
// $id arrives here already cast to an int
return $this->render('article/show.html.twig', ['id' => $id]);
}
}
This is the modern default and the approach favored throughout this track. Symfony also lets you
define routes centrally in config/routes.yaml if you'd rather keep URL definitions
out of your controllers, but attributes are the recommended starting point.
Route Parameters and Requirements
In the example above, {id<\d+>} is an inline requirement —
it tells Symfony that {id} must match one or more digits, so a request like
/articles/abc won't even match this route. The same requirement can also be written
as a separate array on the attribute, which is useful when a pattern gets long or is reused:
#[Route('/articles/{id}', name: 'article_show', requirements: ['id' => '\d+'])]
public function show(int $id)
{
// same route as the inline version above
}
Both forms produce the exact same route — pick whichever reads more clearly for the route you're
writing. The inline <\d+> syntax is handy for quick, obvious constraints, while
the requirements array keeps things readable once a route has several parameters.
Named Routes and Generating URLs
Giving a route a name — like article_show above — means you never have
to hardcode the URL string elsewhere in your application. From inside a controller, call
generateUrl() with the route name and any parameters it needs:
$url = $this->generateUrl('article_show', ['id' => 5]);
// $url is now "/articles/5"
If the route's path ever changes, every place that generates a URL by name keeps working
automatically — only the #[Route] attribute itself needs updating.
Automatic Type-Casting
Notice the controller method signature used int $id rather than a plain
$id. Every URL segment arrives as a string, but when the matching method argument has
a scalar type-hint like int, float, or bool, Symfony
converts the value for you before the method runs — one less manual cast to remember.