Encodera

Thanks for reading!

Donate to the site — we work hard for you.

Contents

Routing

A route connects an address with a controller method. In Symfony it is written as an attribute right above the method — the address and the code handling it always sit together.

A simple route

use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Attribute\Route;
 
class BlogController
{
    #[Route('/blog', name: 'blog_index')]
    public function index(): Response
    {
        return new Response('List of posts');
    }
}

name is the route's name. Links are generated by it, so always set one.

Parameters

A part of the address in curly braces goes into the method argument of the same name:

#[Route('/blog/{slug}', name: 'blog_show')]
public function show(string $slug): Response
{
    return new Response("Post: $slug");
}

The address /blog/first-post passes the string first-post to the method.

Requirements and defaults

A regular expression in angle brackets restricts a parameter, and a default value on the argument makes it optional:

#[Route('/blog/page/{page<\d+>}', name: 'blog_page')]
public function page(int $page = 1): Response
{
    return new Response("Page $page");
}

The address /blog/page/abc does not match this route — Symfony returns a 404 error.

HTTP methods

#[Route('/blog/{id}', name: 'blog_update', methods: ['PUT', 'PATCH'])]
public function update(int $id): Response
{
    // …
}

Without methods a route answers any method.

A shared prefix

An attribute above the class adds the start of the address and of the name to every route inside:

#[Route('/admin', name: 'admin_')]
class AdminController
{
    #[Route('/users', name: 'users')]   // /admin/users, named admin_users
    public function users(): Response
    {
        // …
    }
}

Addresses are not written by hand — they are built from the route name. In a controller:

$url = $this->generateUrl('blog_show', ['slug' => 'first-post']);
// /blog/first-post

In a template:

<a href="{{ path('blog_show', {slug: post.slug}) }}">{{ post.title }}</a>

If the route's address changes, every link updates by itself.

Listing routes

php bin/console debug:router
php bin/console router:match /blog/first-post

The second command shows which route handles an address.

Common mistake

Routes are checked in order, and the first match wins. If /blog/{slug} is declared before /blog/new, the address /blog/new lands in the first one — with slug equal to new. Declare exact addresses higher up, or set the order explicitly: #[Route('/blog/new', priority: 2)].

Thanks for reading!

Donate to the site — we work hard for you.