Routes
Routes live next to the code they run, defined as PHP attributes. No separate routing files to keep in sync (though YAML config is also available if you prefer it).
Wrap any part of the URL in curly braces to make it dynamic. The matched value is passed to the method as an argument with the same name.
Add requirements to placeholders with regular expressions. Symfony also converts the value to the type of the argument: this $year is already an integer.
Routes have names, so you never hardcode URLs anywhere else: templates and controllers generate them with path('blog_show', {slug: 'symfony-8'}). Change the URL once, and it changes everywhere.
<?phpnamespace App\Controller;use Symfony\Component\HttpFoundation\Response;use Symfony\Component\Routing\Attribute\Route;class BlogController{ #[Route('/blog', name: 'blog_list')] public function list(): Response { // ... } #[Route('/blog/{slug}', name: 'blog_show')] public function show(string $slug): Response { // ... } #[Route('/blog/archive/{year}', requirements: ['year' => '\d{4}'])] public function archive(int $year): Response { // ... }}