From 6a7cd1e4b0a2087085e14442c18dab48df6dcd4a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Niedzielski?= Date: Tue, 4 Aug 2026 13:50:53 +0200 Subject: [PATCH 1/3] IBX-12192: Added SiteAccess::MATCHING_TYPE_UNINITIALIZED constant Replaces the 'uninitialized' magic string used for the placeholder SiteAccess wired into the container before request matching happens, so consumers (e.g. ibexa/messenger) can detect it without duplicating the literal. --- .../DependencyInjection/Configuration/ConfigResolver.php | 4 ++-- src/bundle/Core/Resources/config/services.yml | 3 +-- src/lib/MVC/Symfony/SiteAccess.php | 2 ++ src/lib/MVC/Symfony/SiteAccess/SiteAccessService.php | 9 +++------ tests/integration/Core/Resources/settings/common.yml | 2 +- 5 files changed, 9 insertions(+), 11 deletions(-) diff --git a/src/bundle/Core/DependencyInjection/Configuration/ConfigResolver.php b/src/bundle/Core/DependencyInjection/Configuration/ConfigResolver.php index 555dc1b7a8..264bbfc299 100644 --- a/src/bundle/Core/DependencyInjection/Configuration/ConfigResolver.php +++ b/src/bundle/Core/DependencyInjection/Configuration/ConfigResolver.php @@ -222,7 +222,7 @@ public function setDefaultScope(string $scope): void $this->defaultScope = $scope; // On scope change check if siteaccess has been updated so we can log warnings if there are any - if ($this->siteAccess->matchingType !== 'uninitialized') { + if ($this->siteAccess->matchingType !== SiteAccess::MATCHING_TYPE_UNINITIALIZED) { $this->warnAboutTooEarlyLoadedParams(); } } @@ -259,7 +259,7 @@ private function logTooEarlyLoadedListIfNeeded($paramName) return; } - if ($this->siteAccess->matchingType !== 'uninitialized') { + if ($this->siteAccess->matchingType !== SiteAccess::MATCHING_TYPE_UNINITIALIZED) { return; } diff --git a/src/bundle/Core/Resources/config/services.yml b/src/bundle/Core/Resources/config/services.yml index c0c93103cb..09fd9ac702 100644 --- a/src/bundle/Core/Resources/config/services.yml +++ b/src/bundle/Core/Resources/config/services.yml @@ -14,7 +14,7 @@ services: # Siteaccess is injected in the container at runtime Ibexa\Core\MVC\Symfony\SiteAccess: class: Ibexa\Core\MVC\Symfony\SiteAccess - arguments: ['%ibexa.site_access.default.name%', 'uninitialized'] + arguments: ['%ibexa.site_access.default.name%', !php/const Ibexa\Core\MVC\Symfony\SiteAccess::MATCHING_TYPE_UNINITIALIZED] Ibexa\Bundle\Core\DependencyInjection\Configuration\ConfigResolver\DefaultScopeConfigResolver: arguments: @@ -392,4 +392,3 @@ services: decoration_priority: 500 arguments: $inner: '@.inner' - diff --git a/src/lib/MVC/Symfony/SiteAccess.php b/src/lib/MVC/Symfony/SiteAccess.php index 9ed34bbe6c..71d1c4e1d2 100644 --- a/src/lib/MVC/Symfony/SiteAccess.php +++ b/src/lib/MVC/Symfony/SiteAccess.php @@ -16,6 +16,8 @@ class SiteAccess extends ValueObject implements JsonSerializable { public const DEFAULT_MATCHING_TYPE = 'default'; + public const MATCHING_TYPE_UNINITIALIZED = 'uninitialized'; + /** * Name of the siteaccess. * diff --git a/src/lib/MVC/Symfony/SiteAccess/SiteAccessService.php b/src/lib/MVC/Symfony/SiteAccess/SiteAccessService.php index 30dfe3cce9..cce23c23e3 100644 --- a/src/lib/MVC/Symfony/SiteAccess/SiteAccessService.php +++ b/src/lib/MVC/Symfony/SiteAccess/SiteAccessService.php @@ -15,14 +15,11 @@ class SiteAccessService implements SiteAccessServiceInterface, SiteAccessAware { - /** @var \Ibexa\Core\MVC\Symfony\SiteAccess\SiteAccessProviderInterface */ - private $provider; + private SiteAccessProviderInterface $provider; - /** @var \Ibexa\Core\MVC\Symfony\SiteAccess */ - private $siteAccess; + private SiteAccess $siteAccess; - /** @var \Ibexa\Contracts\Core\SiteAccess\ConfigResolverInterface */ - private $configResolver; + private ConfigResolverInterface $configResolver; public function __construct( SiteAccessProviderInterface $provider, diff --git a/tests/integration/Core/Resources/settings/common.yml b/tests/integration/Core/Resources/settings/common.yml index 33597b4f9e..bbd9504cae 100644 --- a/tests/integration/Core/Resources/settings/common.yml +++ b/tests/integration/Core/Resources/settings/common.yml @@ -70,7 +70,7 @@ services: Ibexa\Core\MVC\Symfony\SiteAccess: class: Ibexa\Core\MVC\Symfony\SiteAccess - arguments: ['default', 'uninitialized'] + arguments: ['default', !php/const Ibexa\Core\MVC\Symfony\SiteAccess::MATCHING_TYPE_UNINITIALIZED] Ibexa\Core\MVC\Symfony\SiteAccess\SiteAccessService: class: Ibexa\Core\MVC\Symfony\SiteAccess\SiteAccessService From 1e2e43931cde3e756e68236c9339941f1a08c61c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Niedzielski?= Date: Tue, 4 Aug 2026 13:52:39 +0200 Subject: [PATCH 2/3] Fixed nullable SiteAccessService::$siteAccess property type setSiteAccess() accepts and assigns null, but the property was typed as non-nullable SiteAccess, causing a TypeError. --- src/lib/MVC/Symfony/SiteAccess/SiteAccessService.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/MVC/Symfony/SiteAccess/SiteAccessService.php b/src/lib/MVC/Symfony/SiteAccess/SiteAccessService.php index cce23c23e3..d4db10fc3a 100644 --- a/src/lib/MVC/Symfony/SiteAccess/SiteAccessService.php +++ b/src/lib/MVC/Symfony/SiteAccess/SiteAccessService.php @@ -17,7 +17,7 @@ class SiteAccessService implements SiteAccessServiceInterface, SiteAccessAware { private SiteAccessProviderInterface $provider; - private SiteAccess $siteAccess; + private ?SiteAccess $siteAccess = null; private ConfigResolverInterface $configResolver; From 9654a60bc23b7be47e8e914dbbf01cc399462d43 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Niedzielski?= Date: Tue, 4 Aug 2026 14:06:14 +0200 Subject: [PATCH 3/3] Fixed PHPStan: removed stale baseline entries, guarded getSiteAccessesRelation() against null SiteAccess Making SiteAccessService::$siteAccess properly nullable exposed a real gap: getSiteAccessesRelation() fell back to $this->siteAccess without checking it could be null, and would then call ->name on it. --- phpstan-baseline.neon | 12 ------------ src/lib/MVC/Symfony/SiteAccess/SiteAccessService.php | 5 +++++ .../SiteAccess/SiteAccessServiceInterface.php | 2 ++ 3 files changed, 7 insertions(+), 12 deletions(-) diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon index fbfa0a2475..6ac13d46c4 100644 --- a/phpstan-baseline.neon +++ b/phpstan-baseline.neon @@ -15294,18 +15294,6 @@ parameters: count: 1 path: src/lib/MVC/Symfony/SiteAccess/SiteAccessProviderInterface.php - - - message: '#^Property Ibexa\\Core\\MVC\\Symfony\\SiteAccess\\SiteAccessService\:\:\$siteAccess \(Ibexa\\Core\\MVC\\Symfony\\SiteAccess\) does not accept Ibexa\\Core\\MVC\\Symfony\\SiteAccess\|null\.$#' - identifier: assign.propertyType - count: 1 - path: src/lib/MVC/Symfony/SiteAccess/SiteAccessService.php - - - - message: '#^Property Ibexa\\Core\\MVC\\Symfony\\SiteAccess\\SiteAccessService\:\:\$siteAccess \(Ibexa\\Core\\MVC\\Symfony\\SiteAccess\) on left side of \?\? is not nullable\.$#' - identifier: nullCoalesce.property - count: 1 - path: src/lib/MVC/Symfony/SiteAccess/SiteAccessService.php - - message: '#^Method Ibexa\\Core\\MVC\\Symfony\\Templating\\Exception\\InvalidResponseException\:\:addParameter\(\) has no return type specified\.$#' identifier: missingType.return diff --git a/src/lib/MVC/Symfony/SiteAccess/SiteAccessService.php b/src/lib/MVC/Symfony/SiteAccess/SiteAccessService.php index d4db10fc3a..724ed14562 100644 --- a/src/lib/MVC/Symfony/SiteAccess/SiteAccessService.php +++ b/src/lib/MVC/Symfony/SiteAccess/SiteAccessService.php @@ -9,6 +9,7 @@ namespace Ibexa\Core\MVC\Symfony\SiteAccess; use Ibexa\Contracts\Core\SiteAccess\ConfigResolverInterface; +use Ibexa\Core\Base\Exceptions\InvalidArgumentException; use Ibexa\Core\Base\Exceptions\NotFoundException; use Ibexa\Core\MVC\Symfony\SiteAccess; use function iterator_to_array; @@ -61,6 +62,10 @@ public function getCurrent(): ?SiteAccess public function getSiteAccessesRelation(?SiteAccess $siteAccess = null): array { $siteAccess = $siteAccess ?? $this->siteAccess; + if ($siteAccess === null) { + throw new InvalidArgumentException('siteAccess', 'no SiteAccess given and none currently set'); + } + $saRelationMap = []; /** @var \Ibexa\Core\MVC\Symfony\SiteAccess[] $saList */ diff --git a/src/lib/MVC/Symfony/SiteAccess/SiteAccessServiceInterface.php b/src/lib/MVC/Symfony/SiteAccess/SiteAccessServiceInterface.php index 2bd1dd7342..d08f6905aa 100644 --- a/src/lib/MVC/Symfony/SiteAccess/SiteAccessServiceInterface.php +++ b/src/lib/MVC/Symfony/SiteAccess/SiteAccessServiceInterface.php @@ -33,6 +33,8 @@ public function getCurrent(): ?SiteAccess; * Handles relation between SiteAccesses. Related SiteAccesses share the same repository and root location id. * * @return string[] + * + * @throws \Ibexa\Core\Base\Exceptions\InvalidArgumentException if no SiteAccess is given and none is currently set */ public function getSiteAccessesRelation(?SiteAccess $siteAccess = null): array; }