Skip to content
This repository was archived by the owner on Jul 3, 2020. It is now read-only.

Commit d2a7e27

Browse files
committed
Ability to define multiple assertions in assertion map simpler way.
1 parent 0a3e9a7 commit d2a7e27

File tree

5 files changed

+362
-55
lines changed

5 files changed

+362
-55
lines changed

docs/06. Using the Authorization Service.md

Lines changed: 41 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -190,45 +190,55 @@ Now, every time you check for `myPermission`, `myAssertion` will be checked as w
190190

191191

192192
### Multiple assertions
193-
For convenience you can create instance of ZfcRbac\Assertion\AssertionSet class that can hold multiple assertions as well as specify condition for the check.
194193

195-
There are 2 conditions AND and OR.
194+
The assertion map also accepts multiple assertions as a simple array:
196195

197-
If 'AND' condition is specified (this is default) all of the assertions in the set must pass the check.
198-
If 'OR' condition is specified at least one of the assertions in the set must pass the check.
196+
```php
197+
return [
198+
'zfc_rbac' => [
199+
'assertion_map' => [
200+
'myPermission' => 'myAssertion', // single assertion
201+
'myPermission2' => [ // multiple assertions
202+
'myAssertion',
203+
'myAssertion2'
204+
]
205+
]
206+
]
207+
];
208+
```
199209

200-
See the usage example here:
210+
Or with an additional condition definition:
201211

202-
Create a factory for your assertion set.
203212
```php
213+
return [
214+
'zfc_rbac' => [
215+
'assertion_map' => [
216+
// single assertion
217+
'myPermission' => 'myAssertion',
218+
'myPermission2' => [
219+
// multiple assertions
220+
'assertions' => [
221+
'myAssertion',
222+
'myAssertion2'
223+
],
224+
// condition
225+
'condition' => \ZfcRbac\Assertion\AssertionSet::CONDITION_AND
226+
]
227+
]
228+
]
229+
];
230+
```
204231

205-
use Zend\ServiceManager\FactoryInterface;
206-
use Zend\ServiceManager\ServiceLocatorInterface;
207-
use ZfcRbac\Assertion\AssertionSet;
208-
209-
class MyAssertionSetFactory implements FactoryInterface
210-
{
211-
/**
212-
* {@inheritDoc}
213-
* @return \ZfcRbac\Assertion\AssertionSet
214-
*/
215-
public function createService(ServiceLocatorInterface $serviceLocator)
216-
{
217-
$assertionManager = $serviceLocator->get('ZfcRbac\Assertion\AssertionPluginManager');
218-
$assertion1 = $assertionManager->get('myAssertion1');
219-
$assertion2 = $assertionManager->get('myAssertion2');
220-
221-
// create instance, set condition and add assertions
222-
$assertionSet = new AssertionSet();
223-
$assertionSet->setCondition(AssertionSet::CONDITION_OR);
224-
$assertionSet->setAssertions([$assertion1, $assertion2]);
225-
return $assertionSet;
226-
}
227-
}
232+
If 'AND' condition is specified (this is default) all of the assertions must pass the check.
233+
If 'OR' condition is specified at least one of the assertions must pass the check.
234+
This in the background will create an instance of ZfcRbac\Assertion\AssertionSet and adds the given assertions to it.
228235

229-
```
236+
### Assertion Set
230237

231-
Add it to assertion manager and then add it to assertion map:
238+
ZfcRbac\Assertion\AssertionSet class is basically a container for multiple assertions as well as assertion condition.
239+
An instance of the class get's actually created automatically when you specify multiple assertions (see above)
240+
in the background, but you can also extend the class or create your own instance containing your custom assertions
241+
and specify that in assertion map instead.
232242

233243
```php
234244
return [

src/ZfcRbac/Assertion/AssertionSet.php

Lines changed: 33 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -48,13 +48,11 @@ class AssertionSet implements AssertionInterface, \IteratorAggregate
4848
/**
4949
* Constructor.
5050
*
51-
* @param AssertionInterface[] $assertions An array of assertions.
51+
* @param array|AssertionInterface[] $assertions An array of assertions.
5252
*/
5353
public function __construct(array $assertions = array())
5454
{
55-
foreach ($assertions as $name => $assertion) {
56-
$this->setAssertion($assertion, is_int($name) ? null : $name);
57-
}
55+
$this->setAssertions($assertions);
5856
}
5957

6058
/**
@@ -64,8 +62,24 @@ public function __construct(array $assertions = array())
6462
*
6563
* @return $this
6664
*/
67-
public function setAssertions($assertions)
65+
public function setAssertions(array $assertions)
6866
{
67+
$this->assertions = [];
68+
69+
// if definition contains condition, set it.
70+
if (isset($assertions['condition'])) {
71+
if ($assertions['condition'] != self::CONDITION_AND && $assertions['condition'] != self::CONDITION_OR) {
72+
throw new InvalidArgumentException('Invalid assertion condition given.');
73+
}
74+
$this->setCondition($assertions['condition']);
75+
}
76+
77+
// if there are multiple assertions under a key 'assertions', get them.
78+
if (isset($assertions['assertions']) && is_array($assertions['assertions'])) {
79+
$assertions = $assertions['assertions'];
80+
}
81+
82+
// set each assertion
6983
foreach ($assertions as $name => $assertion) {
7084
$this->setAssertion($assertion, is_int($name) ? null : $name);
7185
}
@@ -75,19 +89,17 @@ public function setAssertions($assertions)
7589
/**
7690
* Set an assertion.
7791
*
78-
* @param AssertionInterface $assertion The assertion instance
79-
*
80-
* @param string $name A name/alias
81-
*
92+
* @param string|AssertionInterface $assertion The assertion instance or it's name
93+
* @param string $name A name/alias
8294
* @return $this
8395
*/
8496
public function setAssertion(AssertionInterface $assertion, $name = null)
8597
{
8698
if (null !== $name) {
8799
$this->assertions[$name] = $assertion;
100+
} else {
101+
$this->assertions[] = $assertion;
88102
}
89-
$this->assertions[] = $assertion;
90-
return $this;
91103
}
92104

93105
/**
@@ -119,6 +131,16 @@ public function getAssertion($name)
119131
return $this->assertions[$name];
120132
}
121133

134+
/**
135+
* Gets all assertions.
136+
*
137+
* @return AssertionInterface[] The assertion instance
138+
*/
139+
public function getAssertions()
140+
{
141+
return $this->assertions;
142+
}
143+
122144
/**
123145
* @return string
124146
*/
@@ -175,9 +197,5 @@ public function assert(AuthorizationService $authorizationService, $context = nu
175197
return false;
176198
}
177199

178-
throw new InvalidArgumentException(sprintf(
179-
'Condition must be either "AND" or "OR", %s given',
180-
is_object($this->condition) ? get_class($this->condition) : gettype($this->condition)
181-
));
182200
}
183201
}

src/ZfcRbac/Service/AuthorizationService.php

Lines changed: 29 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
use Rbac\Permission\PermissionInterface;
2323
use ZfcRbac\Assertion\AssertionPluginManager;
2424
use ZfcRbac\Assertion\AssertionInterface;
25+
use ZfcRbac\Assertion\AssertionSet;
2526
use ZfcRbac\Exception;
2627
use ZfcRbac\Identity\IdentityInterface;
2728

@@ -72,11 +73,34 @@ public function __construct(Rbac $rbac, RoleService $roleService, AssertionPlugi
7273
* Set an assertion
7374
*
7475
* @param string|PermissionInterface $permission
75-
* @param string|callable|AssertionInterface $assertion
76+
* @param string|callable|array|AssertionInterface $assertion
7677
* @return void
7778
*/
7879
public function setAssertion($permission, $assertion)
7980
{
81+
// if is name of the assertion, retrieve an actual instance from assertion plugin manager
82+
if (is_string($assertion)) {
83+
$assertion = $this->assertionPluginManager->get($assertion);
84+
} else if (is_array($assertion)) { // else if multiple assertion definition, create assertion set.
85+
86+
// move assertion definition under a key 'assertions'.
87+
if (!isset($assertion['assertions'])) {
88+
$assertion['assertions'] = (array)$assertion;
89+
} else if (!is_array($assertion['assertions'])) {
90+
$assertion['assertions'] = (array)$assertion['assertions'];
91+
}
92+
93+
// retrieve an actual instance from assertion plugin manager if necessary
94+
foreach ($assertion['assertions'] as $key=>$value) {
95+
if (is_string($value)) {
96+
$assertion['assertions'][$key] = $this->assertionPluginManager->get($value);
97+
}
98+
}
99+
100+
// create assertion set
101+
$assertion = new AssertionSet($assertion);
102+
}
103+
80104
$this->assertions[(string) $permission] = $assertion;
81105
}
82106

@@ -88,7 +112,10 @@ public function setAssertion($permission, $assertion)
88112
*/
89113
public function setAssertions(array $assertions)
90114
{
91-
$this->assertions = $assertions;
115+
$this->assertions = [];
116+
foreach ($assertions as $permissionName => $assertionData) {
117+
$this->setAssertion($permissionName, $assertionData);
118+
}
92119
}
93120

94121
/**
@@ -149,10 +176,6 @@ protected function assert($assertion, $context = null)
149176
if (is_callable($assertion)) {
150177
return $assertion($this, $context);
151178
} elseif ($assertion instanceof AssertionInterface) {
152-
return $assertion->assert($this, $context);
153-
} elseif (is_string($assertion)) {
154-
$assertion = $this->assertionPluginManager->get($assertion);
155-
156179
return $assertion->assert($this, $context);
157180
}
158181

0 commit comments

Comments
 (0)