Two latent bugs in DomainAliasStorage's alias-pattern matching pipeline, surfaced while auditing MR !358 (issue #3583423). Both were originally bundled in that MR but they are unrelated to the resolver refactor and have been split out for review.
1. DomainAliasStorage::sort() never returns -1
The uasort comparator used by getPatterns() is broken:
public function sort($a, $b) { if ((substr_count($a, '*') > substr_count($b, '*')) || (strlen($a) < strlen($b))) { return 1; } return 0; }
A valid PHP comparator must be able to return any of -1, 0, or 1. This implementation only ever returns 0 or 1, so uasort sees "a == b" or "a > b" but never "a < b". Patterns that should have moved up never moved. The docblock claims the list ends up sorted by specificity, but it does not.
Replace with a spaceship-operator comparator:
public function sort($a, $b) { return substr_count($a, '*') <=> substr_count($b, '*') ?: strlen($b) <=> strlen($a); }
Behavior change: the pattern lists returned by getPatterns() (and any other caller of this comparator) now actually sort by specificity — fewer wildcards first, longer string as tiebreaker — which is what the original code claimed to do.
2. DomainAliasStorage::buildPortPatterns() emits patterns in the wrong priority order
The previous implementation interleaved per-pattern variants:
foreach ($patterns as $index => $pattern) { $new_patterns[] = $pattern . ':*'; // wildcard port if (default_port) $new_patterns[] = $pattern; // bare hostname if ($port) $new_patterns[] = $pattern . ':' . $port; // explicit }
For pattern list [p1, p2, p3] on a default port that produced [p1:*, p1, p2:*, p2, p3:*, p3]. loadByHostname() walks this list in order and returns the first DB hit, so p1:* shadowed p1 — even though a bare-hostname alias is more specific than a wildcard-port one. Practical effect: an alias defined as staging.example.com would lose to staging.example.com:* on the same hostname, despite the request having no explicit port.
Reorder so hostname-only patterns are emitted first (in pattern-list order), then port-bearing variants:
$is_default_port = is_null($port) || intval($port) === 80 || intval($port) === 443; $new_patterns = $is_default_port ? $patterns : []; foreach ($patterns as $pattern) { if (!is_null($port)) { $new_patterns[] = $pattern . ':' . $port; } $new_patterns[] = $pattern . ':*'; }
The new order on a default port becomes [p1, p2, p3, p1:port?, p1:*, p2:port?, p2:*, …], matching the documented intent: more specific aliases take precedence over wildcard-port ones.
MR
Branch ready locally with the two fixes as separate commits. Will push to the issue fork and open the MR once this issue has a number.
Notes
- The existing
DomainAliasSortTestonly checks pattern presence (array_diff), not order. Should follow up with an order-asserting test, but I'd like to land the fix first. - No deprecation needed: both functions are internals; the second one (
buildPortPatterns) is private.
Issue fork domain-3588155
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 #3
mably commentedComment #4
mably commentedTwo follow-up commits added per the pre-merge audit:
82c933e7— inline comment explaining why bare-hostname patterns are omitted on non-default ports (no behavior change).2389c39b—DomainAliasSortTestnow asserts the full ordered output ofgetPatterns()instead of just pattern presence. The previous fixture had an order that did not match the actual implementation, plus a duplicate entry and a missing pattern; both bugs were masked byarray_diff(). The new fixtures use explicit-port hostnames so the assertion is deterministic regardless of the test runner.Release notes
Behavior change worth surfacing in the Domain 3.1.0 release notes:
MR description on git.drupalcode.org has the full list of commits and a Release notes section ready to copy into the project release notes when 3.1.0 ships.
Tested locally (Drupal 11.x + MySQL):
testAliasSortpasses with the new fixtures.Comment #6
mably commented