Problem

When a domain entity is loaded via $domain_storage->load() in a controller or service, it may return an entity from Drupal's static entity cache that was populated during early request negotiation — before alias resolution ran. The result: $domain->getHostname() returns the canonical (production) hostname instead of the aliased (local/staging) hostname.

This happens because hook_domain_load (implemented in DomainAliasHooks::domainLoad()) only fires when entities are loaded fresh from storage, not when they come from the static entity cache. During the request lifecycle:

  1. Domain negotiation loads all domains — they enter the static cache
  2. At this point, hook_domain_load fires but returns early because the active domain's alias property is not yet set
  3. The alias negotiation event subscriber runs and sets the alias on the active domain
  4. Later code calls $domain_storage->load('some_id') — the entity is returned from static cache, the hook does not fire, aliases are never applied

The existing test DomainAliasPrefixTest::testEnvironmentRewritePrefixedDomains() documents this issue with an explicit resetCache() call before reloading. But requiring every consumer to remember resetCache() is fragile and error-prone.

Additionally, path-prefixed domains that share a canonical hostname with another domain but have no alias of their own are never resolved when loaded from a different hostname context. The hook_domain_load tries loadByEnvironmentMatch() on the prefixed domain and finds no aliases.

Proposed fix

Replace hook_domain_load with alias resolution built into the storage layer:

  1. The domain_alias module swaps the domain entity storage via hook_entity_type_alter(), replacing DomainStorage with DomainAliasAwareDomainStorage
  2. The new storage overrides loadMultiple() to apply alias resolution after parent::loadMultiple() — for ALL returned entities (cached or fresh)
  3. Resolved entities are written back to the static cache so the resolution only happens once per entity per request
  4. A sibling fallback handles path-prefixed domains: when a domain has no aliases, aliases from domains sharing the same canonical hostname are checked
  5. hook_domain_load is removed from DomainAliasHooks

Issue fork domain-3583190

Command icon 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

mably created an issue. See original summary.

mably’s picture

Status: Active » Needs review

  • mably committed 30095c2e on 3583190-domainalias-cached-domain
    Issue #3583190: replace hook_domain_load with storage-level alias...

  • mably committed 125a3e1a on 3583190-domainalias-cached-domain
    Issue #3583190: replace hook_domain_load with storage-level alias...

  • mably committed d3fc82ea on 3.x
    fix: #3583190 domain_alias: cached domain entities bypass alias...
mably’s picture

Status: Needs review » Fixed

Now that this issue is closed, review the contribution record.

As a contributor, attribute any organization that helped you, or if you volunteered your own time.

Maintainers, credit people who helped resolve this issue.

mably changed the visibility of the branch 3583190-replace-http-host-by-canonical-name to hidden.

  • mably committed e7dcd962 on 3.x
    fix: #3583190 Rollback BC breaking changes from MR 353
    

  • mably committed 7f6503fa on 3.x
    fix: #3583190 Rename context methods setCanonicalHostname/...
mably’s picture

Status: Fixed » Closed (fixed)