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

Commit

Permalink
Rewrite of AssertionSet and moved dynamic creation of AssertionSet to…
Browse files Browse the repository at this point in the history
… assert method of AuthorizationService.
  • Loading branch information
DavidHavl committed Oct 29, 2016
1 parent c695e41 commit 47e17f8
Show file tree
Hide file tree
Showing 5 changed files with 365 additions and 334 deletions.
55 changes: 54 additions & 1 deletion docs/06. Using the Authorization Service.md
Original file line number Diff line number Diff line change
Expand Up @@ -237,9 +237,62 @@ This in the background will create an instance of ZfcRbac\Assertion\AssertionSet

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
in the background, but you can also create your own instance containing your custom assertions
and specify that in assertion map instead.

So you can create a factory for your assertion set like this for example:

```php

use Interop\Container\ContainerInterface;
use Zend\ServiceManager\FactoryInterface;
use Zend\ServiceManager\ServiceLocatorInterface;
use ZfcRbac\Assertion\AssertionSet;

class MyAssertionSetFactory implements FactoryInterface
{
/**
* {@inheritDoc}
*
* @return AssertionSet
*/
public function __invoke(ContainerInterface $container, $name, array $options = null)
{
$assertionManager = $container->get('ZfcRbac\Assertion\AssertionPluginManager');
$assertion1 = $assertionManager->get('myAssertion1');
$assertion2 = $assertionManager->get('myAssertion2');

// create instance, set condition and add assertions
$assertionSet = new AssertionSet([
'assertions' => [$assertion1, $assertion2],
'condition' => AssertionSet::CONDITION_OR
]);
return $assertionSet;
}

/**
* {@inheritDoc}
*
* For use with zend-servicemanager v2; proxies to __invoke().
*
* @param ServiceLocatorInterface $container
* @return \ZfcRbac\Assertion\AssertionSet
*/
public function createService(ServiceLocatorInterface $container)
{
// Retrieve the parent container when under zend-servicemanager v2
if (method_exists($container, 'getServiceLocator')) {
$container = $container->getServiceLocator() ?: $container;
}

return $this($container, AssertionSet::class);
}
}

```

And then add it to assertion manager and assertion map config:

```php
return [
'zfc_rbac' => [
Expand Down
120 changes: 14 additions & 106 deletions src/ZfcRbac/Assertion/AssertionSet.php
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,7 @@
* @author David Havl
* @licence MIT
*/

class AssertionSet implements AssertionInterface, \IteratorAggregate
class AssertionSet implements AssertionInterface
{
/**
* Condition constants
Expand All @@ -51,121 +50,29 @@ class AssertionSet implements AssertionInterface, \IteratorAggregate
* @param array|AssertionInterface[] $assertions An array of assertions.
*/
public function __construct(array $assertions = array())
{
$this->setAssertions($assertions);
}

/**
* Set assertions.
*
* @param AssertionInterface[] $assertions The assertions to set
*
* @return $this
*/
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) {
if ($assertions['condition'] != AssertionSet::CONDITION_AND
&& $assertions['condition'] != AssertionSet::CONDITION_OR) {
throw new InvalidArgumentException('Invalid assertion condition given.');
}
$this->setCondition($assertions['condition']);
$this->condition = $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);
}
return $this;
}

/**
* Set an assertion.
*
* @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)
{
if (null !== $name) {
$this->assertions[$name] = $assertion;
} else {
$this->assertions[] = $assertion;
}
}

/**
* Returns true if the assertion if defined.
*
* @param string $name The assertion name
*
* @return bool true if the assertion is defined, false otherwise
*/
public function hasAssertion($name)
{
return isset($this->assertions[$name]);
}

/**
* Gets a assertion value.
*
* @param string $name The assertion name
*
* @return AssertionInterface The assertion instance
*
* @throws InvalidArgumentException if the assertion is not defined
*/
public function getAssertion($name)
{
if (!$this->hasAssertion($name)) {
throw new InvalidArgumentException(sprintf('The assertion "%s" is not defined.', $name));
if (is_int($name)) {
$this->assertions[] = $assertion;
} else {
$this->assertions[$name] = $assertion;
}
}
return $this->assertions[$name];
}

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

/**
* @return string
*/
public function getCondition()
{
return $this->condition;
}

/**
* Set condition
*
* @param string $condition
*/
public function setCondition($condition)
{
$this->condition = $condition;
}

/**
* Retrieve an external iterator
* @return \ArrayIterator
*/
public function getIterator()
{
return new \ArrayIterator($this->assertions);
}

/**
Expand All @@ -177,6 +84,10 @@ public function getIterator()
*/
public function assert(AuthorizationService $authorizationService, $context = null)
{
if (empty($this->assertions)) {
return true;
}

if (AssertionSet::CONDITION_AND === $this->condition) {
foreach ($this->assertions as $assertion) {
if (!$assertion->assert($authorizationService, $context)) {
Expand All @@ -197,9 +108,6 @@ 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)
));
return false;
}
}
55 changes: 24 additions & 31 deletions src/ZfcRbac/Service/AuthorizationService.php
Original file line number Diff line number Diff line change
Expand Up @@ -78,31 +78,6 @@ public function __construct(Rbac $rbac, RoleService $roleService, AssertionPlugi
*/
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);
} elseif (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;
}

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 @@ -114,10 +89,7 @@ public function setAssertion($permission, $assertion)
*/
public function setAssertions(array $assertions)
{
$this->assertions = [];
foreach ($assertions as $permissionName => $assertionData) {
$this->setAssertion($permissionName, $assertionData);
}
$this->assertions = $assertions;
}

/**
Expand Down Expand Up @@ -168,8 +140,8 @@ public function isGranted($permission, $context = null)
}

/**
* @param string|callable|AssertionInterface $assertion
* @param mixed $context
* @param string|callable|array|AssertionInterface $assertion
* @param mixed $context
* @return bool
* @throws Exception\InvalidArgumentException If an invalid assertion is passed
*/
Expand All @@ -179,6 +151,27 @@ protected function assert($assertion, $context = null)
return $assertion($this, $context);
} elseif ($assertion instanceof AssertionInterface) {
return $assertion->assert($this, $context);
} elseif (is_string($assertion)) { // retrieve an actual instance from assertion plugin manager
$assertion = $this->assertionPluginManager->get($assertion);
return $assertion->assert($this, $context);
} elseif (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;
}
// convert to an array
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);
return $assertion->assert($this, $context);
}

throw new Exception\InvalidArgumentException(sprintf(
Expand Down
Loading

0 comments on commit 47e17f8

Please sign in to comment.