EasyAdminBundle icon indicating copy to clipboard operation
EasyAdminBundle copied to clipboard

Pretty url route conflict when using symfony bundles with EA

Open nevez opened this issue 7 months ago • 1 comments

I have an invoice and accounting bundle included in my EA app. The bundle itself is an EA app, so the main app extends and reuses some of its crud controllers/entities/etc. The main dashboard is configured with

#[AdminDashboard(routePath: '/admin', routeName: 'admin']

and the bundle dashboard is configured with

#[AdminDashboard(routePath:'/zbadmin', routeName:'zbadmin')]

so all route names and paths are different between the two.

In the main app, our "Azienda" (company) entity extends the Azienda entity of the bundle using SINGLE_TABLE doctrine mapping inheritance. Similarly, our AziendaCrudController extends the AziendaCrudController of the bundle.

The problem with this set-up is that EA AdminRouteGenerator detects the 2 dashboards (the main one and the bundle one), and for each of them tries to generate a route for both the Controllers defined in the main app and the bundle, giving this error:

When using pretty URLs, all CRUD controllers must have unique PHP class names to generate unique route names. However, your application has at least two controllers with the FQCN "Allyou\ZiobillBundle\Controller\Admin\AziendaCrudController", generating the route "a
dmin_azienda_index". Even if both CRUD controllers are in different namespaces, they cannot have the same class name. Rename one of these controllers to resolve the issue.

So the first thing I tried was renaming the main app "AziendaCrudController" to "AppAziendaCrudController" as suggested, and I get these routes defined:

$ php bin/console debug:router | grep 'azienda/'
  admin_app_azienda_new                                   GET|POST         ANY      ANY    /admin/app-azienda/new                                     
  admin_app_azienda_batch_delete                          POST             ANY      ANY    /admin/app-azienda/batch-delete                            
  admin_app_azienda_autocomplete                          GET              ANY      ANY    /admin/app-azienda/autocomplete                            
  admin_app_azienda_render_filters                        GET              ANY      ANY    /admin/app-azienda/render-filters                          
  admin_app_azienda_edit                                  GET|POST|PATCH   ANY      ANY    /admin/app-azienda/{entityId}/edit                         
  admin_app_azienda_delete                                POST             ANY      ANY    /admin/app-azienda/{entityId}/delete                       
  admin_app_azienda_detail                                GET              ANY      ANY    /admin/app-azienda/{entityId}                              
  admin_azienda_new                                       GET|POST         ANY      ANY    /admin/azienda/new                                         
  admin_azienda_batch_delete                              POST             ANY      ANY    /admin/azienda/batch-delete                                
  admin_azienda_autocomplete                              GET              ANY      ANY    /admin/azienda/autocomplete                                
  admin_azienda_render_filters                            GET              ANY      ANY    /admin/azienda/render-filters                              
  admin_azienda_edit                                      GET|POST|PATCH   ANY      ANY    /admin/azienda/{entityId}/edit                             
  admin_azienda_delete                                    POST             ANY      ANY    /admin/azienda/{entityId}/delete                           
  admin_azienda_detail                                    GET              ANY      ANY    /admin/azienda/{entityId}                                  
  zbadmin_app_azienda_new                                 GET|POST         ANY      ANY    /zbadmin/app-azienda/new                                   
  zbadmin_app_azienda_batch_delete                        POST             ANY      ANY    /zbadmin/app-azienda/batch-delete                          
  zbadmin_app_azienda_autocomplete                        GET              ANY      ANY    /zbadmin/app-azienda/autocomplete                          
  zbadmin_app_azienda_render_filters                      GET              ANY      ANY    /zbadmin/app-azienda/render-filters                        
  zbadmin_app_azienda_edit                                GET|POST|PATCH   ANY      ANY    /zbadmin/app-azienda/{entityId}/edit                       
  zbadmin_app_azienda_delete                              POST             ANY      ANY    /zbadmin/app-azienda/{entityId}/delete                     
  zbadmin_app_azienda_detail                              GET              ANY      ANY    /zbadmin/app-azienda/{entityId}                            
  zbadmin_azienda_new                                     GET|POST         ANY      ANY    /zbadmin/azienda/new                                       
  zbadmin_azienda_batch_delete                            POST             ANY      ANY    /zbadmin/azienda/batch-delete                              
  zbadmin_azienda_autocomplete                            GET              ANY      ANY    /zbadmin/azienda/autocomplete                              
  zbadmin_azienda_render_filters                          GET              ANY      ANY    /zbadmin/azienda/render-filters                            
  zbadmin_azienda_edit                                    GET|POST|PATCH   ANY      ANY    /zbadmin/azienda/{entityId}/edit                           
  zbadmin_azienda_delete                                  POST             ANY      ANY    /zbadmin/azienda/{entityId}/delete                         
  zbadmin_azienda_detail                                  GET              ANY      ANY    /zbadmin/azienda/{entityId}

Each route is doubled, both the main app and the bundle app ones, with "/azienda" and "/app-azienda", so I end up with 4 routes instead of two. I don't like this, and I don't like having a different route name "app-azienda".

So after reading this doc page about restricting crudcontroller access with "allowedControllers" and "deniedControllers", I reverted the crud controller name change and set this on the main app DashboardController:

#[AdminDashboard(routePath: '/admin', routeName: 'admin', deniedControllers: [
    AziendaCrudController::class,
])]

where "AziendaCrudController" is the bundle's one (in its namespace).

The problem is that I still get the same "CRUD controllers must have unique PHP class names" error, because the bundle's DashboardController has no restriction defined. Being an included bundle, I cannot set a "deniedControllers" parameter there, only "allowedControllers"... being obliged to list all of the bundle's controllers there (remembering to add a line there each time we add a new one) just to solve this issue doesn't seem very elegant.

This is what I'm trying to achieve (made it up):

$ php bin/console debug:router | grep 'azienda/'                            
  admin_azienda_new                                       GET|POST         ANY      ANY    /admin/azienda/new                                         
  admin_azienda_batch_delete                              POST             ANY      ANY    /admin/azienda/batch-delete                                
  admin_azienda_autocomplete                              GET              ANY      ANY    /admin/azienda/autocomplete                                
  admin_azienda_render_filters                            GET              ANY      ANY    /admin/azienda/render-filters                              
  admin_azienda_edit                                      GET|POST|PATCH   ANY      ANY    /admin/azienda/{entityId}/edit                             
  admin_azienda_delete                                    POST             ANY      ANY    /admin/azienda/{entityId}/delete                           
  admin_azienda_detail                                    GET              ANY      ANY    /admin/azienda/{entityId}                                                           
  zbadmin_azienda_new                                     GET|POST         ANY      ANY    /zbadmin/azienda/new                                       
  zbadmin_azienda_batch_delete                            POST             ANY      ANY    /zbadmin/azienda/batch-delete                              
  zbadmin_azienda_autocomplete                            GET              ANY      ANY    /zbadmin/azienda/autocomplete                              
  zbadmin_azienda_render_filters                          GET              ANY      ANY    /zbadmin/azienda/render-filters                            
  zbadmin_azienda_edit                                    GET|POST|PATCH   ANY      ANY    /zbadmin/azienda/{entityId}/edit                           
  zbadmin_azienda_delete                                  POST             ANY      ANY    /zbadmin/azienda/{entityId}/delete                         
  zbadmin_azienda_detail                                  GET              ANY      ANY    /zbadmin/azienda/{entityId}

i.e. each controller route defined only in it's dashboard. It looks like a reasonable thing to do, but I can't figure out how to do it in a simple way, possibly without modifying the bundle code.

Is there a best practice when working with bundles? Am I missing something?

nevez avatar Mar 29 '25 12:03 nevez

I stumble on the same issue even though i have only one AdminDashboard , but several AdminAction declared

allan-simon avatar Apr 03 '25 12:04 allan-simon