vendor/symfony/security-core/Authorization/TraceableAccessDecisionManager.php line 54

Open in your IDE?
  1. <?php
  2. /*
  3.  * This file is part of the Symfony package.
  4.  *
  5.  * (c) Fabien Potencier <[email protected]>
  6.  *
  7.  * For the full copyright and license information, please view the LICENSE
  8.  * file that was distributed with this source code.
  9.  */
  10. namespace Symfony\Component\Security\Core\Authorization;
  11. use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
  12. use Symfony\Component\Security\Core\Authorization\Voter\VoterInterface;
  13. /**
  14.  * Decorates the original AccessDecisionManager class to log information
  15.  * about the security voters and the decisions made by them.
  16.  *
  17.  * @author Javier Eguiluz <[email protected]>
  18.  *
  19.  * @internal
  20.  */
  21. class TraceableAccessDecisionManager implements AccessDecisionManagerInterface
  22. {
  23.     private $manager;
  24.     private $strategy;
  25.     /** @var iterable<mixed, VoterInterface> */
  26.     private $voters = [];
  27.     private $decisionLog = []; // All decision logs
  28.     private $currentLog = [];  // Logs being filled in
  29.     public function __construct(AccessDecisionManagerInterface $manager)
  30.     {
  31.         $this->manager $manager;
  32.         if ($this->manager instanceof AccessDecisionManager) {
  33.             // The strategy and voters are stored in a private properties of the decorated service
  34.             $reflection = new \ReflectionProperty(AccessDecisionManager::class, 'strategy');
  35.             $reflection->setAccessible(true);
  36.             $this->strategy $reflection->getValue($manager);
  37.             $reflection = new \ReflectionProperty(AccessDecisionManager::class, 'voters');
  38.             $reflection->setAccessible(true);
  39.             $this->voters $reflection->getValue($manager);
  40.         }
  41.     }
  42.     /**
  43.      * {@inheritdoc}
  44.      *
  45.      * @param bool $allowMultipleAttributes Whether to allow passing multiple values to the $attributes array
  46.      */
  47.     public function decide(TokenInterface $token, array $attributes$object null/* , bool $allowMultipleAttributes = false */): bool
  48.     {
  49.         $currentDecisionLog = [
  50.             'attributes' => $attributes,
  51.             'object' => $object,
  52.             'voterDetails' => [],
  53.         ];
  54.         $this->currentLog[] = &$currentDecisionLog;
  55.         $result $this->manager->decide($token$attributes$object< \func_num_args() && func_get_arg(3));
  56.         $currentDecisionLog['result'] = $result;
  57.         $this->decisionLog[] = array_pop($this->currentLog); // Using a stack since decide can be called by voters
  58.         return $result;
  59.     }
  60.     /**
  61.      * Adds voter vote and class to the voter details.
  62.      *
  63.      * @param array $attributes attributes used for the vote
  64.      * @param int   $vote       vote of the voter
  65.      */
  66.     public function addVoterVote(VoterInterface $voter, array $attributesint $vote)
  67.     {
  68.         $currentLogIndex = \count($this->currentLog) - 1;
  69.         $this->currentLog[$currentLogIndex]['voterDetails'][] = [
  70.             'voter' => $voter,
  71.             'attributes' => $attributes,
  72.             'vote' => $vote,
  73.         ];
  74.     }
  75.     public function getStrategy(): string
  76.     {
  77.         if (null === $this->strategy) {
  78.             return '-';
  79.         }
  80.         if (method_exists($this->strategy'__toString')) {
  81.             return (string) $this->strategy;
  82.         }
  83.         return get_debug_type($this->strategy);
  84.     }
  85.     /**
  86.      * @return iterable<mixed, VoterInterface>
  87.      */
  88.     public function getVoters(): iterable
  89.     {
  90.         return $this->voters;
  91.     }
  92.     public function getDecisionLog(): array
  93.     {
  94.         return $this->decisionLog;
  95.     }
  96. }
  97. if (!class_exists(DebugAccessDecisionManager::class, false)) {
  98.     class_alias(TraceableAccessDecisionManager::class, DebugAccessDecisionManager::class);
  99. }