Skip to content

Commit fb602ce

Browse files
committed
undeprecate the RoleHierarchyInterface
Instead of deprecating the interface it is sufficient to deprecate its getReachableRoles() method and add a new getReachableRoleNames() method in Symfony 5.
1 parent 522594a commit fb602ce

File tree

10 files changed

+50
-60
lines changed

10 files changed

+50
-60
lines changed

UPGRADE-4.3.md

+2-3
Original file line numberDiff line numberDiff line change
@@ -88,9 +88,8 @@ Security
8888

8989
* The `Role` and `SwitchUserRole` classes are deprecated and will be removed in 5.0. Use strings for roles
9090
instead.
91-
* The `RoleHierarchyInterface` is deprecated and will be removed in 5.0.
92-
* The `getReachableRoles()` method of the `RoleHierarchy` class is deprecated and will be removed in 5.0.
93-
Use the `getReachableRoleNames()` method instead.
91+
* The `getReachableRoles()` method of the `RoleHierarchyInterface` is deprecated and will be removed in 5.0.
92+
Role hierarchies must implement the `getReachableRoleNames()` method instead and return roles as strings.
9493
* The `getRoles()` method of the `TokenInterface` is deprecated. Tokens must implement the `getRoleNames()`
9594
method instead and return roles as strings.
9695
* The `ListenerInterface` is deprecated, turn your listeners into callables instead.

UPGRADE-5.0.md

+2-2
Original file line numberDiff line numberDiff line change
@@ -256,8 +256,8 @@ Security
256256
--------
257257

258258
* The `Role` and `SwitchUserRole` classes have been removed.
259-
* The `RoleHierarchyInterface` has been removed.
260-
* The `getReachableRoles()` method of the `RoleHierarchy` class has been removed.
259+
* The `getReachableRoles()` method of the `RoleHierarchy` class has been removed. It has been replaced by the new
260+
`getReachableRoleNames()` method.
261261
* The `getRoles()` method has been removed from the `TokenInterface`. It has been replaced by the new
262262
`getRoleNames()` method.
263263
* The `ContextListener::setLogoutOnUserChange()` method has been removed.

src/Symfony/Bundle/SecurityBundle/DataCollector/SecurityDataCollector.php

+1-2
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@
2323
use Symfony\Component\Security\Core\Authorization\TraceableAccessDecisionManager;
2424
use Symfony\Component\Security\Core\Authorization\Voter\TraceableVoter;
2525
use Symfony\Component\Security\Core\Role\Role;
26-
use Symfony\Component\Security\Core\Role\RoleHierarchy;
2726
use Symfony\Component\Security\Core\Role\RoleHierarchyInterface;
2827
use Symfony\Component\Security\Core\Role\SwitchUserRole;
2928
use Symfony\Component\Security\Http\Firewall\SwitchUserListener;
@@ -113,7 +112,7 @@ public function collect(Request $request, Response $response, \Exception $except
113112
}
114113

115114
if (null !== $this->roleHierarchy) {
116-
if ($this->roleHierarchy instanceof RoleHierarchy) {
115+
if (method_exists($this->roleHierarchy, 'getReachableRoleNames')) {
117116
$allRoles = $this->roleHierarchy->getReachableRoleNames($assignedRoles);
118117
} else {
119118
$allRoles = array_map(function (Role $role) { return (string) $role; }, $this->roleHierarchy->getReachableRoles($token->getRoles(false)));

src/Symfony/Bundle/SecurityBundle/Resources/config/security.xml

-2
Original file line numberDiff line numberDiff line change
@@ -98,8 +98,6 @@
9898
<argument>%security.role_hierarchy.roles%</argument>
9999
</service>
100100
<service id="Symfony\Component\Security\Core\Role\RoleHierarchyInterface" alias="security.role_hierarchy" />
101-
<service id="Symfony\Component\Security\Core\Role\RoleHierarchy" alias="security.role_hierarchy" />
102-
103101

104102
<!-- Security Voters -->
105103
<service id="security.access.simple_role_voter" class="Symfony\Component\Security\Core\Authorization\Voter\RoleVoter">

src/Symfony/Component/Security/CHANGELOG.md

+2-3
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,8 @@ CHANGELOG
66

77
* The `Role` and `SwitchUserRole` classes are deprecated and will be removed in 5.0. Use strings for roles
88
instead.
9-
* The `RoleHierarchyInterface` is deprecated and will be removed in 5.0.
10-
* The `getReachableRoles()` method of the `RoleHierarchy` class is deprecated and will be removed in 5.0.
11-
Use the `getReachableRoleNames()` method instead.
9+
* The `getReachableRoles()` method of the `RoleHierarchyInterface` is deprecated and will be removed in 5.0.
10+
Role hierarchies must implement the `getReachableRoleNames()` method instead and return roles as strings.
1211
* The `getRoles()` method of the `TokenInterface` is deprecated. Tokens must implement the `getRoleNames()`
1312
method instead and return roles as strings.
1413
* Made the `serialize()` and `unserialize()` methods of `AbstractToken` and

src/Symfony/Component/Security/Core/Authorization/Voter/ExpressionVoter.php

+16-16
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@
1919
use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface;
2020
use Symfony\Component\Security\Core\Authorization\ExpressionLanguage;
2121
use Symfony\Component\Security\Core\Role\Role;
22-
use Symfony\Component\Security\Core\Role\RoleHierarchy;
2322
use Symfony\Component\Security\Core\Role\RoleHierarchyInterface;
2423

2524
/**
@@ -43,6 +42,10 @@ public function __construct(ExpressionLanguage $expressionLanguage, Authenticati
4342
@trigger_error(sprintf('Passing a RoleHierarchyInterface to "%s()" is deprecated since Symfony 4.2. Pass an AuthorizationCheckerInterface instead.', __METHOD__), E_USER_DEPRECATED);
4443
$roleHierarchy = $authChecker;
4544
$authChecker = null;
45+
46+
if (!method_exists($roleHierarchy, 'getReachableRoleNames')) {
47+
@trigger_error(sprintf('Not implementing the getReachableRoleNames() method in %s which implements %s is deprecated since Symfony 4.3.', \get_class($this->roleHierarchy), RoleHierarchyInterface::class), E_USER_DEPRECATED);
48+
}
4649
} elseif (null === $authChecker) {
4750
@trigger_error(sprintf('Argument 3 passed to "%s()" should be an instance of AuthorizationCheckerInterface, not passing it is deprecated since Symfony 4.2.', __METHOD__), E_USER_DEPRECATED);
4851
} elseif (!$authChecker instanceof AuthorizationCheckerInterface) {
@@ -92,34 +95,31 @@ public function vote(TokenInterface $token, $subject, array $attributes)
9295

9396
private function getVariables(TokenInterface $token, $subject)
9497
{
95-
if ($this->roleHierarchy instanceof RoleHierarchy) {
96-
if (method_exists($token, 'getRoleNames')) {
97-
$rolesFromToken = $token->getRoleNames();
98-
} else {
99-
@trigger_error(sprintf('Not implementing the getRoleNames() method in %s which implements %s is deprecated since Symfony 4.3.', \get_class($token), TokenInterface::class), E_USER_DEPRECATED);
100-
101-
$rolesFromToken = $token->getRoles(false);
102-
}
103-
104-
$roles = $this->roleHierarchy->getReachableRoleNames($rolesFromToken);
105-
} elseif (null !== $this->roleHierarchy) {
106-
$roles = $this->roleHierarchy->getReachableRoles($token->getRoles(false));
107-
} elseif (method_exists($token, 'getRoleNames')) {
108-
$roles = $token->getRoleNames();
98+
if (method_exists($token, 'getRoleNames')) {
99+
$roleNames = $token->getRoleNames();
100+
$roles = array_map(function (string $role) { return new Role($role, false); }, $roleNames);
109101
} else {
110102
@trigger_error(sprintf('Not implementing the getRoleNames() method in %s which implements %s is deprecated since Symfony 4.3.', \get_class($token), TokenInterface::class), E_USER_DEPRECATED);
111103

112104
$roles = $token->getRoles(false);
105+
$roleNames = array_map(function (Role $role) { return $role->getRole(); }, $roles);
113106
}
114107

115-
$roles = array_map(function ($role) { return $role instanceof Role ? $role->getRole() : $role; }, $roles);
108+
if (null !== $this->roleHierarchy && method_exists($this->roleHierarchy, 'getReachableRoleNames')) {
109+
$roleNames = $this->roleHierarchy->getReachableRoleNames($roleNames);
110+
$roles = array_map(function (string $role) { return new Role($role, false); }, $roleNames);
111+
} elseif (null !== $this->roleHierarchy) {
112+
$roles = $this->roleHierarchy->getReachableRoles($roles);
113+
$roleNames = array_map(function (Role $role) { return $role->getRole(); }, $roles);
114+
}
116115

117116
$variables = [
118117
'token' => $token,
119118
'user' => $token->getUser(),
120119
'object' => $subject,
121120
'subject' => $subject,
122121
'roles' => $roles,
122+
'role_names' => $roleNames,
123123
'trust_resolver' => $this->trustResolver,
124124
'auth_checker' => $this->authChecker,
125125
];

src/Symfony/Component/Security/Core/Authorization/Voter/RoleHierarchyVoter.php

+5-4
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
namespace Symfony\Component\Security\Core\Authorization\Voter;
1313

1414
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
15+
use Symfony\Component\Security\Core\Role\Role;
1516
use Symfony\Component\Security\Core\Role\RoleHierarchy;
1617
use Symfony\Component\Security\Core\Role\RoleHierarchyInterface;
1718

@@ -27,8 +28,8 @@ class RoleHierarchyVoter extends RoleVoter
2728

2829
public function __construct(RoleHierarchyInterface $roleHierarchy, string $prefix = 'ROLE_')
2930
{
30-
if (!$roleHierarchy instanceof RoleHierarchy) {
31-
@trigger_error(sprintf('Passing a role hierarchy to "%s" that is not an instance of "%s" is deprecated since Symfony 4.3 and support for it will be dropped in Symfony 5.0 ("%s" given).', __CLASS__, RoleHierarchy::class, \get_class($roleHierarchy)), E_USER_DEPRECATED);
31+
if (!method_exists($roleHierarchy, 'getReachableRoleNames')) {
32+
@trigger_error(sprintf('Not implementing the getReachableRoleNames() method in %s which implements %s is deprecated since Symfony 4.3.', \get_class($roleHierarchy), RoleHierarchyInterface::class), E_USER_DEPRECATED);
3233
}
3334

3435
$this->roleHierarchy = $roleHierarchy;
@@ -41,13 +42,13 @@ public function __construct(RoleHierarchyInterface $roleHierarchy, string $prefi
4142
*/
4243
protected function extractRoles(TokenInterface $token)
4344
{
44-
if ($this->roleHierarchy instanceof RoleHierarchy) {
45+
if (method_exists($this->roleHierarchy, 'getReachableRoleNames')) {
4546
if (method_exists($token, 'getRoleNames')) {
4647
$roles = $token->getRoleNames();
4748
} else {
4849
@trigger_error(sprintf('Not implementing the getRoleNames() method in %s which implements %s is deprecated since Symfony 4.3.', \get_class($token), TokenInterface::class), E_USER_DEPRECATED);
4950

50-
$roles = $token->getRoles(false);
51+
$roles = array_map(function (Role $role) { return $role->getRole(); }, $token->getRoles(false));
5152
}
5253

5354
return $this->roleHierarchy->getReachableRoleNames($roles);

src/Symfony/Component/Security/Core/Role/RoleHierarchy.php

+4-11
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,9 @@ public function __construct(array $hierarchy)
3636
*/
3737
public function getReachableRoles(array $roles)
3838
{
39-
@trigger_error(sprintf('The %s() method is deprecated since Symfony 4.3 and will be removed in 5.0. Use roles as strings and the getReachableRoleNames() method instead.', __METHOD__), E_USER_DEPRECATED);
39+
if (0 === \func_num_args() || func_get_arg(0)) {
40+
@trigger_error(sprintf('The %s() method is deprecated since Symfony 4.3 and will be removed in 5.0. Use roles as strings and the getReachableRoleNames() method instead.', __METHOD__), E_USER_DEPRECATED);
41+
}
4042

4143
$reachableRoles = $roles;
4244
foreach ($roles as $role) {
@@ -59,16 +61,7 @@ public function getReachableRoles(array $roles)
5961
*/
6062
public function getReachableRoleNames(array $roles): array
6163
{
62-
$reachableRoles = $roles = array_map(
63-
function ($role) {
64-
if ($role instanceof Role) {
65-
return $role->getRole();
66-
}
67-
68-
return $role;
69-
},
70-
$roles
71-
);
64+
$reachableRoles = $roles;
7265

7366
foreach ($roles as $role) {
7467
if (!isset($this->map[$role])) {

src/Symfony/Component/Security/Core/Role/RoleHierarchyInterface.php

+2-12
Original file line numberDiff line numberDiff line change
@@ -16,19 +16,9 @@
1616
*
1717
* @author Fabien Potencier <fabien@symfony.com>
1818
*
19-
* @deprecated since Symfony 4.3, to be removed in 5.0.
19+
* @method Role[] getReachableRoles(Role[] $roles) Returns an array of all reachable roles by the given ones - deprecated since Symfony 4.3
20+
* @method string[] getReachableRoleNames(string[] $roles) The associated roles - not implementing it is deprecated since Symfony 4.3
2021
*/
2122
interface RoleHierarchyInterface
2223
{
23-
/**
24-
* Returns an array of all reachable roles by the given ones.
25-
*
26-
* Reachable roles are the roles directly assigned but also all roles that
27-
* are transitively reachable from them in the role hierarchy.
28-
*
29-
* @param Role[] $roles An array of directly assigned roles
30-
*
31-
* @return Role[] An array of all reachable roles
32-
*/
33-
public function getReachableRoles(array $roles);
3424
}

src/Symfony/Component/Workflow/EventListener/GuardListener.php

+16-5
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,9 @@
1313

1414
use Symfony\Component\Security\Core\Authentication\AuthenticationTrustResolverInterface;
1515
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
16+
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
1617
use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface;
1718
use Symfony\Component\Security\Core\Role\Role;
18-
use Symfony\Component\Security\Core\Role\RoleHierarchy;
1919
use Symfony\Component\Security\Core\Role\RoleHierarchyInterface;
2020
use Symfony\Component\Validator\Validator\ValidatorInterface;
2121
use Symfony\Component\Workflow\Event\GuardEvent;
@@ -37,6 +37,10 @@ class GuardListener
3737

3838
public function __construct(array $configuration, ExpressionLanguage $expressionLanguage, TokenStorageInterface $tokenStorage, AuthorizationCheckerInterface $authorizationChecker, AuthenticationTrustResolverInterface $trustResolver, RoleHierarchyInterface $roleHierarchy = null, ValidatorInterface $validator = null)
3939
{
40+
if (null !== $roleHierarchy && !method_exists($roleHierarchy, 'getReachableRoleNames')) {
41+
@trigger_error(sprintf('Not implementing the getReachableRoleNames() method in %s which implements %s is deprecated since Symfony 4.3.', \get_class($roleHierarchy), RoleHierarchyInterface::class), E_USER_DEPRECATED);
42+
}
43+
4044
$this->configuration = $configuration;
4145
$this->expressionLanguage = $expressionLanguage;
4246
$this->tokenStorage = $tokenStorage;
@@ -83,22 +87,29 @@ private function getVariables(GuardEvent $event): array
8387
}
8488

8589
if (method_exists($token, 'getRoleNames')) {
86-
$roles = $token->getRoleNames();
90+
$roleNames = $token->getRoleNames();
91+
$roles = array_map(function (string $role) { return new Role($role, false); }, $roleNames);
8792
} else {
88-
$roles = array_map(function (Role $role) { return $role->getRole(); }, $token->getRoles(false));
93+
@trigger_error(sprintf('Not implementing the getRoleNames() method in %s which implements %s is deprecated since Symfony 4.3.', \get_class($token), TokenInterface::class), E_USER_DEPRECATED);
94+
95+
$roles = $token->getRoles(false);
96+
$roleNames = array_map(function (Role $role) { return $role->getRole(); }, $roles);
8997
}
9098

91-
if ($this->roleHierarchy instanceof RoleHierarchy) {
92-
$roles = $this->roleHierarchy->getReachableRoleNames($roles);
99+
if (null !== $this->roleHierarchy && method_exists($this->roleHierarchy, 'getReachableRoleNames')) {
100+
$roleNames = $this->roleHierarchy->getReachableRoleNames($roles);
101+
$roles = array_map(function (string $role) { return new Role($role, false); }, $roleNames);
93102
} elseif (null !== $this->roleHierarchy) {
94103
$roles = $this->roleHierarchy->getReachableRoles($token->getRoles(false));
104+
$roleNames = array_map(function (Role $role) { return $role->getRole(); }, $roles);
95105
}
96106

97107
$variables = [
98108
'token' => $token,
99109
'user' => $token->getUser(),
100110
'subject' => $event->getSubject(),
101111
'roles' => $roles,
112+
'role_names' => $roleNames,
102113
// needed for the is_granted expression function
103114
'auth_checker' => $this->authorizationChecker,
104115
// needed for the is_* expression function

0 commit comments

Comments
 (0)