IBX-12204: SiteAccessService owns a scope-change stack, SiteAccessAware deprecated - #798
Draft
Steveb-p wants to merge 4 commits into
Draft
IBX-12204: SiteAccessService owns a scope-change stack, SiteAccessAware deprecated#798Steveb-p wants to merge 4 commits into
Steveb-p wants to merge 4 commits into
Conversation
…re deprecated SiteAccessService now maintains a real LIFO stack of SiteAccess changes and exposes changeSiteAccess()/restoreSiteAccess(), wrapping the existing ScopeChangeEvent dispatch instead of requiring callers to hand-build it. getCurrent() reflects the active scope correctly, including through nested sub-requests (content preview, fragments, ESI). SiteAccessAware is marked @deprecated; straightforward "read current SiteAccess" consumers (ContentPreviewHelper, ConsoleCommandListener, HttpUtils, DefaultRouter, Generator, AliasGeneratorDecorator, DecoratedFragmentRenderer/InlineFragmentRenderer) are migrated to SiteAccessService::getCurrent() instead.
…etter Generator (and UrlAliasGenerator), HttpUtils, and DefaultRouter now receive SiteAccessServiceInterface as a constructor dependency instead of through a setSiteAccessService() call. For the two classes extending Symfony framework base classes (HttpUtils, DefaultRouter), the new parameter is appended as a nullable, named-argument-bound constructor parameter so the existing positional arguments coming from Symfony's own service definitions are left untouched.
…ctor arg UrlAliasGenerator::__construct() now requires SiteAccessServiceInterface as its 4th argument; the test built the generator via getMockBuilder() with only 3 constructor args, causing an ArgumentCountError on both PHP 8.3 and 8.4 CI jobs.
Removing SiteAccessAware from SiteAccessService also dropped the old setSiteAccess() call that seeded it with the shared, container-wide default SiteAccess singleton at construction time. That meant getCurrent() went from "never null once the container is built" to genuinely null until the first PostSiteAccessMatchEvent, breaking any code that reads it outside of an HTTP request cycle (integration tests, CLI warm-up, etc.) — surfaced by ComplexConfigProcessor/IOConfigResolver now throwing on IO-related integration tests. SiteAccessService now takes that shared SiteAccess singleton as a 4th constructor argument and seeds the stack with it directly (no event dispatch, matching the old setSiteAccess() semantics exactly), restoring the pre-existing guarantee.
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.



Description:
A
ConfigScopeListeneralready reacts toMVCEvents::CONFIG_SCOPE_CHANGE/CONFIG_SCOPE_RESTOREand broadcasts the new SiteAccess to everyVersatileScopeInterfaceconfig resolver and everySiteAccessAwareview manager/view provider — butSiteAccessServiceitself was never one of those broadcast targets. It kept a single value, injected once viaSiteAccessAware::setSiteAccess()from request matching, that never updated when a scope change was dispatched (see IBX-8074). Every scope-change call site (ContentPreviewHelper,ConsoleCommandListener) also had to hand-build aScopeChangeEventand dispatch it itself, with no supported API for it.This PR makes
SiteAccessServicethe single owner of "what is the current SiteAccess right now":SiteAccessService::changeSiteAccess(SiteAccess $siteAccess): SiteAccessandrestoreSiteAccess(): ?SiteAccess, which wrap the existingScopeChangeEventdispatch underMVCEvents::CONFIG_SCOPE_CHANGE/CONFIG_SCOPE_RESTORE— no new event types, just a supported API instead of hand-dispatching.SiteAccessServicenow maintains a real LIFO stack ofSiteAccesschanges instead of a single injected value:EventSubscriberInterfaceand subscribes toMVCEvents::SITEACCESS: on aMAIN_REQUESTmatch it resets the stack to[$siteAccess]; on aSUB_REQUESTmatch (fragments, ESI, content-preview's internal sub-request) it pushes onto the stack.KernelEvents::FINISH_REQUEST, which pops the stack — but never below 1 remaining entry. That single "floor guard" is shared withrestoreSiteAccess(), so a sub-request's own push is always safely undone by its own finish, and an unbalancedrestoreSiteAccess()call (or CLI's one-timechangeSiteAccess()floor) can never strip the stack down to empty.getCurrent()returns the top of the stack. The constructor now also takes the shared, container-wide defaultSiteAccesssingleton (the same oneSiteAccessListenermutates in place) and seeds the stack with it directly, with no event dispatch — this preserves the pre-existing guarantee thatgetCurrent()is never null once the container is built, which code such asComplexConfigProcessorrelies on outside of an HTTP request cycle (CLI warm-up, integration tests, etc.).SiteAccessAwareis marked@deprecated(no runtime deprecation notice — it's still legitimately used by consumers not migrated here) in favor of callingSiteAccessService::getCurrent()directly.SiteAccessAwareconsumers to constructor-injectSiteAccessServiceInterfaceand callgetCurrent()instead of storing a value viasetSiteAccess():ContentPreviewHelper,ConsoleCommandListener,HttpUtils,DefaultRouter,Generator(andUrlAliasGenerator),AliasGeneratorDecorator,DecoratedFragmentRenderer/InlineFragmentRenderer.ConsoleCommandListenerstill mutates the sharedSiteAccesssingleton in place in addition to callingchangeSiteAccess()—ConfigResolverand friends still read that singleton directly for theMATCHING_TYPE_UNINITIALIZEDsentinel (see IBX-12192) and are intentionally not migrated in this PR (would require a circular DI dependency back ontoSiteAccessService, plus non-trivial caching/broadcast semantics). Same reasoning excludesSiteAccess\Router,View\Manager/Provider\Configured.ComplexConfigProcessorwhile migrating it: it read$this->siteAccessService->getCurrent()->namewith no null check. Added agetCurrentSiteAccessName()guard that throwsInvalidArgumentException, matching the precedent already set inSiteAccessService::getSiteAccessesRelation().DecoratedFragmentRenderer/InlineFragmentRendererpreviously only ever saw the original request's SiteAccess when rewriting fragment paths (they weren't part ofConfigScopeListener's scope-change broadcast). They now correctly reflect whateverSiteAccessService::getCurrent()says, including during an active content-preview scope change — this is a correctness fix, not a regression.routing.yml,services.yml,helpers.yml,image.yml, and theSecurityPass/ChainRoutingPass/FragmentPasscompiler passes now passSiteAccessServiceInterfaceas a constructor argument instead of the oldsetSiteAccess()calls;SiteAccessServiceitself gained anEventDispatcherInterfaceconstructor argument and akernel.event_subscribertag. ForHttpUtilsandDefaultRouter— which extend Symfony framework base classes with their own evolving constructors — the new parameter is appended as a nullable, named-argument-bound constructor parameter ($definition->setArgument('$siteAccessService', ...)), so the existing positional arguments coming from Symfony's own service definitions are left untouched.phpstan-baseline.neonentries left behind by removingSiteAccessAware/setSiteAccess()from the migrated classes.Verified:
phpstan analyseclean, and theunit_core/bundle_core/bundle_ioPHPUnit suites pass (6567/864/27 tests respectively, no failures — only pre-existing PHPUnit-deprecation warnings unrelated to this change).For QA:
Two scenarios worth exercising manually:
--siteaccess=<name>and confirmSiteAccessService::getCurrent()(andConfigResolver) reflect that siteaccess for the whole command run.New unit test coverage lives in
SiteAccessServiceTestfor the stack semantics specifically: nestedchangeSiteAccess()/restoreSiteAccess()pairs behaving as LIFO,MAIN_REQUESTresetting vs.SUB_REQUESTpushing, the finish_request floor guard never popping below 1 entry, and a full sub-request-nesting scenario.Documentation:
SiteAccessAwareis now@deprecated— worth a mention in the deprecation notes for this release, pointing integrators atSiteAccessServiceInterface::getCurrent()/changeSiteAccess()/restoreSiteAccess()instead of the oldsetSiteAccess()+ hand-dispatchedScopeChangeEventpattern.