EasyCorp / EasyCorp/EasyAdminBundle
Parameter-Specific State Providers for Hierarchical CRUDs
Nobody has claimed this yet.
- Dominant language
- PHP
- Stars
- 4.3k
- Forks
- 1.1k
- Avg merge
- 8d 2h
- Merged PRs (30d)
- 11
Description
1. The Core Problem: Mandatory Parameter Persistence
EasyAdmin's AdminUrlGenerator is hardcoded to prioritize entityId. When a developer defines a hierarchical route like this:
#[AdminRoute(path: '/{parentId}/sub-resource/{entityId}')]
class MyCrudController extends AbstractCrudController
{
...
}
the following occurs:
- The Generator Error: When rendering links on the
indexordetailpages, the generator sees{parentId}in the route but has no source to fetch it from. - The Twig Crash: This results in a
MissingMandatoryParametersExceptionduring the rendering of standard action buttons (Edit, Delete, etc.). - The Lifecycle Gap: Even if the URL is manually hacked together, the "Parent" context is lost when moving between
index,new, andeditactions.
2. Proposed Solution: StateProviderInterface
I propose a single, focused interface. Its job is to resolve a specific value for a given parameter name based on the current context (the Request or the specific Entity being rendered in a row).
interface StateProviderInterface
{
/**
* @param string $paramName The placeholder name (e.g., 'parentId')
* @param AdminContext $context The current admin request context
* @return mixed The value to be injected into the route (int, string, or object e.g Uuid::v4())
*/
public function resolve(string $paramName, AdminContext $context): mixed;
}
3. Registration via #[AdminRoute]
The provider is linked directly to the controller via the existing AdminRoute attribute. This creates a clear contract: "If you use this route, use this provider to fill its placeholders (with the exception of entityId)."
#[AdminRoute(
path: '/admin/{parentId}/category/{entityId}',
provider: CategoryStateProvider::class
)]
class CategoryCrudController extends AbstractCrudController
{
// ...
}
Usage Example
class CategoryStateProvider implements StateProviderInterface
{
public function resolve(string $paramName, AdminContext $context): mixed
{
if ($paramName === 'parentId') {
return $context->getEntity()->getInstance()->getParent()->getId();
}
return null; // This should fallback to the default exception for mandatory parameter
}
}
4. How this Resolves the "Top-Level" Logic
A. Bulletproof URL Generation
When the ActionFactory generates a link for an EDIT action:
- It identifies that the route requires
{parentId}. - It calls the
StateProvider::resolve('parentId', $context). - The provider returns a value to fill the parentId (e.g.,
$entityDto->getInstance()->getParent()->getId()). - The URL survives: The generator now has all required data to build a valid Symfony route.
B. Implicit Parent Association
Because the AdminContext now tracks the resolved parentId, standard CRUD methods become aware of the hierarchy:
createEntity(): Can automatically pullparentIdfrom the context to assign the owner.createIndexQueryBuilder(): Can automatically filter the list so users only see children of the currentparentId.
5. Why this "Top-Level" Fix?
Instead of forcing developers to override every single action to manually inject a parentId, this solution fixes the Data Source for the AdminUrlGenerator.
By providing a single entity/value for a given parameter name, we allow EasyAdmin to handle Nested Resources and Multi-tenancy out of the box. It transforms EasyAdmin from a flat-file manager into a true hierarchical CMS.
Comparison: Current vs. Proposed
| Feature | Current State | With StateProvider |
|---|---|---|
| Route Requirement | Only entityId is auto-filled. |
parentId (or any name) is auto-filled. |
| Implementation | Overriding 4-5 core methods. | One Interface + Attribute. |
| Reliability | Twig crashes on custom routes. | Twig renders valid links dynamically. |
| Logic Location | Scattered throughout Controller. | Centralized in the Provider. |
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start by tracing AdminUrlGenerator and ActionFactory for how mandatory route parameters, especially entityId, are resolved, then inspect AdminRoute and AdminContext integration. Compare the behavior of index, detail, new, and edit links for hierarchical routes. Done means a provider can supply non-entity parameters, missing values retain the existing exception behavior, and standard CRUD links preserve the parent context.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- php, symfony
- Domain
- backend
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 42/100