Problem/Motivation
Drupal entities typically provide their routes through a route_provider handler. These route_provider classes provider boilerplate routing, so these can be removed from .routing.yml files
Steps to reproduce
See for example https://git.drupalcode.org/project/domain/-/blob/4.x/domain/domain.routi... and https://git.drupalcode.org/project/drupal/-/blob/main/core/lib/Drupal/Co...
Proposed resolution
Provide entity routes through EntityRouteProviderInterface
Remaining tasks
- Write a merge request
- Review
- Commit
User interface changes
The edit and delete pages are titled Edit %label and Delete %label, because their titles now come from EntityController::editTitle() and deleteTitle() instead of the static ones the routing files carried. Tab titles are unchanged, since those come from the local task definitions. The domain alias edit and delete routes gain _admin_route, which domain's already had, so those two pages use the admin theme and load the parent domain without configuration overrides.
API changes
This is a backwards-compatibility break. Two of the three items below fail silently, so they are worth a change record and a release note.
DomainAliasController::addAlias()is REMOVED. The controller class survives withlisting()andlistingTitle(). Its prepopulation of the parent domain moves toDomainAliasForm::getEntityFromRouteMatch(), which is the seam core calls. Anything calling that method, or pointing a route of its own at it, breaks outright.- The add form's form ID changes from
domain_edit_formtodomain_form. The entity type declares noaddform handler, so the generated add route runs thedefaultoperation where the old route nameddomain.editexplicitly. An implementation ofhook_form_domain_edit_form_alter()written to catch the add form silently stops firing on it. An alter written againsthook_form_domain_form_alter()is unaffected, because that is the base form ID hook and it already fires for both operations. The domain alias add form keeps the IDdomain_alias_formit already had, since the removed controller also ran thedefaultoperation. - Five form routes move out of the routing files and are generated from the link templates:
entity.domain.add_form,entity.domain.edit_form,entity.domain.delete_form,entity.domain_alias.edit_formandentity.domain_alias.delete_form. The names core derives match the names those routes already had, and the two historical names survive as aliases,entity.domain.addofentity.domain.add_formanddomain_alias.addofentity.domain_alias.add_form, soUrl::fromRoute()keeps working for both. Both entity types now declare aroute_providerhandler, anddomain_aliasdeclares aDomainAliasHtmlRouteProviderthat keeps the add route's own access requirements rather than core's_entity_create_access.
No contributed project that integrates with Domain was found to reference DomainAliasController::addAlias(), to alter domain_edit_form, or to name entity.domain.add or domain_alias.add, so the exposed cases are custom code and any project not checked here.
Data model changes
None
AI-Generated: Yes (Claude Code was used to help draft this issue summary and to write the code and tests on the merge request. I reviewed and ran the work myself before posting it.)
Issue fork domain-3615915
Show commands
Start within a Git clone of the project using the version control instructions.
Or, if you do not have SSH keys set up on git.drupalcode.org:
Comments
Comment #4
mably commentedComment #5
mably commentedComment #6
idebr commenteddomain_alias.addand be done here or in a follow-up issueentity.[entity_type].*version, and deprecate aliases. See for reference https://www.drupal.org/node/3317784. This is actionable for thedomain.adminanddomain_alias.adminand be done here or in a follow-up issueComment #7
mably commentedBoth points are addressed, the first one here and the second one in a follow-up.
1. The
add-formlink template is now declared on the domain alias entity type, sodomain_alias.addleaves the routing file and the route comes from the route provider asentity.domain_alias.add_form, with the old name kept as an alias.DomainAliasController::addAlias()is deleted: the parent domain record now reaches the form throughDomainAliasForm::getEntityFromRouteMatch().Two things the generated route cannot express, so the alias entity type gets a small
DomainAliasHtmlRouteProviderthat overridesgetAddFormRoute():DefaultHtmlRouteProvider::getAddFormRoute()sets_entity_create_access: domain_alias, which reachesDomainAliasAccessControlHandler::checkCreateAccess(). That method is inherited from the domain record handler and testsadminister domainsandcreate domains, so it would grant and deny the wrong people. The route keeps_entity_access: domain.updateand_permission: create domain aliases, which is what it required before.{domain}parameter any more.EntityResolverManageronly adds a parameter for the entity type the form itself builds, and the old route was upcast solely because the deleted controller type hintedDomainInterface $domain. The provider now sets that parameter conversion explicitly.The page title is unchanged:
EntityController::addTitle()renders "Add domain alias" from the entity type label. The route gains_admin_route, like the edit and delete routes already in this issue. New kernel coverage asserts the route, the alias, and that the form takes the parent domain record from the path; the functional test now asserts the saved alias still belongs to the domain record it was added from.2. The route naming is filed as #3616784: Use entity.domain.collection as the primary name of the domain listing route rather than done here, because deprecating
domain.adminis more than a rename. An alias is resolved by name and is never matched against a path, and nothing in core resolves an alias for a consumer keyed on a route name: local tasks (base_route), local actions (appears_on), the menu active trail andhook_help()all compare the matched route name as a plain string, andgetRouteAliases()has no caller in core. Six contributed projects declarebase_route: domain.adminfor their tabs on the Domains page, so the rename needs a compatibility layer that rewrites the deprecated names for the length of the deprecation. The follow-up has the details.The branch is also rebased on the current 4.x.
AI-Generated: Yes (Claude Code was used to help draft this comment and to write the code and the tests on the merge request. The new tests were confirmed to fail against the previous code and to pass with the change.)
Comment #8
mably commented