Skip to content
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

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

Merged
merged 1 commit into from
May 2, 2024

Conversation

nicolas-grekas
Copy link
Member

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

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.

@nicolas-grekas
Copy link
Member Author

I just confirmed on a real app that this solves all ambiguities while providing nice DX.

@nicolas-grekas nicolas-grekas added Ready ❄️ Feature Freeze Important Pull Requests to finish before the next Symfony "feature freeze" labels Apr 4, 2024
@nicolas-grekas nicolas-grekas force-pushed the entity-vr branch 2 times, most recently from 068c12f to b8d9631 Compare April 4, 2024 12:58
@chalasr
Copy link
Member

chalasr commented Apr 6, 2024

rebase needed and 👍

@bobvandevijver

This comment was marked as outdated.

@nicolas-grekas

This comment was marked as outdated.

@bobvandevijver

This comment was marked as outdated.

@nicolas-grekas

This comment was marked as outdated.

@nicolas-grekas

This comment was marked as outdated.

@bobvandevijver

This comment was marked as outdated.

@nicolas-grekas

This comment was marked as outdated.

@bobvandevijver

This comment was marked as outdated.

@nicolas-grekas

This comment was marked as outdated.

@bobvandevijver

This comment was marked as outdated.

@nicolas-grekas

This comment was marked as outdated.

@bobvandevijver

This comment was marked as outdated.

Copy link
Contributor

@bobvandevijver bobvandevijver left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@nicolas-grekas I absolutely love the solution you've come up with, this is awesome! 😃

I tested this by backporting the changes to a 6.4 project, everything seems to be working great there, and the old, now deprecated, automapping is still disabled as expected.

src/Symfony/Bridge/Doctrine/Attribute/MapEntity.php Outdated Show resolved Hide resolved
@nicolas-grekas nicolas-grekas modified the milestones: 7.2, 7.1 May 2, 2024
fabpot added a commit that referenced this pull request May 2, 2024
…etween a route parameter and its corresponding request attribute (nicolas-grekas)

This PR was merged into the 7.1 branch.

Discussion
----------

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

| 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:
```php
#[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:
```php
#[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.

Commits
-------

1e091b9 [Routing] Add `{foo:bar}` syntax to define a mapping between a route parameter and its corresponding request attribute
@fabpot
Copy link
Member

fabpot commented May 2, 2024

Thank you @nicolas-grekas.

@fabpot fabpot merged commit b2e6e49 into symfony:7.1 May 2, 2024
3 of 10 checks passed
@nicolas-grekas nicolas-grekas deleted the entity-vr branch May 21, 2024 08:12
@kevinpapst
Copy link

In https://symfony.com/blog/new-in-symfony-7-1-mapped-route-parameters it says

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.

I counter that argument. Deprecating a feature that works since years is not a great DX. This one feels different than other deprecations, as it requires so many route to be manually adjusted. I understand it if there are multiple Entities and parameters, but if only one {id} is set and only one Entity is used, isn't it obvious which one is meant?

@stof
Copy link
Member

stof commented May 22, 2024

the usage of {id} to find by primary key was not part of the auto-mapping feature. @nicolas-grekas I think this should deserve a separate deprecation message (and probably a separate changelog entry)

@kevinpapst
Copy link

My feedback is purely based on this example in the Blog entry:

Bildschirmfoto 2024-05-22 um 12 43 56

Do I misunderstand something? Is it deprecated or not?

Considering the note:

Given that this new feature provides a nice DX

I honestly don't see how this change is a win from DX side. Looks more like unnecessary repetition to me.
I really fear having to adjust and test hundreds of routes across several projects.

@nicolas-grekas
Copy link
Member Author

The {id:document} mapping in the last example in the blog post is not needed indeed.
What matters is having explicit mapping and using {document} should be the way to go.
/cc @javiereguiluz FYI

@kevinpapst
Copy link

@nicolas-grekas thanks for the update. I agree that {document} is better to understand and should be used. But in the past {id} was documented and is likely used in tenth of thousands of routes out there.
So my question and hope remains: {id} keeps on working without a deprecation?

@kevinpapst
Copy link

Follow up at #57211

@javiereguiluz
Copy link
Member

@nicolas-grekas @kevinpapst from the point of view of generating URLs in templates:

<a href="{{ path('document_show', {id: document.id}) }}"> ... </a>

This looks better than the following:

<a href="{{ path('document_show', {document: document.id}) }}"> ... </a>

A document is not the same as document ID. That's why I kept the {id} parameter in the route and mapped it to the controller's document argument.

But maybe I'm missing something here.

fabpot added a commit that referenced this pull request May 30, 2024
…ities (nicolas-grekas)

This PR was merged into the 7.1 branch.

Discussion
----------

[DoctrineBridge] Revert deprecating by-{id} mapping of entities

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

As discussed in #57211
Introduced in #54455

Commits
-------

b81a62c [DoctrineBridge] Revert deprecating by-{id} mapping of entities
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.

EntityValueResolver injecting entities when it shouldn't
9 participants