Issue #3588091: Add domain_config_entity_ui submodule — per-domain support for config-entity admin pages

See #3588091.

What this adds

A new experimental submodule domain_config_entity_ui that brings per-domain override support to EntityForm-based config-entity admin flows (block, view modes, search pages, views, …). Pairs with domain_config_ui (which covers the ConfigFormBase side).

How it works

Five coordinated pieces:

  • DomainAwareConfigEntityStorageTrait overrides doLoadMultiple() to fold the active domain's override on top of the override-free read path. Regular loads flow through unchanged: the trait short-circuits when $this->overrideFree is FALSE.
  • DomainAwareConfigEntityStorageInterface is an empty marker. The form_alter and ParamConverter gate on instanceof — capability discovery is runtime introspection.
  • DomainAwareConfigEntityStorage is a thin shell that uses the trait, implements the interface, and extends core's ConfigEntityStorage. DomainAwareSwapRegistry::computeSwaps() auto-discovers every config entity type whose default storage_class is ConfigEntityStorage and registers a swap to this class.
  • DomainConfigEntityUiFormHooks::formAlter() exposes the parent module's "Enable domain configuration" toggle on EntityForm-based config-entity edit pages, gated on the marker interface.
  • DomainOverrideConfigEntityConverter runs at higher priority than core's AdminPathConfigEntityConverter. Same capability gate; loads override-merged for registered configs.

Two-stage opt-in

  1. Installing the submodulelifecycle: experimental + Drupal's install confirmation prompt.
  2. Per-entity-type checkboxes on /admin/config/domain/config-entity-ui. Default install: empty. Settings subscriber clears entity-type definitions on save so the swap takes effect on the next request without drush cr. Form opens with a yellow warning that only block has been validated end-to-end.

Extensibility

hook_domain_config_entity_ui_swaps_alter() (documented in domain_config_entity_ui.api.php) lets contrib modules register their own DomainAware*Storage subclass for entity types whose default storage_class is a custom subclass (image_styleImageStyleStorage, user_roleRoleStorage, …). Modules can also REMOVE auto-discovered entries to opt a vanilla-storage type out.

Tests

Kernel (3 files, 11 tests / 49 assertions):

  • DomainAwareConfigEntityStorageTest — storage swap, override-merged read, BlockListBuilder save flow regression, mid-request override re-read, non-curated entity type unchanged, disable un-checks.
  • DomainOverrideConfigEntityConverterTest — converter capability gate.
  • DomainAwareSwapRegistryAlterTest — alter-registered entries surface, coexist with auto-discovery, strict-equality guard.

Functional (DomainConfigEntityUiToggleTest):

  • Toggle present on Configure block; absent on Place block; absent on uncovered user_role.
  • SettingsForm flips coverage on the next request (empty → check block → toggle appears).
  • Save round-trip: toggle → register → edit label → save → per-domain override holds the new value, base untouched, form re-renders override-merged. Skipped on environments where the parent diff bridge is missing (property_exists($baseData) probe).

Module metadata

  • name: Domain Configuration Entity UI
  • package: Domain
  • lifecycle: experimental, lifecycle_link points at this issue
  • core_version_requirement: ^10.3 || ^11 (uses \Drupal\Core\Form\ConfigTarget from 10.3)
  • configure: domain_config_entity_ui.settings_form (Configure link on Modules page)
  • menu link: under Configuration > Domain > Domain config entity types
  • permission: administer domain config entity ui
  • dependencies: domain:domain_config_ui
  • domain #3587744 — parent (write-side correctness in domain_config); merged.
  • #3588057 / #3588108 — parallel "menu plugin manager cache leaks across domains" pair.
Edited by Frank Mably

Merge request reports

Loading