Skip to content

[Routing] Add {foo:bar} syntax to define a mapping between a route parameter and its corresponding request attribute #54720

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
May 2, 2024

Conversation

nicolas-grekas
Copy link
Member

@nicolas-grekas nicolas-grekas commented Apr 24, 2024

Q A
Branch? 7.1
Bug fix? no
New feature? yes
Deprecations? no
Issues -
License MIT

While trying to improve the DX of auto-mapping Doctrine entities and from the discussion on the related PR #54455, I realized that it would help a lot if we were able to express a mapping between route parameter and request attributes directly into route definitions.

This PR adds the ability to define a route with such a mapping:

#[Route('/conference/{slug:conference}')]

On the router side, the side-effect of this is just that a new _route_mapping array is returned by the matcher, and nothing else.

Then, in HttpKernel's RouterListener, we use that parameter to map route parameters to request attributes. On their turn, argument resolvers will just see a request attribute named conference. But they can also now read the _route_mapping attribute and decide to do more tailored things depending on the mapping.

For example, one could define this route:

#[Route('/conference/{id:conference}/{slug:conference}')]

This would be turned into a request attribute named conference with ['id' => 'the-id', 'slug' => 'the-slug'] as content.

This mapping concern already leaks into many value resolver attributes (see their "name" property).

For the entity value resolver, this feature will allow deprecating auto-mapping altogether, and will make things more explicit.

@carsonbot carsonbot added this to the 7.1 milestone Apr 24, 2024
@nicolas-grekas nicolas-grekas modified the milestones: 7.1, 7.2 Apr 24, 2024
@nicolas-grekas nicolas-grekas changed the title [Routing] Add {foo:bar} syntax to define a mapping between a route parameter and its corresponding attribute [Routing] Add {foo:bar} syntax to define a mapping between a route parameter and its corresponding request attribute Apr 24, 2024
@nicolas-grekas nicolas-grekas modified the milestones: 7.2, 7.1 May 2, 2024
…parameter and its corresponding request attribute
@fabpot
Copy link
Member

fabpot commented May 2, 2024

Thank you @nicolas-grekas.

@fabpot fabpot merged commit 15956b2 into symfony:7.1 May 2, 2024
4 of 10 checks passed
fabpot added a commit that referenced this pull request May 2, 2024
… favor of mapped route parameters (nicolas-grekas)

This PR was merged into the 7.1 branch.

Discussion
----------

[DoctrineBridge] Deprecate auto-mapping of entities in favor of mapped route parameters

| Q             | A
| ------------- | ---
| Branch?       | 7.1
| Bug fix?      | no
| New feature?  | yes
| Deprecations? |
| Issues        | Fix #50739
| License       | MIT

Auto-mapping of entities on controllers is a foot-gun when multiple entities are listed on the signature of the controller.
This is described extensively by e.g. `@stof` in the linked issue and in a few others.

The issue is that we try to use all request attributes to call a `findOneBy`, but when there are many entities, there can be an overlap in the naming of the field/associations of both entities.

In this PR, I propose to deprecate auto-mapping and to replace it with mapped route parameters, as introduced in #54720.

If we go this way, people that use auto-mapping to e.g. load a `$conference` based on its `{slug}` will have to declare the mapping by using `{slug:conference}` instead. That makes everything explicit and keeps a nice DX IMHO, by not forcing a `#[MapEntity]` attribute for simple cases.

Commits
-------

a49f9ea [DoctrineBridge] Deprecate auto-mapping of entities in favor of mapped route parameters
@fabpot fabpot mentioned this pull request May 2, 2024
@nicolas-grekas nicolas-grekas deleted the route-mapping branch May 21, 2024 08:12
@hellomedia
Copy link
Contributor

Thank you @nicolas-grekas for this useful addition.

I didn't find a doc update. Did I miss it or are you welcoming one ?

@OskarStark
Copy link
Contributor

We have one here

It not merged yet

@ywcdiao
Copy link

ywcdiao commented Aug 4, 2024

Hi @fabpot , @nicolas-grekas

Will this new feature be added to the Symfony 5.4 and 6.4 ?

@xabbuh
Copy link
Member

xabbuh commented Aug 4, 2024

No, new features are only added to the branch that is currently in development. Old feature versions do only receive bugfixes and security patches.

fabpot added a commit that referenced this pull request Mar 24, 2025
…ameter (eltharin)

This PR was squashed before being merged into the 7.3 branch.

Discussion
----------

[Routing] Add alias in `{foo:bar}` syntax in route parameter

| Q             | A
| ------------- | ---
| Branch?       | 7.3
| Bug fix?      | no
| New feature?  | yes
| Deprecations? | no
| License       | MIT

Since #54720 we can/have to write route parameters with "destination" as slug:bar,

but if we have two properties with same name example :

`/search-book/{name:author}/{name:category}`

we get the error message : Route pattern "/search-book/{name}/{name}" cannot reference variable name "name" more than once.

Actually to prevent this error we have to use MapEntity as :

```php
    public function bookSearch(
        #[MapEntity(mapping: ['authorName' => 'name'])]
        Author $author,
        #[MapEntity(mapping: ['categoryName' => 'name'])]
        Category $category): Response
    {
```

and we have to remove Mapped Route Parameters :

`#[Route('/search-book/{authorName}/{categoryName}')`

This PR proposal is to remove MapEntity attributes and keep Mapped Route Parameters by adding an alias on it :

`/search-book/{authorName:author.name}/{categoryName:category.name}`

With that, EntityValueResolver will search name in author Entity and name in Category Entity.

We can have url with : `{{ path('bookSearch', {authorName: 'KING', categoryName: 'Horror'}) }}`

Commits
-------

4e2c638 [Routing] Add alias in `{foo:bar}` syntax in route parameter
symfony-splitter pushed a commit to symfony/routing that referenced this pull request Mar 24, 2025
…ameter (eltharin)

This PR was squashed before being merged into the 7.3 branch.

Discussion
----------

[Routing] Add alias in `{foo:bar}` syntax in route parameter

| Q             | A
| ------------- | ---
| Branch?       | 7.3
| Bug fix?      | no
| New feature?  | yes
| Deprecations? | no
| License       | MIT

Since symfony/symfony#54720 we can/have to write route parameters with "destination" as slug:bar,

but if we have two properties with same name example :

`/search-book/{name:author}/{name:category}`

we get the error message : Route pattern "/search-book/{name}/{name}" cannot reference variable name "name" more than once.

Actually to prevent this error we have to use MapEntity as :

```php
    public function bookSearch(
        #[MapEntity(mapping: ['authorName' => 'name'])]
        Author $author,
        #[MapEntity(mapping: ['categoryName' => 'name'])]
        Category $category): Response
    {
```

and we have to remove Mapped Route Parameters :

`#[Route('/search-book/{authorName}/{categoryName}')`

This PR proposal is to remove MapEntity attributes and keep Mapped Route Parameters by adding an alias on it :

`/search-book/{authorName:author.name}/{categoryName:category.name}`

With that, EntityValueResolver will search name in author Entity and name in Category Entity.

We can have url with : `{{ path('bookSearch', {authorName: 'KING', categoryName: 'Horror'}) }}`

Commits
-------

4e2c6386912 [Routing] Add alias in `{foo:bar}` syntax in route parameter
symfony-splitter pushed a commit to symfony/http-kernel that referenced this pull request Mar 24, 2025
…ameter (eltharin)

This PR was squashed before being merged into the 7.3 branch.

Discussion
----------

[Routing] Add alias in `{foo:bar}` syntax in route parameter

| Q             | A
| ------------- | ---
| Branch?       | 7.3
| Bug fix?      | no
| New feature?  | yes
| Deprecations? | no
| License       | MIT

Since symfony/symfony#54720 we can/have to write route parameters with "destination" as slug:bar,

but if we have two properties with same name example :

`/search-book/{name:author}/{name:category}`

we get the error message : Route pattern "/search-book/{name}/{name}" cannot reference variable name "name" more than once.

Actually to prevent this error we have to use MapEntity as :

```php
    public function bookSearch(
        #[MapEntity(mapping: ['authorName' => 'name'])]
        Author $author,
        #[MapEntity(mapping: ['categoryName' => 'name'])]
        Category $category): Response
    {
```

and we have to remove Mapped Route Parameters :

`#[Route('/search-book/{authorName}/{categoryName}')`

This PR proposal is to remove MapEntity attributes and keep Mapped Route Parameters by adding an alias on it :

`/search-book/{authorName:author.name}/{categoryName:category.name}`

With that, EntityValueResolver will search name in author Entity and name in Category Entity.

We can have url with : `{{ path('bookSearch', {authorName: 'KING', categoryName: 'Horror'}) }}`

Commits
-------

4e2c6386912 [Routing] Add alias in `{foo:bar}` syntax in route parameter
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants