• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

api-platform / core / 20847225472

09 Jan 2026 09:22AM UTC coverage: 29.095% (+0.1%) from 28.946%
20847225472

push

github

web-flow
feat(doctrine): uuid filter (#7628)

Co-authored-by: soyuka <soyuka@users.noreply.github.com>

130 of 156 new or added lines in 4 files covered. (83.33%)

80 existing lines in 11 files now uncovered.

16992 of 58402 relevant lines covered (29.09%)

81.51 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

97.14
/src/Symfony/Security/ResourceAccessChecker.php
1
<?php
2

3
/*
4
 * This file is part of the API Platform project.
5
 *
6
 * (c) Kévin Dunglas <dunglas@gmail.com>
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 */
11

12
declare(strict_types=1);
13

14
namespace ApiPlatform\Symfony\Security;
15

16
use ApiPlatform\Metadata\ResourceAccessCheckerInterface;
17
use Symfony\Component\ExpressionLanguage\ExpressionLanguage;
18
use Symfony\Component\ExpressionLanguage\Node\NameNode;
19
use Symfony\Component\ExpressionLanguage\Node\Node;
20
use Symfony\Component\Security\Core\Authentication\AuthenticationTrustResolverInterface;
21
use Symfony\Component\Security\Core\Authentication\Token\NullToken;
22
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
23
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
24
use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface;
25
use Symfony\Component\Security\Core\Role\RoleHierarchyInterface;
26

27
/**
28
 * Checks if the logged user has sufficient permissions to access the given resource.
29
 *
30
 * @author Kévin Dunglas <dunglas@gmail.com>
31
 */
32
final class ResourceAccessChecker implements ResourceAccessCheckerInterface, ObjectVariableCheckerInterface
33
{
34
    public function __construct(private readonly ?ExpressionLanguage $expressionLanguage = null, private readonly ?AuthenticationTrustResolverInterface $authenticationTrustResolver = null, private readonly ?RoleHierarchyInterface $roleHierarchy = null, private readonly ?TokenStorageInterface $tokenStorage = null, private readonly ?AuthorizationCheckerInterface $authorizationChecker = null)
35
    {
36
    }
2,403✔
37

38
    public function isGranted(string $resourceClass, string $expression, array $extraVariables = []): bool
39
    {
40
        if (null === $this->tokenStorage || null === $this->authenticationTrustResolver) {
188✔
41
            throw new \LogicException('The "symfony/security" library must be installed to use the "security" attribute.');
2✔
42
        }
43

44
        if (null === $this->expressionLanguage) {
186✔
45
            throw new \LogicException('The "symfony/expression-language" library must be installed to use the "security" attribute.');
2✔
46
        }
47

48
        return (bool) $this->expressionLanguage->evaluate($expression, $this->getVariables($extraVariables));
184✔
49
    }
50

51
    public function usesObjectVariable(string $expression, array $variables = []): bool
52
    {
53
        return $this->hasObjectVariable($this->expressionLanguage->parse($expression, array_keys($this->getVariables($variables)))->getNodes()->toArray());
75✔
54
    }
55

56
    /**
57
     * @copyright Fabien Potencier <fabien@symfony.com>
58
     *
59
     * @see https://github.com/symfony/symfony/blob/master/src/Symfony/Component/Security/Core/Authorization/Voter/ExpressionVoter.php
60
     */
61
    private function getVariables(array $variables): array
62
    {
63
        if (null === $token = $this->tokenStorage->getToken()) {
184✔
64
            $token = new NullToken();
38✔
65
        }
66

67
        return array_merge($variables, [
184✔
68
            'token' => $token,
184✔
69
            'user' => $token->getUser(),
184✔
70
            'roles' => $this->getEffectiveRoles($token),
184✔
71
            'trust_resolver' => $this->authenticationTrustResolver,
184✔
72
            'auth_checker' => $this->authorizationChecker, // needed for the is_granted expression function
184✔
73
        ]);
184✔
74
    }
75

76
    /**
77
     * @return string[]
78
     */
79
    private function getEffectiveRoles(TokenInterface $token): array
80
    {
81
        if (null === $this->roleHierarchy) {
184✔
82
            return $token->getRoleNames();
6✔
83
        }
84

85
        return $this->roleHierarchy->getReachableRoleNames($token->getRoleNames());
178✔
86
    }
87

88
    /**
89
     * Recursively checks if a variable named 'object' is present in the expression AST.
90
     *
91
     * @param Node|array<mixed>|null $nodeOrNodes the ExpressionLanguage Node instance or an array of nodes/values
92
     */
93
    private function hasObjectVariable(Node|array|null $nodeOrNodes): bool
94
    {
95
        if ($nodeOrNodes instanceof NameNode) {
75✔
UNCOV
96
            if ('object' === $nodeOrNodes->attributes['name'] || 'previous_object' === $nodeOrNodes->attributes['name']) {
14✔
UNCOV
97
                return true;
14✔
98
            }
99

100
            return false;
×
101
        }
102

103
        if ($nodeOrNodes instanceof Node) {
75✔
104
            foreach ($nodeOrNodes->nodes as $childNode) {
75✔
105
                if ($this->hasObjectVariable($childNode)) {
38✔
UNCOV
106
                    return true;
14✔
107
                }
108
            }
109

110
            return false;
75✔
111
        }
112

113
        if (\is_array($nodeOrNodes)) {
75✔
114
            foreach ($nodeOrNodes as $element) {
75✔
115
                if (\is_string($element)) {
75✔
116
                    continue;
75✔
117
                }
118

119
                if ($this->hasObjectVariable($element)) {
75✔
UNCOV
120
                    return true;
14✔
121
                }
122
            }
123
        }
124

125
        return false;
61✔
126
    }
127
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc