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

Open in your IDE?
  1. <?php
  2. /*
  3.  * This file is part of the Symfony package.
  4.  *
  5.  * (c) Fabien Potencier <fabien@symfony.com>
  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\Strategy\AccessDecisionStrategyInterface;
  13. use Symfony\Component\Security\Core\Authorization\Voter\VoterInterface;
  14. /**
  15.  * Decorates the original AccessDecisionManager class to log information
  16.  * about the security voters and the decisions made by them.
  17.  *
  18.  * @author Javier Eguiluz <javier.eguiluz@gmail.com>
  19.  *
  20.  * @internal
  21.  */
  22. class TraceableAccessDecisionManager implements AccessDecisionManagerInterface
  23. {
  24.     private AccessDecisionManagerInterface $manager;
  25.     private ?AccessDecisionStrategyInterface $strategy null;
  26.     /** @var iterable<mixed, VoterInterface> */
  27.     private iterable $voters = [];
  28.     private array $decisionLog = []; // All decision logs
  29.     private array $currentLog = [];  // Logs being filled in
  30.     public function __construct(AccessDecisionManagerInterface $manager)
  31.     {
  32.         $this->manager $manager;
  33.         // The strategy and voters are stored in a private properties of the decorated service
  34.         if (property_exists($manager'strategy')) {
  35.             $reflection = new \ReflectionProperty($manager::class, 'strategy');
  36.             $this->strategy $reflection->getValue($manager);
  37.         }
  38.         if (property_exists($manager'voters')) {
  39.             $reflection = new \ReflectionProperty($manager::class, 'voters');
  40.             $this->voters $reflection->getValue($manager);
  41.         }
  42.     }
  43.     public function decide(TokenInterface $token, array $attributesmixed $object nullbool $allowMultipleAttributes false): bool
  44.     {
  45.         $currentDecisionLog = [
  46.             'attributes' => $attributes,
  47.             'object' => $object,
  48.             'voterDetails' => [],
  49.         ];
  50.         $this->currentLog[] = &$currentDecisionLog;
  51.         $result $this->manager->decide($token$attributes$object$allowMultipleAttributes);
  52.         $currentDecisionLog['result'] = $result;
  53.         $this->decisionLog[] = array_pop($this->currentLog); // Using a stack since decide can be called by voters
  54.         return $result;
  55.     }
  56.     /**
  57.      * Adds voter vote and class to the voter details.
  58.      *
  59.      * @param array $attributes attributes used for the vote
  60.      * @param int   $vote       vote of the voter
  61.      */
  62.     public function addVoterVote(VoterInterface $voter, array $attributesint $vote)
  63.     {
  64.         $currentLogIndex \count($this->currentLog) - 1;
  65.         $this->currentLog[$currentLogIndex]['voterDetails'][] = [
  66.             'voter' => $voter,
  67.             'attributes' => $attributes,
  68.             'vote' => $vote,
  69.         ];
  70.     }
  71.     public function getStrategy(): string
  72.     {
  73.         if (null === $this->strategy) {
  74.             return '-';
  75.         }
  76.         if (method_exists($this->strategy'__toString')) {
  77.             return (string) $this->strategy;
  78.         }
  79.         return get_debug_type($this->strategy);
  80.     }
  81.     /**
  82.      * @return iterable<mixed, VoterInterface>
  83.      */
  84.     public function getVoters(): iterable
  85.     {
  86.         return $this->voters;
  87.     }
  88.     public function getDecisionLog(): array
  89.     {
  90.         return $this->decisionLog;
  91.     }
  92. }