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

Commit

Permalink
Ability to define multiple assertions in assertion map simpler way.
Browse files Browse the repository at this point in the history
  • Loading branch information
DavidHavl committed Oct 28, 2016
1 parent 0a3e9a7 commit d2a7e27
Show file tree
Hide file tree
Showing 5 changed files with 362 additions and 55 deletions.
72 changes: 41 additions & 31 deletions docs/06. Using the Authorization Service.md
Original file line number Diff line number Diff line change
Expand Up @@ -190,45 +190,55 @@ Now, every time you check for `myPermission`, `myAssertion` will be checked as w


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

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

If 'AND' condition is specified (this is default) all of the assertions in the set must pass the check.
If 'OR' condition is specified at least one of the assertions in the set must pass the check.
```php
return [
'zfc_rbac' => [
'assertion_map' => [
'myPermission' => 'myAssertion', // single assertion
'myPermission2' => [ // multiple assertions
'myAssertion',
'myAssertion2'
]
]
]
];
```

See the usage example here:
Or with an additional condition definition:

Create a factory for your assertion set.
```php
return [
'zfc_rbac' => [
'assertion_map' => [
// single assertion
'myPermission' => 'myAssertion',
'myPermission2' => [
// multiple assertions
'assertions' => [
'myAssertion',
'myAssertion2'
],
// condition
'condition' => \ZfcRbac\Assertion\AssertionSet::CONDITION_AND
]
]
]
];
```

use Zend\ServiceManager\FactoryInterface;
use Zend\ServiceManager\ServiceLocatorInterface;
use ZfcRbac\Assertion\AssertionSet;

class MyAssertionSetFactory implements FactoryInterface
{
/**
* {@inheritDoc}
* @return \ZfcRbac\Assertion\AssertionSet
*/
public function createService(ServiceLocatorInterface $serviceLocator)
{
$assertionManager = $serviceLocator->get('ZfcRbac\Assertion\AssertionPluginManager');
$assertion1 = $assertionManager->get('myAssertion1');
$assertion2 = $assertionManager->get('myAssertion2');

// create instance, set condition and add assertions
$assertionSet = new AssertionSet();
$assertionSet->setCondition(AssertionSet::CONDITION_OR);
$assertionSet->setAssertions([$assertion1, $assertion2]);
return $assertionSet;
}
}
If 'AND' condition is specified (this is default) all of the assertions must pass the check.
If 'OR' condition is specified at least one of the assertions must pass the check.
This in the background will create an instance of ZfcRbac\Assertion\AssertionSet and adds the given assertions to it.

```
### Assertion Set

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

This comment has been minimized.

Copy link
@svycka

svycka Oct 28, 2016

Contributor

but you can also extend the class or create your own instance containing your custom assertions and specify that in assertion map instead.

can you show how? You creating new AssertionSet in AuthorizationService, you suggesting extend AuthorizationService also?

and specify that in assertion map instead.

```php
return [
Expand Down
48 changes: 33 additions & 15 deletions src/ZfcRbac/Assertion/AssertionSet.php
Original file line number Diff line number Diff line change
Expand Up @@ -48,13 +48,11 @@ class AssertionSet implements AssertionInterface, \IteratorAggregate
/**
* Constructor.
*
* @param AssertionInterface[] $assertions An array of assertions.
* @param array|AssertionInterface[] $assertions An array of assertions.
*/
public function __construct(array $assertions = array())
{
foreach ($assertions as $name => $assertion) {
$this->setAssertion($assertion, is_int($name) ? null : $name);
}
$this->setAssertions($assertions);
}

/**
Expand All @@ -64,8 +62,24 @@ public function __construct(array $assertions = array())
*
* @return $this
*/
public function setAssertions($assertions)
public function setAssertions(array $assertions)
{
$this->assertions = [];

// if definition contains condition, set it.
if (isset($assertions['condition'])) {
if ($assertions['condition'] != self::CONDITION_AND && $assertions['condition'] != self::CONDITION_OR) {
throw new InvalidArgumentException('Invalid assertion condition given.');
}
$this->setCondition($assertions['condition']);
}

// if there are multiple assertions under a key 'assertions', get them.
if (isset($assertions['assertions']) && is_array($assertions['assertions'])) {
$assertions = $assertions['assertions'];
}

// set each assertion
foreach ($assertions as $name => $assertion) {
$this->setAssertion($assertion, is_int($name) ? null : $name);
}
Expand All @@ -75,19 +89,17 @@ public function setAssertions($assertions)
/**
* Set an assertion.
*
* @param AssertionInterface $assertion The assertion instance
*
* @param string $name A name/alias
*
* @param string|AssertionInterface $assertion The assertion instance or it's name
* @param string $name A name/alias
* @return $this
*/
public function setAssertion(AssertionInterface $assertion, $name = null)

This comment has been minimized.

Copy link
@basz

basz Oct 28, 2016

Collaborator

Update param phpdoc

{
if (null !== $name) {
$this->assertions[$name] = $assertion;
} else {
$this->assertions[] = $assertion;
}
$this->assertions[] = $assertion;
return $this;
}

/**
Expand Down Expand Up @@ -119,6 +131,16 @@ public function getAssertion($name)
return $this->assertions[$name];
}

/**
* Gets all assertions.
*
* @return AssertionInterface[] The assertion instance
*/
public function getAssertions()
{
return $this->assertions;
}

/**
* @return string
*/
Expand Down Expand Up @@ -175,9 +197,5 @@ public function assert(AuthorizationService $authorizationService, $context = nu
return false;
}

throw new InvalidArgumentException(sprintf(
'Condition must be either "AND" or "OR", %s given',
is_object($this->condition) ? get_class($this->condition) : gettype($this->condition)
));
}
}
35 changes: 29 additions & 6 deletions src/ZfcRbac/Service/AuthorizationService.php
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
use Rbac\Permission\PermissionInterface;
use ZfcRbac\Assertion\AssertionPluginManager;
use ZfcRbac\Assertion\AssertionInterface;
use ZfcRbac\Assertion\AssertionSet;
use ZfcRbac\Exception;
use ZfcRbac\Identity\IdentityInterface;

Expand Down Expand Up @@ -72,11 +73,34 @@ public function __construct(Rbac $rbac, RoleService $roleService, AssertionPlugi
* Set an assertion
*
* @param string|PermissionInterface $permission
* @param string|callable|AssertionInterface $assertion
* @param string|callable|array|AssertionInterface $assertion
* @return void
*/
public function setAssertion($permission, $assertion)
{
// if is name of the assertion, retrieve an actual instance from assertion plugin manager
if (is_string($assertion)) {
$assertion = $this->assertionPluginManager->get($assertion);
} else if (is_array($assertion)) { // else if multiple assertion definition, create assertion set.

// move assertion definition under a key 'assertions'.
if (!isset($assertion['assertions'])) {
$assertion['assertions'] = (array)$assertion;
} else if (!is_array($assertion['assertions'])) {
$assertion['assertions'] = (array)$assertion['assertions'];
}

// retrieve an actual instance from assertion plugin manager if necessary
foreach ($assertion['assertions'] as $key=>$value) {
if (is_string($value)) {
$assertion['assertions'][$key] = $this->assertionPluginManager->get($value);
}
}

// create assertion set
$assertion = new AssertionSet($assertion);
}

$this->assertions[(string) $permission] = $assertion;
}

Expand All @@ -88,7 +112,10 @@ public function setAssertion($permission, $assertion)
*/
public function setAssertions(array $assertions)
{
$this->assertions = $assertions;
$this->assertions = [];
foreach ($assertions as $permissionName => $assertionData) {
$this->setAssertion($permissionName, $assertionData);
}
}

/**
Expand Down Expand Up @@ -149,10 +176,6 @@ protected function assert($assertion, $context = null)
if (is_callable($assertion)) {
return $assertion($this, $context);
} elseif ($assertion instanceof AssertionInterface) {
return $assertion->assert($this, $context);
} elseif (is_string($assertion)) {
$assertion = $this->assertionPluginManager->get($assertion);

return $assertion->assert($this, $context);
}

Expand Down

0 comments on commit d2a7e27

Please sign in to comment.