Skip to content

Commit 64fd6bd

Browse files
committed
Rewrote logic of AbstractVoter
1 parent 869a937 commit 64fd6bd

File tree

5 files changed

+196
-5
lines changed

5 files changed

+196
-5
lines changed

UPGRADE-3.0.md

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -680,6 +680,43 @@ UPGRADE FROM 2.x to 3.0
680680
));
681681
```
682682

683+
* The `AbstractVoter::getSupportedAttributes()` and `AbstractVoter::getSupportedClasses()`
684+
methods have been removed in favor of `AbstractVoter::supports()`.
685+
686+
Before:
687+
688+
```php
689+
class MyVoter extends AbstractVoter
690+
{
691+
protected function getSupportedAttributes()
692+
{
693+
return array('CREATE', 'EDIT');
694+
}
695+
696+
protected function getSupportedClasses()
697+
{
698+
return array('AppBundle\Entity\Post');
699+
}
700+
701+
// ...
702+
}
703+
```
704+
705+
After:
706+
707+
```php
708+
class MyVoter extends AbstractVoter
709+
{
710+
protected function supports($attribute, $class)
711+
{
712+
return $this->isClassInstanceOf($class, 'AppBundle\Entity\Post')
713+
&& in_array($attribute, array('CREATE', 'EDIT'));
714+
}
715+
716+
// ...
717+
}
718+
```
719+
683720
### Translator
684721

685722
* The `Translator::setFallbackLocale()` method has been removed in favor of

src/Symfony/Component/Security/CHANGELOG.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,11 @@ CHANGELOG
1212
`Symfony\Component\Security\Http\Authentication\SimpleFormAuthenticatorInterface` instead
1313
* deprecated `Symfony\Component\Security\Core\Util\ClassUtils`, use
1414
`Symfony\Component\Security\Acl\Util\ClassUtils` instead
15-
* deprecated `supportsAttribute()` and `supportsClass()` attributes of
15+
* deprecated `supportsAttribute()` and `supportsClass()` methods of
1616
`Symfony\Component\Security\Core\Authorization\AccessDecisionManagerInterface` and
1717
`Symfony\Component\Security\Core\Authorization\Voter\VoterInterface`.
18+
* deprecated `getSupportedAttributes()` and `getSupportedClasses()` methods of
19+
`Symfony\Component\Security\Core\Authorization\Voter\AbstractVoter`, use `supports()` instead.
1820

1921
2.7.0
2022
-----

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

Lines changed: 67 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@ abstract class AbstractVoter implements VoterInterface
2626
*/
2727
public function supportsAttribute($attribute)
2828
{
29+
@trigger_error('The '.__METHOD__.' is deprecated since version 2.8 and will be removed in version 3.0.');
30+
2931
return in_array($attribute, $this->getSupportedAttributes());
3032
}
3133

@@ -34,6 +36,8 @@ public function supportsAttribute($attribute)
3436
*/
3537
public function supportsClass($class)
3638
{
39+
@trigger_error('The '.__METHOD__.' is deprecated since version 2.8 and will be removed in version 3.0.');
40+
3741
foreach ($this->getSupportedClasses() as $supportedClass) {
3842
if ($supportedClass === $class || is_subclass_of($class, $supportedClass)) {
3943
return true;
@@ -58,12 +62,13 @@ public function supportsClass($class)
5862
*/
5963
public function vote(TokenInterface $token, $object, array $attributes)
6064
{
61-
if (!$object || !$this->supportsClass(get_class($object))) {
65+
if (!$object) {
6266
return self::ACCESS_ABSTAIN;
6367
}
6468

6569
// abstain vote by default in case none of the attributes are supported
6670
$vote = self::ACCESS_ABSTAIN;
71+
$class = get_class($object);
6772

6873
$reflector = new \ReflectionMethod($this, 'voteOnAttribute');
6974
$isNewOverwritten = $reflector->getDeclaringClass()->getName() !== 'Symfony\Component\Security\Core\Authorization\Voter\AbstractVoter';
@@ -72,7 +77,7 @@ public function vote(TokenInterface $token, $object, array $attributes)
7277
}
7378

7479
foreach ($attributes as $attribute) {
75-
if (!$this->supportsAttribute($attribute)) {
80+
if (!$this->supports($attribute, $class)) {
7681
continue;
7782
}
7883

@@ -95,19 +100,77 @@ public function vote(TokenInterface $token, $object, array $attributes)
95100
return $vote;
96101
}
97102

103+
/**
104+
* Determines if the attribute and class are supported by this voter.
105+
*
106+
* To determine if the passed class is instance of the supported class, the
107+
* isClassInstanceOf() method can be used.
108+
*
109+
* @param string $attribute An attribute
110+
* @param string $class The fully qualified class name of the passed object
111+
*
112+
* @return bool True if the attribute and class is supported, false otherwise
113+
*/
114+
protected function supports($attribute, $class)
115+
{
116+
@trigger_error('The getSupportedClasses and getSupportedAttributes methods are deprecated since version 2.8 and will be removed in version 3.0. Overwrite supports instead.');
117+
118+
$classIsSupported = false;
119+
foreach ($this->getSupportedClasses() as $supportedClass) {
120+
if ($this->isClassInstanceOf($class, $supportedClass)) {
121+
$classIsSupported = true;
122+
break;
123+
}
124+
}
125+
126+
if (!$classIsSupported) {
127+
return false;
128+
}
129+
130+
if (!in_array($attribute, $this->getSupportedAttributes())) {
131+
return false;
132+
}
133+
134+
return true;
135+
}
136+
137+
/**
138+
* A helper method to test if the actual class is instanceof or equal
139+
* to the expected class.
140+
*
141+
* @param string $actualClass The actual class name
142+
* @param string $expectedClass The expected class name
143+
*
144+
* @return bool
145+
*/
146+
protected function isClassInstanceOf($actualClass, $expectedClass)
147+
{
148+
return $expectedClass === $actualClass || is_subclass_of($actualClass, $expectedClass);
149+
}
150+
98151
/**
99152
* Return an array of supported classes. This will be called by supportsClass.
100153
*
101154
* @return array an array of supported classes, i.e. array('Acme\DemoBundle\Model\Product')
155+
*
156+
* @deprecated since version 2.8, to be removed in 3.0. Use supports() instead.
102157
*/
103-
abstract protected function getSupportedClasses();
158+
protected function getSupportedClasses()
159+
{
160+
@trigger_error('The '.__METHOD__.' is deprecated since version 2.8 and will be removed in version 3.0.');
161+
}
104162

105163
/**
106164
* Return an array of supported attributes. This will be called by supportsAttribute.
107165
*
108166
* @return array an array of supported attributes, i.e. array('CREATE', 'READ')
167+
*
168+
* @deprecated since version 2.8, to be removed in 3.0. Use supports() instead.
109169
*/
110-
abstract protected function getSupportedAttributes();
170+
protected function getSupportedAttributes()
171+
{
172+
@trigger_error('The '.__METHOD__.' is deprecated since version 2.8 and will be removed in version 3.0.');
173+
}
111174

112175
/**
113176
* Perform a single access check operation on a given attribute, object and (optionally) user
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
<?php
2+
3+
namespace Symfony\Component\Security\Core\Tests\Authorization\Voter;
4+
5+
use Symfony\Component\Security\Core\Authorization\Voter\AbstractVoter;
6+
use Symfony\Component\Security\Core\Authorization\Voter\VoterInterface;
7+
8+
class AbstractVoterTest_Voter extends AbstractVoter
9+
{
10+
protected function isGranted($attribute, $object, $user = null)
11+
{
12+
return 'EDIT' === $attribute;
13+
}
14+
15+
protected function supports($attribute, $class)
16+
{
17+
return $this->isClassInstanceOf($class, 'AbstractVoterTest_Object')
18+
&& in_array($attribute, array('EDIT', 'CREATE'));
19+
}
20+
}
21+
22+
class AbstractVoterTest extends \PHPUnit_Framework_TestCase
23+
{
24+
protected $voter;
25+
protected $object;
26+
protected $token;
27+
28+
protected function setUp()
29+
{
30+
$this->voter = new AbstractVoterTest_Voter();
31+
$this->object = $this->getMock('AbstractVoterTest_Object');
32+
$this->token = $this->getMock('Symfony\Component\Security\Core\Authentication\Token\TokenInterface');
33+
}
34+
35+
public function testAttributeAndClassSupported()
36+
{
37+
$this->assertEquals(VoterInterface::ACCESS_GRANTED, $this->voter->vote($this->token, $this->object, array('EDIT')));
38+
$this->assertEquals(VoterInterface::ACCESS_DENIED, $this->voter->vote($this->token, $this->object, array('CREATE')));
39+
}
40+
41+
public function testAttributeNotSupported()
42+
{
43+
$this->assertEquals(VoterInterface::ACCESS_ABSTAIN, $this->voter->vote($this->token, $this->object, array('DELETE')));
44+
}
45+
46+
public function testOneAttributeSupported()
47+
{
48+
$this->assertEquals(VoterInterface::ACCESS_GRANTED, $this->voter->vote($this->token, $this->object, array('DELETE', 'EDIT')));
49+
$this->assertEquals(VoterInterface::ACCESS_DENIED, $this->voter->vote($this->token, $this->object, array('DELETE', 'CREATE')));
50+
}
51+
52+
public function testClassNotSupported()
53+
{
54+
$this->assertEquals(VoterInterface::ACCESS_ABSTAIN, $this->voter->vote($this->token, $this->getMock('AbstractVoterTest_Object1'), array('EDIT')));
55+
}
56+
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
<?php
2+
3+
namespace Symfony\Component\Security\Core\Tests\Authorization\Voter;
4+
5+
use Symfony\Component\Security\Core\Authorization\Voter\AbstractVoter;
6+
7+
class LegacyAbstractVoterTest_Voter extends AbstractVoter
8+
{
9+
protected function getSupportedClasses()
10+
{
11+
return array('AbstractVoterTest_Object');
12+
}
13+
14+
protected function getSupportedAttributes()
15+
{
16+
return array('EDIT', 'CREATE');
17+
}
18+
19+
protected function isGranted($attribute, $object, $user = null)
20+
{
21+
return 'EDIT' === $attribute;
22+
}
23+
}
24+
25+
class LegacyAbstractVoterTest extends AbstractVoterTest
26+
{
27+
protected function setUp()
28+
{
29+
parent::setUp();
30+
31+
$this->voter = new LegacyAbstractVoterTest_Voter();
32+
}
33+
}

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy