diff --git a/src/Symfony/Component/Security/Core/Authorization/AccessDecisionManager.php b/src/Symfony/Component/Security/Core/Authorization/AccessDecisionManager.php index 025f6827bdfd1..65cf304b5800f 100644 --- a/src/Symfony/Component/Security/Core/Authorization/AccessDecisionManager.php +++ b/src/Symfony/Component/Security/Core/Authorization/AccessDecisionManager.php @@ -35,6 +35,9 @@ final class AccessDecisionManager implements AccessDecisionManagerInterface private iterable $voters; private array $votersCacheAttributes = []; private array $votersCacheObject = []; + private array $nonCachableVoters = []; + private array $cachedVoters = []; + private AccessDecisionStrategyInterface $strategy; /** @@ -87,13 +90,28 @@ private function getVoters(array $attributes, $object = null): iterable } // use `get_class` to handle anonymous classes $keyObject = \is_object($object) ? $object::class : get_debug_type($object); + + foreach ($keyAttributes as $keyAttribute) { + if (isset($this->cachedVoters[$keyAttribute][$keyObject])) { + $voters = $this->nonCachableVoters + $this->cachedVoters[$keyAttribute][$keyObject]; + ksort($voters); + + yield from $voters; + + return; + } + } + + $voters = []; foreach ($this->voters as $key => $voter) { if (!$voter instanceof CacheableVoterInterface) { - yield $voter; + $this->nonCachableVoters[$key] = $voter; + $voters[] = $voter; continue; } $supports = true; + $supportedAttributes = []; // The voter supports the attributes if it supports at least one attribute of the list foreach ($keyAttributes as $keyAttribute) { if (null === $keyAttribute) { @@ -104,10 +122,10 @@ private function getVoters(array $attributes, $object = null): iterable $supports = $this->votersCacheAttributes[$keyAttribute][$key]; } if ($supports) { - break; + $supportedAttributes[] = $keyAttribute; } } - if (!$supports) { + if (!$supports && [] === $supportedAttributes) { continue; } @@ -119,7 +137,14 @@ private function getVoters(array $attributes, $object = null): iterable if (!$supports) { continue; } - yield $voter; + + foreach ($supportedAttributes as $supportedAttribute) { + $this->cachedVoters[$supportedAttribute][$keyObject][$key] = $voter; + } + + $voters[] = $voter; } + + yield from $voters; } }