symfony-entity-route-mappinglisted
Install: claude install-skill ubermuda/loupe
# Entity and route mapping (Symfony EntityValueResolver)
## `{param:variable}` declares the mapping in the path
Declare the mapping in the route path with `{param:variable}`. `variable` is the
controller method parameter name. Type-hint that parameter as the entity class.
`EntityValueResolver` then resolves it and returns 404 when no entity matches.
When the route parameter name matches the entity field name, you need no
`#[MapEntity]` attribute:
```php
// Route param "slug" matches Organization::$slug — auto-resolved
#[Route('/{slug:org}', requirements: ['slug' => '[a-z0-9][a-z0-9_\-]{2,29}'])]
public function __invoke(Organization $org): Response
```
The snippets here put `#[Route]` next to `__invoke()` for brevity. In a real
controller it goes on the **class**. Gamache's `ControllerRouteAttributeRule`
fails a controller whose only `#[Route]` is method-level.
When the names differ, add `#[MapEntity]` to declare the field mapping. When the
parameter resolves to the entity's `id`, prefer the colon-alias form
`{id:workspace}`, which auto-resolves with no `mapping:` bridge.
```php
#[Route('/workspace/{workspaceId}/status')]
public function __invoke(
#[MapEntity(mapping: ['workspaceId' => 'id'])] Workspace $workspace,
): JsonResponse
```
Never inject a repository into a controller only to do a slug lookup. Entity
mapping exists for that.
## Pitfall 1: `{param:alias}` renames the request attribute
`{projectSlug:project}` stores the URL value under the alias `project