New in Symfony 7.1: Mapped Route Parameters
May 21, 2024 • Published by Javier Eguiluz
Symfony 7.1 is backed by:
Symfony maps route parameters to controller arguments automatically since day one. You only have to use the same name in both places and Symfony does the necessary data type conversion:
1 2 3 4 5 6 7
#[Route('/document/{id}')]
public function showDocument(int $id): Response
{
// here, $id is an integer variable with the same value as
// the string value included in the URL after '/document/'
// ...
}
When using Doctrine entities, this feature is even more convenient because it can transform the route parameters into entities via database queries:
1 2 3 4 5 6 7 8 9 10 11
// ...
use App\Entity\Document;
#[Route('/document/{id}')]
public function showDocument(Document $document): Response
{
// using the $id value of the route, Symfony makes a database query
// to find an entity of type Document and whose id matches that value
// (and throws a 404 error if the entity is not found)
// ...
}
This feature works by using all the route parameters in the database query:
1 2 3 4 5 6 7
#[Route('/document/{slug}/{id}-{name}/')]
public function showDocument(Document $document): Response
{
// the database query in this case would be:
// $repository = $entityManager->getRepository(Document::class);
// $document = $repository->findOneBy(['slug' => 'the slug', 'id' => 'the id', 'name' => 'the name']);
}
This becomes problematic when the controller arguments contain more than one entity. All route parameters will be used to find all entities, resulting in errors. You can solve this with the #[MapEntity] attribute but in Symfony 7.1 we're introducing Mapped Route Parameters as an alternative.
When adding route parameters, you can now define the mapping between the route parameter and the controller argument:
1 2 3 4 5 6 7
#[Route('/document/{slug:category}/{id:document}-{name:document}/')]
public function showDocument(Document $document, Category $category): Response
{
// the database queries in this case would be:
// $document = $documentRepository->findOneBy(['id' => 'the id', 'name' => 'the name']);
// $category = $categoryRepository->findOneBy(['slug' => 'the slug']);
}
This explicit mapping configuration solves the issues when using multiple entities
as controller arguments and is more concise than using the #[MapEntity]
attribute.
This mapping also comes in handy when you can't change the route parameter names
but want to use different controller argument names:
1 2
#[Route('/voucher/{voucher:voucherCode}/{action:userAction}/')]
public function handleVoucher(string $voucherCode, string $userAction): Response
Given that this new feature provides a nice DX (developer experience) and is very concise, we've decided to deprecate the automatic mapping of route parameters into Doctrine entities starting from Symfony 7.1. This means that the following example is now deprecated:
1 2
#[Route('/document/{id}')]
public function showDocument(Document $document): Response
To fix this deprecation, you can use the #[MapEntity]
attribute:
1 2 3 4 5 6 7
use Symfony\Bridge\Doctrine\Attribute\MapEntity;
// ...
#[Route('/document/{id}')]
public function showDocument(
#[MapEntity(id: 'id')] Document $document,
): Response
Or you can use the name of the argument as route parameter:
1 2
#[Route('/document/{document}')]
public function showDocument(Document $document): Response
Help the Symfony project!
As with any Open-Source project, contributing code or documentation is the most common way to help, but we also have a wide range of sponsoring opportunities.
Comments are closed.
To ensure that comments stay relevant, they are closed for old posts.
That seems like a lot of work and such a massive (although fairly trivial) change considering it worked like that since symfony 2.x
Dont get me wrong this is a great feature and I generally like explicitness vs implicitness, but I hope this has a longer deprecation time than 8.0
/va/washington
/dc/washington
```php
#[Route('/place/{abbr:state}/{code:city}')]
public function showPlace(State $state, City $city): Response
{
// the database queries in this case should be
$state = $stateRepository->findOneBy(['abbr' => 'va']);
$city = $cityRepositiory->findOneBy(['state'=>$state, 'code' => 'washington']);
}
```
```php
#[Route('/document/{document}')]
public function showDocument(Document $document): Response
```
But if we use `MapEntity` attribute the deprecation is resolved