diff --git a/.travis.yml b/.travis.yml index 9b5b4872..b89c98ee 100644 --- a/.travis.yml +++ b/.travis.yml @@ -18,37 +18,17 @@ env: matrix: include: - - php: 5.6 - env: - - DEPS=lowest - - php: 5.6 - env: - - DEPS=locked - - LEGACY_DEPS="phpunit/phpunit" - - php: 5.6 - env: - - DEPS=latest - - TEST_COVERAGE=true - - php: 7 - env: - - DEPS=lowest - - php: 7 - env: - - DEPS=locked - - LEGACY_DEPS="phpunit/phpunit" - - CHECK_CS=true - - php: 7 - env: - - DEPS=latest - php: 7.1 env: - DEPS=lowest - php: 7.1 env: - DEPS=locked + - CHECK_CS=true - php: 7.1 env: - DEPS=latest + - TEST_COVERAGE=true - php: 7.2 env: - DEPS=lowest diff --git a/CHANGELOG.md b/CHANGELOG.md index 7f695262..5b58d2ba 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,49 +2,59 @@ All notable changes to this project will be documented in this file, in reverse chronological order by release. -## 2.7.0 - TBD +## 3.0.0 - TBD ### Added -- Nothing. +- [#34](https://github.com/zendframework/zend-permissions-rbac/pull/34) adds + checks for circular references in the role hierarchy when using the + `Role::addChild()` and `Role::addParent()` methods. ### Changed -- Nothing. - -### Deprecated - -- Nothing. - -### Removed - -- Nothing. - -### Fixed +- [#34](https://github.com/zendframework/zend-permissions-rbac/pull/34) updates + the `Role::addChild(RoleInterface $child)` method to accept only a `RoleInterface` parameter; + strings are no longer accepted. -- Nothing. +- [#34](https://github.com/zendframework/zend-permissions-rbac/pull/34) updates + the `Zend\Permissions\Rbac\AssertionInterface`, adding two parameters to the + `assert()` definition and defining a return type, so that it now reads as + follows: -## 2.6.1 - TBD + ```php + public function assert( + Rbac $rbac, + RoleInterface $role, + string $permission + ) : bool + ``` -### Added +### Deprecated - Nothing. -### Changed - -- Nothing. +### Removed -### Deprecated +- [#34](https://github.com/zendframework/zend-permissions-rbac/pull/34) removes + support for PHP versions prior to 7.1. -- Nothing. +- [#34](https://github.com/zendframework/zend-permissions-rbac/pull/34) removes + the [AbstractIterator](https://github.com/zendframework/zend-permissions-rbac/blob/release-2.6.0/src/AbstractIterator.php) + class. The role hierarchy no longer relies on a `RecursiveIterator`. -### Removed +- [#34](https://github.com/zendframework/zend-permissions-rbac/pull/34) removes + the [AbstractRole](https://github.com/zendframework/zend-permissions-rbac/blob/release-2.6.0/src/AbstractRole.php) + class. All its functions have been merged to the `Zend\Permissions\Rbac\Role` + class. -- Nothing. +- [#34](https://github.com/zendframework/zend-permissions-rbac/pull/34) removes + the method `Role::setParent()`; use `Role::addParent()` instead. ### Fixed -- Nothing. +- [#30](https://github.com/zendframework/zend-permissions-rbac/issues/30) fixes + circular references within the `Role::addChild()` and `Role::addParent()` + algorithms. ## 2.6.0 - 2018-02-01 diff --git a/LICENSE.md b/LICENSE.md index dbb1b49c..67c914a6 100644 --- a/LICENSE.md +++ b/LICENSE.md @@ -1,4 +1,4 @@ -Copyright (c) 2005-2015, Zend Technologies USA, Inc. +Copyright (c) 2005-2018, Zend Technologies USA, Inc. All rights reserved. diff --git a/README.md b/README.md index 958d7b95..a1a49be4 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,8 @@ [](https://secure.travis-ci.org/zendframework/zend-permissions-rbac) [](https://coveralls.io/r/zendframework/zend-permissions-rbac?branch=master) -Provides role-based access control (RBAC) permissions management. +Provides [Role-Based Access Control](https://it.wikipedia.org/wiki/Role-based_access_control) +(RBAC) permissions management. -- File issues at https://github.com/zendframework/zend-permissions-rbac -- Documentation is at https://zendframework.github.io/zend-permissions-rbac/ +- File issues at https://github.com/zendframework/zend-permissions-rbac/issues +- Documentation is at https://docs.zendframework.com/zend-permissions-rbac/ diff --git a/composer.json b/composer.json index d9ed34ac..ee4a597f 100644 --- a/composer.json +++ b/composer.json @@ -1,10 +1,12 @@ { "name": "zendframework/zend-permissions-rbac", - "description": "provides a role-based access control management", + "description": "Provides a role-based access control management", "license": "BSD-3-Clause", "keywords": [ - "zf2", - "Rbac" + "zendframework", + "zend-permssions-rbac", + "rbac", + "authorization" ], "homepage": "https://github.com/zendframework/zend-permissions-rbac", "autoload": { @@ -13,7 +15,7 @@ } }, "require": { - "php": "^5.6 || ^7.0" + "php": "^7.1" }, "minimum-stability": "dev", "prefer-stable": true, @@ -29,7 +31,7 @@ } }, "require-dev": { - "phpunit/phpunit": "^5.7.15|| ^6.2.1", + "phpunit/phpunit": "^7.0.1", "zendframework/zend-coding-standard": "~1.0.0" }, "scripts": { diff --git a/composer.lock b/composer.lock index dac7565f..e27fe4d8 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", "This file is @generated automatically" ], - "content-hash": "2daefbdcd3df58ce5d4db6cd1e272273", + "content-hash": "60dda7c6ebcec6ecc57fe765479fd341", "packages": [], "packages-dev": [ { @@ -362,16 +362,16 @@ }, { "name": "phpspec/prophecy", - "version": "1.7.3", + "version": "1.7.5", "source": { "type": "git", "url": "https://github.com/phpspec/prophecy.git", - "reference": "e4ed002c67da8eceb0eb8ddb8b3847bb53c5c2bf" + "reference": "dfd6be44111a7c41c2e884a336cc4f461b3b2401" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpspec/prophecy/zipball/e4ed002c67da8eceb0eb8ddb8b3847bb53c5c2bf", - "reference": "e4ed002c67da8eceb0eb8ddb8b3847bb53c5c2bf", + "url": "https://api.github.com/repos/phpspec/prophecy/zipball/dfd6be44111a7c41c2e884a336cc4f461b3b2401", + "reference": "dfd6be44111a7c41c2e884a336cc4f461b3b2401", "shasum": "" }, "require": { @@ -383,7 +383,7 @@ }, "require-dev": { "phpspec/phpspec": "^2.5|^3.2", - "phpunit/phpunit": "^4.8.35 || ^5.7" + "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.5" }, "type": "library", "extra": { @@ -421,44 +421,44 @@ "spy", "stub" ], - "time": "2017-11-24T13:59:53+00:00" + "time": "2018-02-19T10:16:54+00:00" }, { "name": "phpunit/php-code-coverage", - "version": "5.3.0", + "version": "6.0.1", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-code-coverage.git", - "reference": "661f34d0bd3f1a7225ef491a70a020ad23a057a1" + "reference": "f8ca4b604baf23dab89d87773c28cc07405189ba" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/661f34d0bd3f1a7225ef491a70a020ad23a057a1", - "reference": "661f34d0bd3f1a7225ef491a70a020ad23a057a1", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/f8ca4b604baf23dab89d87773c28cc07405189ba", + "reference": "f8ca4b604baf23dab89d87773c28cc07405189ba", "shasum": "" }, "require": { "ext-dom": "*", "ext-xmlwriter": "*", - "php": "^7.0", + "php": "^7.1", "phpunit/php-file-iterator": "^1.4.2", "phpunit/php-text-template": "^1.2.1", - "phpunit/php-token-stream": "^2.0.1", + "phpunit/php-token-stream": "^3.0", "sebastian/code-unit-reverse-lookup": "^1.0.1", "sebastian/environment": "^3.0", "sebastian/version": "^2.0.1", "theseer/tokenizer": "^1.1" }, "require-dev": { - "phpunit/phpunit": "^6.0" + "phpunit/phpunit": "^7.0" }, "suggest": { - "ext-xdebug": "^2.5.5" + "ext-xdebug": "^2.6.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "5.3.x-dev" + "dev-master": "6.0-dev" } }, "autoload": { @@ -484,7 +484,7 @@ "testing", "xunit" ], - "time": "2017-12-06T09:29:45+00:00" + "time": "2018-02-02T07:01:41+00:00" }, { "name": "phpunit/php-file-iterator", @@ -576,28 +576,28 @@ }, { "name": "phpunit/php-timer", - "version": "1.0.9", + "version": "2.0.0", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-timer.git", - "reference": "3dcf38ca72b158baf0bc245e9184d3fdffa9c46f" + "reference": "8b8454ea6958c3dee38453d3bd571e023108c91f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/3dcf38ca72b158baf0bc245e9184d3fdffa9c46f", - "reference": "3dcf38ca72b158baf0bc245e9184d3fdffa9c46f", + "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/8b8454ea6958c3dee38453d3bd571e023108c91f", + "reference": "8b8454ea6958c3dee38453d3bd571e023108c91f", "shasum": "" }, "require": { - "php": "^5.3.3 || ^7.0" + "php": "^7.1" }, "require-dev": { - "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.0" + "phpunit/phpunit": "^7.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.0-dev" + "dev-master": "2.0-dev" } }, "autoload": { @@ -612,7 +612,7 @@ "authors": [ { "name": "Sebastian Bergmann", - "email": "sb@sebastian-bergmann.de", + "email": "sebastian@phpunit.de", "role": "lead" } ], @@ -621,33 +621,33 @@ "keywords": [ "timer" ], - "time": "2017-02-26T11:10:40+00:00" + "time": "2018-02-01T13:07:23+00:00" }, { "name": "phpunit/php-token-stream", - "version": "2.0.2", + "version": "3.0.0", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-token-stream.git", - "reference": "791198a2c6254db10131eecfe8c06670700904db" + "reference": "21ad88bbba7c3d93530d93994e0a33cd45f02ace" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/791198a2c6254db10131eecfe8c06670700904db", - "reference": "791198a2c6254db10131eecfe8c06670700904db", + "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/21ad88bbba7c3d93530d93994e0a33cd45f02ace", + "reference": "21ad88bbba7c3d93530d93994e0a33cd45f02ace", "shasum": "" }, "require": { "ext-tokenizer": "*", - "php": "^7.0" + "php": "^7.1" }, "require-dev": { - "phpunit/phpunit": "^6.2.4" + "phpunit/phpunit": "^7.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "2.0-dev" + "dev-master": "3.0-dev" } }, "autoload": { @@ -670,20 +670,20 @@ "keywords": [ "tokenizer" ], - "time": "2017-11-27T05:48:46+00:00" + "time": "2018-02-01T13:16:43+00:00" }, { "name": "phpunit/phpunit", - "version": "6.5.5", + "version": "7.0.2", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "83d27937a310f2984fd575686138597147bdc7df" + "reference": "e2f8aa21bc54b6ba218bdd4f9e0dac1e9bc3b4e9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/83d27937a310f2984fd575686138597147bdc7df", - "reference": "83d27937a310f2984fd575686138597147bdc7df", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/e2f8aa21bc54b6ba218bdd4f9e0dac1e9bc3b4e9", + "reference": "e2f8aa21bc54b6ba218bdd4f9e0dac1e9bc3b4e9", "shasum": "" }, "require": { @@ -695,15 +695,15 @@ "myclabs/deep-copy": "^1.6.1", "phar-io/manifest": "^1.0.1", "phar-io/version": "^1.0", - "php": "^7.0", + "php": "^7.1", "phpspec/prophecy": "^1.7", - "phpunit/php-code-coverage": "^5.3", + "phpunit/php-code-coverage": "^6.0", "phpunit/php-file-iterator": "^1.4.3", "phpunit/php-text-template": "^1.2.1", - "phpunit/php-timer": "^1.0.9", - "phpunit/phpunit-mock-objects": "^5.0.5", + "phpunit/php-timer": "^2.0", + "phpunit/phpunit-mock-objects": "^6.0", "sebastian/comparator": "^2.1", - "sebastian/diff": "^2.0", + "sebastian/diff": "^3.0", "sebastian/environment": "^3.1", "sebastian/exporter": "^3.1", "sebastian/global-state": "^2.0", @@ -711,16 +711,12 @@ "sebastian/resource-operations": "^1.0", "sebastian/version": "^2.0.1" }, - "conflict": { - "phpdocumentor/reflection-docblock": "3.0.2", - "phpunit/dbunit": "<3.0" - }, "require-dev": { "ext-pdo": "*" }, "suggest": { "ext-xdebug": "*", - "phpunit/php-invoker": "^1.1" + "phpunit/php-invoker": "^2.0" }, "bin": [ "phpunit" @@ -728,7 +724,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "6.5.x-dev" + "dev-master": "7.0-dev" } }, "autoload": { @@ -754,33 +750,30 @@ "testing", "xunit" ], - "time": "2017-12-17T06:31:19+00:00" + "time": "2018-02-26T07:03:12+00:00" }, { "name": "phpunit/phpunit-mock-objects", - "version": "5.0.6", + "version": "6.0.1", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit-mock-objects.git", - "reference": "33fd41a76e746b8fa96d00b49a23dadfa8334cdf" + "reference": "e3249dedc2d99259ccae6affbc2684eac37c2e53" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit-mock-objects/zipball/33fd41a76e746b8fa96d00b49a23dadfa8334cdf", - "reference": "33fd41a76e746b8fa96d00b49a23dadfa8334cdf", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit-mock-objects/zipball/e3249dedc2d99259ccae6affbc2684eac37c2e53", + "reference": "e3249dedc2d99259ccae6affbc2684eac37c2e53", "shasum": "" }, "require": { "doctrine/instantiator": "^1.0.5", - "php": "^7.0", + "php": "^7.1", "phpunit/php-text-template": "^1.2.1", "sebastian/exporter": "^3.1" }, - "conflict": { - "phpunit/phpunit": "<6.0" - }, "require-dev": { - "phpunit/phpunit": "^6.5" + "phpunit/phpunit": "^7.0" }, "suggest": { "ext-soap": "*" @@ -788,7 +781,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "5.0.x-dev" + "dev-master": "6.0.x-dev" } }, "autoload": { @@ -813,7 +806,7 @@ "mock", "xunit" ], - "time": "2018-01-06T05:45:45+00:00" + "time": "2018-02-15T05:27:38+00:00" }, { "name": "sebastian/code-unit-reverse-lookup", @@ -862,21 +855,21 @@ }, { "name": "sebastian/comparator", - "version": "2.1.2", + "version": "2.1.3", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/comparator.git", - "reference": "11c07feade1d65453e06df3b3b90171d6d982087" + "reference": "34369daee48eafb2651bea869b4b15d75ccc35f9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/11c07feade1d65453e06df3b3b90171d6d982087", - "reference": "11c07feade1d65453e06df3b3b90171d6d982087", + "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/34369daee48eafb2651bea869b4b15d75ccc35f9", + "reference": "34369daee48eafb2651bea869b4b15d75ccc35f9", "shasum": "" }, "require": { "php": "^7.0", - "sebastian/diff": "^2.0", + "sebastian/diff": "^2.0 || ^3.0", "sebastian/exporter": "^3.1" }, "require-dev": { @@ -922,32 +915,33 @@ "compare", "equality" ], - "time": "2018-01-12T06:34:42+00:00" + "time": "2018-02-01T13:46:46+00:00" }, { "name": "sebastian/diff", - "version": "2.0.1", + "version": "3.0.0", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/diff.git", - "reference": "347c1d8b49c5c3ee30c7040ea6fc446790e6bddd" + "reference": "e09160918c66281713f1c324c1f4c4c3037ba1e8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/347c1d8b49c5c3ee30c7040ea6fc446790e6bddd", - "reference": "347c1d8b49c5c3ee30c7040ea6fc446790e6bddd", + "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/e09160918c66281713f1c324c1f4c4c3037ba1e8", + "reference": "e09160918c66281713f1c324c1f4c4c3037ba1e8", "shasum": "" }, "require": { - "php": "^7.0" + "php": "^7.1" }, "require-dev": { - "phpunit/phpunit": "^6.2" + "phpunit/phpunit": "^7.0", + "symfony/process": "^2 || ^3.3 || ^4" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "2.0-dev" + "dev-master": "3.0-dev" } }, "autoload": { @@ -972,9 +966,12 @@ "description": "Diff implementation", "homepage": "https://github.com/sebastianbergmann/diff", "keywords": [ - "diff" + "diff", + "udiff", + "unidiff", + "unified diff" ], - "time": "2017-08-03T08:09:46+00:00" + "time": "2018-02-01T13:45:15+00:00" }, { "name": "sebastian/environment", @@ -1578,7 +1575,7 @@ "prefer-stable": true, "prefer-lowest": false, "platform": { - "php": "^5.6 || ^7.0" + "php": "^7.1" }, "platform-dev": [] } diff --git a/doc/book/examples.md b/doc/book/examples.md index 48cbc4d8..798e7acc 100644 --- a/doc/book/examples.md +++ b/doc/book/examples.md @@ -80,30 +80,30 @@ Checking permission using `isGranted()` with a class implementing `Zend\Permissions\Rbac\AssertionInterface`: ```php +use App\Model\Article; use Zend\Permissions\Rbac\AssertionInterface; use Zend\Permissions\Rbac\Rbac; -class AssertUserIdMatches implements AssertionInterface +class AssertUserRoleMatches implements AssertionInterface { protected $userId; protected $article; - public function __construct($userId) + public function __construct(string $userId) { $this->userId = $userId; } - public function setArticle($article) + public function setArticle(Article $article) { $this->article = $article; } - public function assert(Rbac $rbac) + public function assert(Rbac $rbac, RoleInterface $role = null, string $permission = null) { if (! $this->article) { return false; } - return ($this->userId === $this->article->getUserId()); } } diff --git a/doc/book/index.html b/doc/book/index.html index 07c8a528..4337842e 100644 --- a/doc/book/index.html +++ b/doc/book/index.html @@ -3,7 +3,7 @@
- Provide and query Role-Based Access Controls for your application. + Provide and query Role-Based Access Controls (RBAC) for your application.
$ composer require zendframework/zend-permissions-rbac
diff --git a/doc/book/intro.md b/doc/book/intro.md
index ba94f30f..980cc434 100644
--- a/doc/book/intro.md
+++ b/doc/book/intro.md
@@ -1,8 +1,7 @@
# Introduction
-zend-permissions-rbac provides a lightweight role-based access control (RBAC)
-implementation based around PHP's `RecursiveIterator` and
-`RecursiveIteratorIterator`. RBAC differs from access control lists (ACL) by
+`zend-permissions-rbac` provides a lightweight [Role-Based Access Control](https://it.wikipedia.org/wiki/Role-based_access_control)
+(RBAC) implementation in PHP. RBAC differs from access control lists (ACL) by
putting the emphasis on roles and their permissions rather than objects
(resources).
@@ -16,7 +15,7 @@ Thus, RBAC has the following model:
- many to many relationship between **identities** and **roles**.
- many to many relationship between **roles** and **permissions**.
-- **roles** can have a parent role.
+- **roles** can have parent and child roles (hierarchy of roles).
## Roles
diff --git a/doc/book/methods.md b/doc/book/methods.md
index c3d086c9..c88113bc 100644
--- a/doc/book/methods.md
+++ b/doc/book/methods.md
@@ -1,62 +1,39 @@
# Methods
-## `Zend\Permissions\Rbac\AbstractIterator`
-
-The `AbstractIterator` is used as the basis for both the primary `Rbac` class
-and the `AbstractRole`.
-
-Method signature | Description
------------------------------------ | -----------
-`current() : RoleInterface` | Return the current role instance.
-`getChildren() : RecursiveIterator` | Returns a recursive iterator of all children of the current role.
-`hasChildren() : bool` | Indicates if the current role has children.
-`key() : int` | Index of the current role instance.
-`next() : void` | Advance to the next role instance.
-`rewind() : void` | Seek to the first item in the iterator.
-`valid() : bool` | Is the current index valid?
-
-## `Zend\Permissions\Rbac\AbstractRole`
-
-The `AbstractRole` provides the base functionality required by the
-`RoleInterface`, and is the foundation for the `Role` class.
-
-Method signature | Description
----------------------------------------------- | -----------
-`addChild(string|RoleInterface $child) : void` | Add a child role to the current instance.
-`addPermission(string $name) : void` | Add a permission for the current role.
-`getName() : string` | Retrieve the name assigned to this role.
-`hasPermission(string $name) : bool` | Does the role have the given permission?
-`setParent(RoleInterface $parent) : void` | Assign the provided role as the current role's parent.
-`addParent(RoleInterface $parent) : Role` | Add a parent role to the current instance.
-`getParent() null|RoleInterface|array` | Retrieve the current role's parent, or array of parents if more that one exists.
+## `Zend\Permissions\Rbac\Role`
+
+The `Role` provides the base functionality required by the `RoleInterface`.
+
+Method signature | Description
+------------------------------------------| -----------
+`__construct(string $name) : void` | Create a new instance with the provided name.
+`getName() : string` | Retrieve the name assigned to this role.
+`addPermission(string $name) : void` | Add a permission for the current role.
+`hasPermission(string $name) : bool` | Does the role have the given permission?
+`addChild(RoleInterface $child) : Role` | Add a child role to the current instance.
+`getChildren() : RoleInterface[]` | Get all the children roles.
+`addParent(RoleInterface $parent) : Role` | Add a parent role to the current instance.
+`getParents() : RoleInterface[]` | Get all the parent roles.
## `Zend\Permissions\Rbac\AssertionInterface`
Custom assertions can be provided to `Rbac::isGranted()` (see below); such
assertions are provided the `Rbac` instance on invocation.
-Method signature | Description
---------------------------- | -----------
-`assert(Rbac $rbac) : bool` | Given an RBAC, determine if permission is granted.
+Method signature | Description
+-------------------------------------------------------------------- | -----------
+`assert(Rbac $rbac, RoleInterface $role, string $permission) : bool` | Given an RBAC, a role, and a permission, determine if permission is granted.
## `Zend\Permissions\Rbac\Rbac`
`Rbac` is the object with which you will interact within your application in
-order to query for permissions. It extends `AbstractIterator`.
+order to query for permissions.
Method signature | Description
--------------------------------------------------------------------------- | -----------
-`addRole(string|RoleInterface $child, array|RoleInterface $parents = null)` | Add a role to the RBAC. If `$parents` is non-null, the `$child` is also added to any parents provided.
-`getRole(string|RoleInterface $role) : RoleInterface` | Recursively queries the RBAC for the given role, returning it if found, and raising an exception otherwise.
-`hasRole(string|RoleInterface $role) : bool` | Recursively queries the RBAC for the given role, returning `true` if found, `false` otherwise.
+`addRole(string\|RoleInterface $child, array\|RoleInterface $parents = null)` | Add a role to the RBAC. If `$parents` is non-null, the `$child` is also added to any parents provided.
+`getRole(string $role) : RoleInterface` | Get the role specified by name, raising an exception if not found.
+`hasRole(string\|RoleInterface $role) : bool` | Recursively queries the RBAC for the given role, returning `true` if found, `false` otherwise.
`getCreateMissingRoles() : bool` | Retrieve the flag that determines whether or not `$parent` roles are added automatically if not present when calling `addRole()`.
`setCreateMissingRoles(bool $flag) : void` | Set the flag that determines whether or not `$parent` roles are added automatically if not present when calling `addRole()`.
-`isGranted(string|RoleInterface $role, string $permission, $assert = null)` | Determine if the role has the given permission. If `$assert` is provided and either an `AssertInterface` instance or callable, it will be queried before checking against the given role.
-
-## `Zend\Permissions\Rbac\Role`
-
-`Role` inherits from `AbstractRole` and `AbstractIterator`.
-
-Method signature | Description
----------------------------------- | -----------
-`__construct(string $name) : void` | Create a new instance with the provided name.
+`isGranted(string\|RoleInterface $role, string $permission, $assert = null)` | Determine if the role has the given permission. If `$assert` is provided and either an `AssertInterface` instance or callable, it will be queried before checking against the given role.
diff --git a/doc/book/migration/to-v3-0.md b/doc/book/migration/to-v3-0.md
new file mode 100644
index 00000000..cc30fcae
--- /dev/null
+++ b/doc/book/migration/to-v3-0.md
@@ -0,0 +1,85 @@
+# Upgrading to 3.0
+
+If you upgrade from version 2 releases, you will notice a few changes. This
+document details the changes
+
+## Minimum supported PHP version
+
+Version 3 drops support for PHP versions prior to PHP 7.1.
+
+## AssertionInterface
+
+The primary change is the `Zend\Permissions\Rbac\AssertionInterface::assert()`
+method definition.
+
+The new `assert` method has the following signature:
+
+```php
+namespace Zend\Permissions\Rbac;
+
+public function assert(
+ Rbac $rbac,
+ RoleInterface $role,
+ string $permission
+) : bool
+```
+
+The version 2 releases defined the method such that it only accepted a single
+parameter, `Rbac $rbac`. Version 3 adds the `$role` and `$permission`
+parameters. This simplifies implementation of dynamic assertions using the role
+and the permission information.
+
+For instance, imagine you want to disable a specific permission `foo` for an
+`admin` role; you can implement that as follows:
+
+```php
+public function assert(Rbac $rbac, RoleInterface $role, string $permission) : bool
+{
+ return ! ($permission === 'foo' && $role->getName() === 'admin');
+}
+```
+
+If you were previously implementing `AssertionInterface`, you will need to
+update the `assert()` signature to match the changes in version 3.
+
+If you were creating assertions as PHP callables, you may continue to use the
+existing signature; however, you may also expand them to accept the new
+arguments should they assist you in creating more complex, dynamic assertions.
+
+## RoleInterface
+
+`Zend\Permissions\Rbac\RoleInterface` also received a number of changes,
+including type hints and method name changes.
+
+### Type hints
+
+With the update to [PHP 7.1](#minimum-supported-php-version), we also updated
+the `RoleInterface` to provide:
+
+- scalar type hints where applicable (`addPermission()` and `hasPermission()`).
+- add return type hints (including scalar type hints) to all methods.
+
+You will need to examine the `RoleInterface` definitions to determine what
+changes to make to your implementations.
+
+### setParent becomes addParent
+
+In version 3, we renamed the method `Role::setParent()` to `Role::addParent()`.
+This naming is more consistent with other method names, such as
+`Role::addChild()`, and also makes clear that more than one parent may be
+provided to any given role.
+
+### getParent becomes getParents
+
+In line with the previous change, `getParent()` was also renamed to
+`getParents()`, which returns an array of `RoleInterface` instances.
+
+### Removed support for string arguments in Role::addChild
+
+Version 3 no longer allows adding a child using a string role name; you may only
+provide `RoleInterface` instances.
+
+### Adds getChildren
+
+Since roles may have multiple children, the method `getChildren()` was added; it
+returns an array of `RoleInterface` instances.
diff --git a/mkdocs.yml b/mkdocs.yml
index a04995d9..59b3b516 100644
--- a/mkdocs.yml
+++ b/mkdocs.yml
@@ -6,8 +6,9 @@ pages:
- Reference:
- Methods: methods.md
- Examples: examples.md
+ - Migration:
+ - 'v2.X to v3.0': migration/to-v3-0.md
site_name: zend-permissions-rbac
site_description: zend-permissions-rbac
repo_url: 'https://github.com/zendframework/zend-permissions-rbac'
copyright: 'Copyright (c) 2016 Zend Technologies USA Inc.'
-
diff --git a/phpunit.xml.dist b/phpunit.xml.dist
index c709b112..09d524cd 100644
--- a/phpunit.xml.dist
+++ b/phpunit.xml.dist
@@ -1,7 +1,7 @@