Problem/Motivation
Url objects can now specify the domain as an option, see #3574800: Allow Url objects to specify the Domain as an option
However, the domain path alias is only applied when the URL is generated on the active domain
Steps to reproduce
- Create a node that is published on Domain One, but not Domain Two
- Assign a domain path alias to the node for Domain One
- Generate a URL for the node on Domain Two
- Notice the domain path alias is not applied
Proposed resolution
Apply domain path alias processing on outbound URLs with a domain option
Remaining tasks
- Write a merge request
- Review
- Commit
User interface changes
The domain path alias is applied to URLs with a Domain option
API changes
To be determined
Data model changes
To be determined
Issue fork domain_path-3575163
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 commentedProblem
When code sets
$url->setOption('domain', 'example_com')directly (without going throughDomainSourcePathProcessor), domain path aliases are not applied. Core'sPathProcessorAlias(priority 300) aliases the path for the active domain, and nobody re-aliases it for the target domain.This is because
domain_pathcurrently resolves aliases only viahook_domain_source_alter, which is fired byDomainSourcePathProcessor(priority 90) — but that processor skips processing when$options['domain']is already set.Solution
New outbound path processor
DomainPathOutboundProcessorat priority 85 (afterDomainSourcePathProcessorat 90, beforeDomainPathProcessorat 80):$options['domain']getAliasByPathAndDomain()The processor is safe for double-processing: when
hook_domain_source_alterhas already replaced the path (domain_source flow), the reverse-resolve typically fails (returns the path unchanged), and the target-domain lookup also returns the same path. Net result: path stays unchanged.Priority chain
PathProcessorAliasDomainSourcePathProcessorhook_domain_source_alterDomainPathOutboundProcessorDomainPathProcessorChanges
src/HttpKernel/DomainPathOutboundProcessor.phpdomain_path.services.yml— registered the new service at priority 85tests/src/Functional/DomainPathDomainOptionTest.php— 3 test methods covering alias resolution, fallback without alias, and non-canonical route exclusionDepends on
#3574800 (domain module:
DomainPathProcessorwith thedomainURL option)Comment #5
idebr commentedPerhaps the following priority chain is preferable?
310 DomainSourcePathProcessor -> sets
$options['domain']if not set before305 DomainPathOutboundProcessor
-> calls
DomainPathAliasManager::getPathByAliasAndDomain()only if$options['domain']is set-> sets
$options['alias'] = TRUEto prevent duplicate processing by PathProcessorAlias since it includes a fallback to the core path alias: https://git.drupalcode.org/project/drupal/-/blob/main/core/modules/path_...hook_domain_source_alteris no longer neededComment #6
idebr commentedDomainPathOutboundProcessor::resolveDomain()is a good example of how allowing both strings and Domain objects in a variable leads to messy code :)Comment #7
mably commentedCurrent architecture (this MR)
AliasPathProcessorDomainPathAliasManager)DomainSourcePathProcessorhook_domain_source_alter, setsoptions['domain']DomainPathOutboundProcessorDomainPathProcessorbase_urlto target domainThe problem: core's
AliasPathProcessor(priority 300) runs first and aliases the path for the active domain. Then our processor at 85 has to undo that (reverse-resolve withgetPathByAlias) and redo it for the target domain. This reverse-then-forward dance works but is wasteful.@idebr proposed architecture
DomainSourcePathProcessoroptions['domain']DomainPathOutboundProcessoroptions['domain']is set, aliases path for target domain, setsoptions['alias'] = TRUEAliasPathProcessor$options['alias']— if TRUE, skips. Otherwise aliases normallyDomainPathProcessorbase_urlto target domainKey insight: by running before core's
AliasPathProcessor(priority 305 > 300), you alias the path for the target domain first. Then you set$options['alias'] = TRUE, which is core's built-in mechanism to tellAliasPathProcessor"aliasing is already done, skip it" (AliasPathProcessor.php line 45). No reverse-resolve needed.Also:
hook_domain_source_alterwould no longer be needed becauseDomainPathOutboundProcessorhandles the aliasing directly —DomainPathFormHooks::domainSourceAlter()was only used to swap the alias for the target domain, which this processor now does.Trade-offs
This approach is cleaner because:
$options['alias']skip mechanismhook_domain_source_alterimplementationConsiderations:
DomainSourcePathProcessormoving from 90 to 310 is a bigger change in the domain module — it needs to work correctly running before core aliasing instead of afterhook_domain_source_alterto modify the alias would breakDomainSourcePathProcessorat 310 would be the internal path (e.g./node/1) rather than an alias, which might actually be simplerI'll rework the implementation to follow this approach — seems like a solid improvement.
Comment #8
mably commented@idebr could you validate this issue please? https://www.drupal.org/project/domain/issues/3575227
Comment #9
idebr commentedI suggest naming the service DomainPathAliasProcessor: the core service is somewhat misnamed missing the 'Alias' part, and Outbound is an implementation detail that easily becomes outdated if the implementation changes
Comment #10
mably commentedService renamed.
Comment #11
mably commentedLooks Domain Path 2.x will now require Domain 3.x.
Don't know what to think about that.
Comment #12
idebr commented#11 An option is to tag 2.0.0 first to allow projects to update, and merge this issue in 2.1.x that requires drupal/domain:^3.0?
Core path alias processing can be skipped entirely if the
$option['domain']is set, since getPathByAliasAndDomain includes a fallback to Core path alias processing, see https://git.drupalcode.org/project/domain_path/-/blob/2.x/src/DomainPath...Comment #13
mably commentedI'll go directly to 3.x to match domain module versioning.
Implemented your suggestion that should definitely improve performance.
Comment #14
mably commentedShould be ready for merge.
Is it ok for you @idebr?
Comment #15
idebr commentedLooks good to me 👍
Comment #17
mably commentedComment #19
mably commentedLooks like our latest changes have introduced some regressions.
Investigating.
Comment #20
mably commented@idebr ok, found the culprit, $options['language'] is not populated anymore after moving DomainSourcePathProcessor at priority 310.
The domain_source field can be translated, so it's currently totally broken.
How could we fix that?
May be we can get the current language by ourselves if not provided in
$options['language'].What do you think?
Comment #21
idebr commentedI think this was fixed in a follow-up in Domain? #3575489: DomainSourcePathProcessor uses wrong translation when $options['language'] is not set (priority 310)