diff --git a/UPGRADE.md b/UPGRADE.md
index 896c6d4..7522a2d 100644
--- a/UPGRADE.md
+++ b/UPGRADE.md
@@ -2,20 +2,26 @@
## From LmcRbac v1 to LmcRbac v2
-LmcRbac v2 is a major version upgrade with many breaking changes that prevent
+LmcRbac v2 is a major version upgrade with many major breaking changes that prevent
straightforward upgrading.
+### Major changes
+
+- LmcRbac v2 is now based on Role and Rbac classes from `laminas-permissions-rbac`. All services have
+been updated to use these classes and interfaces.
+
+
### Namespace change
The namespace has been changed from LmcRbac to Lmc\Rbac. Please review your code to replace `LmcRbac` namespace
by `Lmc\Rbac` namespace.
-### Deprecations
+### Deprecations and removals
-- `Lmc\Rbac\HierarchicalRole` has been deprecated since `Lmc\Rbac\Role` now supports hierarchical roles. Flat roles
-are just a simplified version of a hierarchical roles. Use `Lmc\Rbac\Role` instead.
+- `LmcRbac\HierarchicalRole`, `LmcRbac\Role` and `LmcRbac\RoleInterface` has been deleted.
+Use the equivalent classes from `laminas-permissions-rbac` instead.
- The factories for services have been refactored from the `src/Container` folder
- to be colocated with the service that a factory is creating. All factories in the `src/Container` has been deprecated.
+ to be colocated with the service that a factory is creating. All factories in the `src/Container` has been deleted.
- The `AssertionContainer` class, interface and factory have been deprecated and replaced by `AssertionPluginManager` class, interface and factory.
## From ZfcRbac v3 to LmcRbac v1
diff --git a/composer.json b/composer.json
index fa787da..fc1b1ae 100644
--- a/composer.json
+++ b/composer.json
@@ -40,6 +40,7 @@
],
"require": {
"php": "^8.1 || ^8.2 || ^8.3",
+ "laminas/laminas-permissions-rbac": "^3.0",
"laminas/laminas-servicemanager": "^3.3",
"laminas/laminas-stdlib": "^3.1",
"doctrine/persistence": "^2.0 || ^3.0"
diff --git a/composer.lock b/composer.lock
index e651ca7..c23f0a1 100644
--- a/composer.lock
+++ b/composer.lock
@@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
- "content-hash": "27f8cc606345644071b208a518951361",
+ "content-hash": "6c21a5408719a4bb6be4cc83ac4d7ac6",
"packages": [
{
"name": "doctrine/event-manager",
@@ -194,6 +194,66 @@
],
"time": "2024-06-20T10:14:30+00:00"
},
+ {
+ "name": "laminas/laminas-permissions-rbac",
+ "version": "3.6.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/laminas/laminas-permissions-rbac.git",
+ "reference": "6699e9b95fb360b921b2e6d655977d4786da0443"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/laminas/laminas-permissions-rbac/zipball/6699e9b95fb360b921b2e6d655977d4786da0443",
+ "reference": "6699e9b95fb360b921b2e6d655977d4786da0443",
+ "shasum": ""
+ },
+ "require": {
+ "php": "~8.1.0 || ~8.2.0 || ~8.3.0"
+ },
+ "conflict": {
+ "zendframework/zend-permissions-rbac": "*"
+ },
+ "require-dev": {
+ "laminas/laminas-coding-standard": "~2.5.0",
+ "phpunit/phpunit": "^10.1.2",
+ "psalm/plugin-phpunit": "^0.18.4",
+ "vimeo/psalm": "^5.10"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "Laminas\\Permissions\\Rbac\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "description": "Provides a role-based access control management",
+ "homepage": "https://laminas.dev",
+ "keywords": [
+ "authorization",
+ "laminas",
+ "laminas-permissions-rbac",
+ "rbac"
+ ],
+ "support": {
+ "chat": "https://laminas.dev/chat",
+ "docs": "https://docs.laminas.dev/laminas-permissions-rbac/",
+ "forum": "https://discourse.laminas.dev",
+ "issues": "https://github.com/laminas/laminas-permissions-rbac/issues",
+ "rss": "https://github.com/laminas/laminas-permissions-rbac/releases.atom",
+ "source": "https://github.com/laminas/laminas-permissions-rbac"
+ },
+ "funding": [
+ {
+ "url": "https://funding.communitybridge.org/projects/laminas-project",
+ "type": "community_bridge"
+ }
+ ],
+ "time": "2023-11-27T21:55:58+00:00"
+ },
{
"name": "laminas/laminas-servicemanager",
"version": "3.22.1",
@@ -677,26 +737,26 @@
},
{
"name": "composer/pcre",
- "version": "3.2.0",
+ "version": "3.3.0",
"source": {
"type": "git",
"url": "https://github.com/composer/pcre.git",
- "reference": "ea4ab6f9580a4fd221e0418f2c357cdd39102a90"
+ "reference": "1637e067347a0c40bbb1e3cd786b20dcab556a81"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/composer/pcre/zipball/ea4ab6f9580a4fd221e0418f2c357cdd39102a90",
- "reference": "ea4ab6f9580a4fd221e0418f2c357cdd39102a90",
+ "url": "https://api.github.com/repos/composer/pcre/zipball/1637e067347a0c40bbb1e3cd786b20dcab556a81",
+ "reference": "1637e067347a0c40bbb1e3cd786b20dcab556a81",
"shasum": ""
},
"require": {
"php": "^7.4 || ^8.0"
},
"conflict": {
- "phpstan/phpstan": "<1.11.8"
+ "phpstan/phpstan": "<1.11.10"
},
"require-dev": {
- "phpstan/phpstan": "^1.11.8",
+ "phpstan/phpstan": "^1.11.10",
"phpstan/phpstan-strict-rules": "^1.1",
"phpunit/phpunit": "^8 || ^9"
},
@@ -736,7 +796,7 @@
],
"support": {
"issues": "https://github.com/composer/pcre/issues",
- "source": "https://github.com/composer/pcre/tree/3.2.0"
+ "source": "https://github.com/composer/pcre/tree/3.3.0"
},
"funding": [
{
@@ -752,7 +812,7 @@
"type": "tidelift"
}
],
- "time": "2024-07-25T09:36:02+00:00"
+ "time": "2024-08-19T19:43:53+00:00"
},
{
"name": "composer/semver",
@@ -2415,32 +2475,32 @@
},
{
"name": "phpunit/php-code-coverage",
- "version": "10.1.15",
+ "version": "10.1.16",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/php-code-coverage.git",
- "reference": "5da8b1728acd1e6ffdf2ff32ffbdfd04307f26ae"
+ "reference": "7e308268858ed6baedc8704a304727d20bc07c77"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/5da8b1728acd1e6ffdf2ff32ffbdfd04307f26ae",
- "reference": "5da8b1728acd1e6ffdf2ff32ffbdfd04307f26ae",
+ "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/7e308268858ed6baedc8704a304727d20bc07c77",
+ "reference": "7e308268858ed6baedc8704a304727d20bc07c77",
"shasum": ""
},
"require": {
"ext-dom": "*",
"ext-libxml": "*",
"ext-xmlwriter": "*",
- "nikic/php-parser": "^4.18 || ^5.0",
+ "nikic/php-parser": "^4.19.1 || ^5.1.0",
"php": ">=8.1",
- "phpunit/php-file-iterator": "^4.0",
- "phpunit/php-text-template": "^3.0",
- "sebastian/code-unit-reverse-lookup": "^3.0",
- "sebastian/complexity": "^3.0",
- "sebastian/environment": "^6.0",
- "sebastian/lines-of-code": "^2.0",
- "sebastian/version": "^4.0",
- "theseer/tokenizer": "^1.2.0"
+ "phpunit/php-file-iterator": "^4.1.0",
+ "phpunit/php-text-template": "^3.0.1",
+ "sebastian/code-unit-reverse-lookup": "^3.0.0",
+ "sebastian/complexity": "^3.2.0",
+ "sebastian/environment": "^6.1.0",
+ "sebastian/lines-of-code": "^2.0.2",
+ "sebastian/version": "^4.0.1",
+ "theseer/tokenizer": "^1.2.3"
},
"require-dev": {
"phpunit/phpunit": "^10.1"
@@ -2452,7 +2512,7 @@
"type": "library",
"extra": {
"branch-alias": {
- "dev-main": "10.1-dev"
+ "dev-main": "10.1.x-dev"
}
},
"autoload": {
@@ -2481,7 +2541,7 @@
"support": {
"issues": "https://github.com/sebastianbergmann/php-code-coverage/issues",
"security": "https://github.com/sebastianbergmann/php-code-coverage/security/policy",
- "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/10.1.15"
+ "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/10.1.16"
},
"funding": [
{
@@ -2489,7 +2549,7 @@
"type": "github"
}
],
- "time": "2024-06-29T08:25:15+00:00"
+ "time": "2024-08-22T04:31:57+00:00"
},
{
"name": "phpunit/php-file-iterator",
@@ -2897,16 +2957,16 @@
},
{
"name": "psr/log",
- "version": "3.0.0",
+ "version": "3.0.1",
"source": {
"type": "git",
"url": "https://github.com/php-fig/log.git",
- "reference": "fe5ea303b0887d5caefd3d431c3e61ad47037001"
+ "reference": "79dff0b268932c640297f5208d6298f71855c03e"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/php-fig/log/zipball/fe5ea303b0887d5caefd3d431c3e61ad47037001",
- "reference": "fe5ea303b0887d5caefd3d431c3e61ad47037001",
+ "url": "https://api.github.com/repos/php-fig/log/zipball/79dff0b268932c640297f5208d6298f71855c03e",
+ "reference": "79dff0b268932c640297f5208d6298f71855c03e",
"shasum": ""
},
"require": {
@@ -2941,9 +3001,9 @@
"psr-3"
],
"support": {
- "source": "https://github.com/php-fig/log/tree/3.0.0"
+ "source": "https://github.com/php-fig/log/tree/3.0.1"
},
- "time": "2021-07-14T16:46:02+00:00"
+ "time": "2024-08-21T13:31:24+00:00"
},
{
"name": "sebastian/cli-parser",
diff --git a/config/lmcrbac.global.php.dist b/config/lmcrbac.global.php.dist
index e873f22..6bbf080 100644
--- a/config/lmcrbac.global.php.dist
+++ b/config/lmcrbac.global.php.dist
@@ -25,14 +25,6 @@ declare(strict_types=1);
return [
'lmc_rbac' => [
- /**
- * Key that is used to fetch the identity provider
- *
- * Please note that when an identity is found, it MUST implement the LmcRbac\Identity\IdentityProviderInterface
- * interface, otherwise it will throw an exception.
- */
- // 'identity_provider' => 'LmcRbac\Identity\AuthenticationIdentityProvider',
-
/**
* Set the guest role
*
@@ -50,7 +42,7 @@ return [
*
* The provider config for InMemoryRoleProvider must follow the following format:
*
- * 'LmcRbac\Role\InMemoryRoleProvider' => [
+ * Lmc\Rbac\Role\InMemoryRoleProvider::class => [
* 'role1' => [
* 'children' => ['children1', 'children2'], // OPTIONAL
* 'permissions' => ['edit', 'read'] // OPTIONAL
diff --git a/data/FlatRole.php.dist b/data/FlatRole.php.dist
index 9bd49ea..67d97ac 100644
--- a/data/FlatRole.php.dist
+++ b/data/FlatRole.php.dist
@@ -21,8 +21,7 @@ declare(strict_types=1);
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
-use Lmc\Rbac\Permission\PermissionInterface;
-use Lmc\Rbac\Role\RoleInterface;
+use Laminas\Permissions\Rbac\RoleInterface;
/**
* @ORM\Entity
@@ -45,12 +44,12 @@ class FlatRole implements RoleInterface
protected ?int $id;
/**
- * @var string|null
+ * @var string
*
* @ORM\Column(type="string", length=255, unique=true)
*/
#[ORM\Column(name: 'name', type: 'string', length: 255, unique: true)]
- protected ?string $name;
+ protected string $name = '';
/**
* @var Permission[]|Collection
@@ -101,28 +100,21 @@ class FlatRole implements RoleInterface
/**
* @inheritDoc
*/
- public function addPermission(PermissionInterface|string $permission): void
+ public function addPermission(string $name): void
{
- if (is_string($permission)) {
- $permission = new Permission($permission);
- }
+ $permission = new Permission($name);
- $this->permissions[(string) $permission] = $permission;
+ $this->permissions[$name] = $permission;
}
/**
* @inheritDoc
*/
- public function hasPermission(PermissionInterface|string $permission): bool
+ public function hasPermission(string $name): bool
{
- // This can be a performance problem if your role has a lot of permissions. Please refer
- // to the cookbook to an elegant way to solve this issue
-
- return isset($this->permissions[(string) $permission]);
+ return isset($this->permissions[$name]);
}
-
-
public function getChildren(): iterable
{
return [];
@@ -133,8 +125,18 @@ class FlatRole implements RoleInterface
return false;
}
- public function addChild(RoleInterface $role): void
+ public function addChild(RoleInterface $child): void
{
// Do nothing
}
+
+ public function addParent(RoleInterface $parent): void
+ {
+ // Do nothing
+ }
+
+ public function getParents(): iterable
+ {
+ return [];
+ }
}
diff --git a/data/HierarchicalRole.php.dist b/data/HierarchicalRole.php.dist
index ea4e54c..560b470 100644
--- a/data/HierarchicalRole.php.dist
+++ b/data/HierarchicalRole.php.dist
@@ -21,7 +21,7 @@ declare(strict_types=1);
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
-use Lmc\Rbac\Role\RoleInterface;
+use Laminas\Permissions\Rbac\RoleInterface;
/**
* @ORM\Entity
@@ -44,12 +44,12 @@ class HierarchicalRole implements RoleInterface
protected ?int $id = null;
/**
- * @var string|null
+ * @var string
*
* @ORM\Column(type="string", length=48, unique=true)
*/
#[ORM\Column(name: 'name', type: 'string', length: 255, unique: true)]
- protected ?string $name;
+ protected string $name = '';
/**
* @var RoleInterface[]|Collection
@@ -111,34 +111,34 @@ class HierarchicalRole implements RoleInterface
* @param RoleInterface $child
* @return void
*/
- public function addChild(RoleInterface $role): void
+ public function addChild(RoleInterface $child): void
{
- $this->children[] = $role;
+ $this->children[] = $child;
}
/**
- * @param string|Permission $permission
+ * @param string|Permission $name
* @return void
*/
- public function addPermission(string|Permission|\Lmc\Rbac\Permission\PermissionInterface $permission): void
+ public function addPermission(string|Permission $name): void
{
- if (is_string($permission)) {
- $permission = new Permission($permission);
+ if (is_string($name)) {
+ $permission = new Permission($name);
}
- $this->permissions[(string) $permission] = $permission;
+ $this->permissions[(string) $name] = $permission;
}
/**
- * @param $permission
+ * @param string $name
* @return bool
*/
- public function hasPermission(string|\Lmc\Rbac\Permission\PermissionInterface $permission): bool
+ public function hasPermission(string $name): bool
{
// This can be a performance problem if your role has a lot of permissions. Please refer
// to the cookbook to an elegant way to solve this issue
- return isset($this->permissions[(string) $permission]);
+ return isset($this->permissions[$name]);
}
/**
@@ -149,11 +149,18 @@ class HierarchicalRole implements RoleInterface
return $this->children;
}
- /**
- * @inheritDoc
- */
public function hasChildren(): bool
{
return ! $this->children->isEmpty();
}
+
+ public function addParent(RoleInterface $parent): void
+ {
+ // Do nothing
+ }
+
+ public function getParents(): iterable
+ {
+ return [];
+ }
}
diff --git a/data/Permission.php.dist b/data/Permission.php.dist
index 841b383..2f986f9 100644
--- a/data/Permission.php.dist
+++ b/data/Permission.php.dist
@@ -19,7 +19,6 @@ declare(strict_types=1);
*/
use Doctrine\ORM\Mapping as ORM;
-use Lmc\Rbac\Permission\PermissionInterface;
/**
* @ORM\Entity
@@ -27,7 +26,7 @@ use Lmc\Rbac\Permission\PermissionInterface;
*/
#[ORM\Entity]
#[ORM\Table(name: 'permissions')]
-class Permission implements PermissionInterface
+class Permission
{
/**
* @var int|null
@@ -42,12 +41,12 @@ class Permission implements PermissionInterface
protected ?int $id;
/**
- * @var string|null
+ * @var string
*
* @ORM\Column(type="string", length=128, unique=true)
*/
#[ORM\Column(type: 'string', length: 128, unique: true)]
- protected ?string $name;
+ protected string $name = '';
/**
* Constructor
diff --git a/data/Role.php.dist b/data/Role.php.dist
index 5cc5202..d5e3c3b 100644
--- a/data/Role.php.dist
+++ b/data/Role.php.dist
@@ -21,8 +21,7 @@ declare(strict_types=1);
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
-use Lmc\Rbac\Permission\PermissionInterface;
-use Lmc\Rbac\Role\RoleInterface;
+use Laminas\Permissions\Rbac\RoleInterface;
/**
* @ORM\Entity
@@ -97,14 +96,14 @@ class Role implements RoleInterface
/**
* Add a permission
*
- * @param string|PermissionInterface $name
+ * @param string $name
* @return void
*/
- public function addPermission(string|PermissionInterface $permission): void
+ public function addPermission(string $name): void
{
- $permission = new \Permission($permission);
+ $permission = new \Permission($name);
- $this->permissions[(string) $permission] = $permission;
+ $this->permissions[$name] = $permission;
}
public function getName(): string
@@ -112,9 +111,9 @@ class Role implements RoleInterface
return $this->name;
}
- public function hasPermission(string|PermissionInterface $permission): bool
+ public function hasPermission(string $name): bool
{
- return isset($this->permissions[(string) $permission]);
+ return isset($this->permissions[$name]);
}
public function addChild(RoleInterface $child): void
@@ -131,4 +130,14 @@ class Role implements RoleInterface
{
return ! $this->children->isEmpty();
}
+
+ public function addParent(RoleInterface $parent): void
+ {
+ // Do nothing
+ }
+
+ public function getParents(): iterable
+ {
+ return [];
+ }
}
diff --git a/docs/docs/Guides/integrating.md b/docs/docs/Guides/integrating.md
new file mode 100644
index 0000000..9f86439
--- /dev/null
+++ b/docs/docs/Guides/integrating.md
@@ -0,0 +1,158 @@
+---
+title: Integrating into applications
+---
+
+LmcRbac can be used in your application to implement role-based access control.
+
+However, it is important to note that Authorization service `isGranted()` method expects
+an identity to be provided. The identity must also implement the `Lmc\Rbac\Identity\IdentityInterface`.
+
+User authentication is not in the scope of LmcRbac and must be implemented by your application.
+
+## Laminas MVC applications
+
+In a Laminas MVC application, you can use the ['laminas-authentication'](https://docs.laminas.dev/laminas-authentication)
+component with an appropriate adapter to provide the identity.
+
+The `Laminas\Authentication\AuthenticationService` service provides the identity using the `getIdentity()` method.
+However, it is not prescriptive on the signature of the returned identity object. It is up to the
+authentication adapter to return a authentication result that contains an identity object that implements the
+`IdentityInterface`.
+
+For example:
+
+```php
+authenticationService = $authenticationService;
+ $this->authorizationService = $authorizationService;
+ }
+
+ public function doSomething()
+ {
+ $identity = $this->authenticationService->hasIdentity() ? $this->authenticationService->getIdentity() : null;
+
+ // Check for permission
+ if ($this->getAuthorizationService()->isGranted($identity, 'somepermssion')) {
+ // authorized
+ } else {
+ // not authorized
+ }
+ }
+
+}
+
+```
+### Other Laminas MVC components to use
+To facilitate integration in an MVC application, you can use [LmcUser](https://lm-commons.github.io/LmcUser/) for
+authentication.
+
+You can also use [LmcRbacMvc](https://lm-commons.github.io/LmcRbacMvc/) which extends LmcRbac by handling identities.
+It also provides additional functionalities like route guards and strategies for handling unauthorized access. For example,
+an unauthorized strategy could be to redirect to a login page.
+
+## Mezzio and PSR-7 applications
+
+In a Mezzio application, you can use the [`mezzio/mezzio-authentication`](https://docs.mezzio.dev/mezzio-authentication/)
+component to provide the identity. `mezzio/mezzio-authentication` will add a `UserInterface` object to the request attributes.
+
+Although the `UserInterface` interface has a `getRoles` method, LmcRbac's `AuthorizationService` still expects the identity
+to implement the `IdentityInterface`.
+
+This can be overcome by providing `mezzio/mezzio-authentication` with a custom factory to instantiate a user object that
+implements the `IdentityInterface` as explained in this [section](https://docs.mezzio.dev/mezzio-authentication/v1/intro/)
+of the `mezzio/mezzio-authentication` documentation.
+
+For example:
+
+```php
+identity = $identity;
+ $this->roles = $roles;
+ $this->details = $details;
+ }
+
+ public function getIdentity(): string
+ {
+ return $this->identity;
+ }
+
+ public function getRoles(): array
+ {
+ return $this->roles;
+ }
+
+ public function getDetails(): array
+ {
+ return $this->details;
+ }
+
+ public function getDetail(string $name, $default = null)
+ {
+ return $this->details[$name] ?? $default;
+ }
+}
+```
+Then provide a factory for creating the user class somewhere in a config provider:
+```php
+ [
+ UserInterface => function (string $identity, array $roles = [], array $details = []): UserInterface {
+ return new MyUser($identity, $roles, $details);
+ };
+ ],
+ ];
+
+```
+
+From this point, assuming that you have configured your application to use the `Mezzio\Authentication\AuthenticationMiddleware`,
+you can use `MyUser` in your handler by retrieving it from the request:
+
+```php
+// Retrieve the UserInterface object from the request.
+$user = $request->getAttribute(UserInterface::class);
+
+// Check for permission, this works because $user implements IdentityInterface
+if ($this->getAuthorizationService()->isGranted($user, 'somepermssion')) {
+ // authorized
+} else {
+ // not authorized
+}
+```
+
+How you define roles and permissions in your application is up to you. One way would be to use the route name as
+a permission such that authorization can be set up based on routes and optionally on route+verb.
+
+
+### Other Mezzio components to use
+
+A LmcRbac Mezzio component is under development to provide factories and middleware to facilitate integration of LmcRbac
+in Mezzio applications.
diff --git a/docs/docs/Upgrading/migration.md b/docs/docs/Upgrading/migration.md
new file mode 100644
index 0000000..b582938
--- /dev/null
+++ b/docs/docs/Upgrading/migration.md
@@ -0,0 +1,22 @@
+---
+sidebar_label: From ZF-Commons Rbac v3
+sidebar_position: 2
+title: Migrating from ZF-Commons RBAC v3
+---
+
+The ZF-Commons Rbac was created for the Zend Framework. When the Zend Framework was migrated to
+the Laminas project, the LM-Commons organization was created to provide components formerly provided by ZF-Commons.
+
+When ZfcRbac was moved to LM-Commons, it was split into two repositories:
+
+- [LmcRbacMvc](https://github.com/LM-Commons/LmcRbacMvc) contains the old version 2 of ZfcRbac.
+- LmcRbac contains the version 3 of ZfcRbac, which was only released as v3.alpha.1.
+
+To upgrade to LmcRbac v2, it is suggested to do it in two steps:
+
+1. Upgrade to LmcRbac v1 with the following steps:
+ * Uninstall `zf-commons/zfc-rbac:3.0.0-alpha.1`.
+ * Install `lm-commons/lmc-rbac:~1.0`
+ * Change `zfc-rbac.global.php` to `lmcrbac.global.php` and update the key `zfc_rbac` to `lmc_rbac`.
+ * Review your code for usages of the `ZfcRbac/*` namespace to `LmcRbac/*` namespace.
+2. Upgrade to LmcRbac v2 using the instructions in this [section](to-v2.md).
diff --git a/docs/docs/Upgrading/to-v2.md b/docs/docs/Upgrading/to-v2.md
new file mode 100644
index 0000000..c43c345
--- /dev/null
+++ b/docs/docs/Upgrading/to-v2.md
@@ -0,0 +1,37 @@
+---
+sidebar_label: From v1 to v2
+sidebar_position: 1
+title: Upgrading from v1 to v2
+---
+
+LmcRbac v2 is a major version upgrade with many breaking changes that prevent
+straightforward upgrading.
+
+### Namespace change
+
+The namespace has been changed from LmcRbac to Lmc\Rbac.
+
+Please review your code to replace references to the `LmcRbac` namespace
+by the `Lmc\Rbac` namespace.
+
+### LmcRbac is based on laminas-permissions-rbac
+
+LmcRbac is now based on the role class and interface provided by laminas-permissions-rbac which
+provides a hierarchical role model only.
+
+Therefore the `Role`, `HierarchicalRole` classes and the `RoleInterface` and `HierarchicalRoleInterface` have been removed
+in version 2.
+
+The `PermissionInterface` interface has been removed as permissions in `laminas-permissions-rbac` as just strings or any
+objects that can be casted to a string. If you use objects to hold permissions, just make sure that the object can be
+casted to a string by, for example, implementing a `__toString()` method.
+
+### Refactoring the factories
+
+The factories for services have been refactored from the `LmcRbac\Container` namespace
+to be colocated with the service that a factory is creating. All factories in the `LmcRbac\Container` namespace have
+been removed.
+
+### Refactoring the Assertion Plugin Manager
+
+The `AssertionContainer` class, interface and factory have been replaced by `AssertionPluginManager` class, interface and factory.
diff --git a/docs/docs/assertions.md b/docs/docs/assertions.md
index 552a549..dc86f1a 100644
--- a/docs/docs/assertions.md
+++ b/docs/docs/assertions.md
@@ -14,13 +14,13 @@ You can define dynamic assertion functions and assigned them to permission via c
## Defining a dynamic assertion function
-A dynamic assertion must implement the `LmcRbac\Assertion\AssertionInterace` which defines only one method:
+A dynamic assertion must implement the `Lmc\Rbac\Assertion\AssertionInterace` which defines only one method:
```php
public function assert(
string $permission,
- IdentityInterface $identity = null,
- $context = null
+ ?IdentityInterface $identity = null,
+ mixed $context = null
): bool
```
The assertion returns `true` when the access is granted, `false` otherwise.
@@ -31,9 +31,9 @@ represented by `$permission` owns the resource represented by `$context`.
```php
[
@@ -66,7 +67,7 @@ return [
],
'assertion_manager' => [
'factories' => [
- \My\Namespace\MyAssertion::class => \Laminas\ServiceManager\Factory\InvokableFactory::class
+ \My\Namespace\MyAssertion::class => InvokableFactory::class
],
],
],
@@ -77,11 +78,13 @@ It is also possible to configure an assertion using a callable instead of a clas
```php
[
/* the rest of the file */
'assertion_map' => [
- 'edit' => function assert(string $permission, IdentityInterface $identity = null, $context = null): bool
+ 'edit' => function assert(string $permission, ?IdentityInterface $identity = null, $context = null): bool
{
// for 'edit' permission
if ('edit' === $permission) {
@@ -113,15 +116,15 @@ return [
\My\Namespace\AssertionB::class,
],
'read' => [
- 'condition' => \LmcRbac\Assertion\AssertionSet::CONDITION_OR,
+ 'condition' => \Lmc\Rbac\Assertion\AssertionSet::CONDITION_OR,
\My\Namespace\AssertionC::class,
\My\Namespace\AssertionD::class,
],
'delete' => [
- 'condition' => \LmcRbac\Assertion\AssertionSet::CONDITION_OR,
+ 'condition' => \Lmc\Rbac\Assertion\AssertionSet::CONDITION_OR,
\My\Namespace\AssertionE::class,
[
- 'condition' => \LmcRbac\Assertion\AssertionSet::CONDITION_AND,
+ 'condition' => \Lmc\Rbac\Assertion\AssertionSet::CONDITION_AND,
\My\Namespace\AssertionF::class,
\My\Namespace\AssertionC::class,
],
@@ -142,3 +145,9 @@ associated with the `'delete'` permission above.
The default logic is to combine assertions using 'and' logic but this can be explicitly set as shown above for `'delete'`
permission.
+## Defining dynamic assertions at run-time
+
+Although dynamic assertions are typically defined in the application's configuration, it is possible to set
+dynamic assertions at run-time by using the Authorization Service utility methods for adding/getting assertions.
+
+These methods are described in the Authorization Service [reference](authorization-service.md#reference).
diff --git a/docs/docs/authorization-service.md b/docs/docs/authorization-service.md
index a8914e9..ee68543 100644
--- a/docs/docs/authorization-service.md
+++ b/docs/docs/authorization-service.md
@@ -7,27 +7,160 @@ title: Authorization Service
### Usage
The Authorization service can be retrieved from the service manager using the name
-`LmcRbac\Service\AuthorizationServiceInterface` and injected into your code:
+`Lmc\Rbac\Service\AuthorizationServiceInterface` and injected into your code:
```php
get(LmcRbac\Service\AuthorizationServiceInterface::class);
+ $authorizationService = $container->get(Lmc\Rbac\Service\AuthorizationServiceInterface::class);
```
### Reference
-`LmcRbac\Service\AuthorizationServiceInterface` defines the following method:
+`Lmc\Rbac\Service\AuthorizationServiceInterface` defines the following methods:
-`isGranted(?IdentityInterface $identity, string $permission, $context = null): bool`
+#### `isGranted(?IdentityInterface $identity, string $permission, $context = null): bool`
-| Parameter | Description |
-|----------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
-| `$identity` | The identity whose roles to checks. If `$identity` is null, then the `guest` is used. The `guest` role is definable via configuration and defaults to `'guest'`. |
-| `$permission` | The permission to check against |
-| `$context` | A context that will be passed to dynamic assertions that are defined for the permission |
+Checks that the identity has is granted the permission for the (optional) context.
+
+ | Parameter | Description |
+ |----------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
+ | `$identity` | The identity whose roles to checks. If `$identity` is null, then the `guest` is used. The `guest` role is definable via configuration and defaults to `'guest'`. |
+ | `$permission` | The permission to check against |
+ | `$context` | A context that will be passed to dynamic assertions that are defined for the permission |
+
+#### `setAssertions(array $assertions, bool $merge = false): void`
+
+Allows to define dynamic assertions at run-time.
+
+ | Parameter | Description |
+ |---------------|-----------------------------------------------------------------------------------------|
+ | `$assertions` | An array of assertions to merge or to replace |
+ | `$merge` | if `true` the content of `$assertions` will be merged with existing assertions. |
+
+
+#### `setAssertion(string $permission, AssertionInterface|callable|string $assertion): void`
+Allows to define a dynamic assertion at run-time.
+
+ | Parameter | Description |
+ |---------------|-----------------------------------------|
+ | `$permission` | Permission name |
+ | `$assertion` | The assertion to set for `$permission` |
+
+#### `hasAssertion(string $permission): bool`
+Checks if the authorization has a dynamic assertion for a given permission.
+
+ | Parameter | Description |
+ |---------------|--------------------------|
+ | `$permission` | Permission name |
+
+
+#### `getAssertions(): array`
+
+Returns all the dynamic assertions defined.
+
+#### `getAssertion(string $permission): AssertionInterface|callable|string|null`
+
+Returns the dynamic assertion for the give permission
+
+ | Parameter | Description |
+ |---------------|-----------------------------|
+ | `$permission` | Permission permission name |
More on dynamic assertions can be found in the [Assertions](assertions.md) section.
More on the `guest` role can be found in the [Configuration](configuration.md) section.
+## Injecting the Authorization Service
+
+There are a few methods to inject the Authorization Service into your service.
+
+### Using a factory
+
+You can inject the AuthorizationService into your own objects using a factory. The Authorization Service
+can be retrieved from the container using `'Lmc\Rbac\Service\AuthorizationServiceInterface'`.
+
+Here is a classic example for injecting the Authorization Service into your own service
+
+*in your app's Module*
+
+```php
+use Lmc\Rbac\Service\AuthorizationServiceInterface;
+class Module
+{
+ public function getConfig()
+ {
+ return [
+ 'service_manager' => [
+ 'factories' => [
+ 'MyService' => function($sm) {
+ $authService = $sm->get('AuthorizationServiceInterface');
+ return new MyService($authService);
+ }
+ ],
+ ],
+ ];
+ }
+}
+````
+
+### Using traits
+
+For convenience, LmcRbac provides a `AuthorizationServiceAwareTrait` that adds the `$authorizationService` property and
+setter/getter methods.
+
+### Using delegators
+
+LmcRbac ships with a `Lmc\Rbac\Service\AuthorizationServiceDelegatorFactory` [delegator factory](https://docs.laminas.dev/laminas-servicemanager/delegators/)
+to automatically inject the authorization service into your classes.
+
+Your class must implement the `Lmc\Rbac\Service\AuthorizationServiceAwareInterface` and use the above trait, as shown below:
+
+```php
+namespace MyModule;
+
+use Lmc\Rbac\Service\AuthorizationServiceAwareInterface;
+use Lmc\Rbac\Service\AuthorizationServiceAwareTrait;
+
+class MyClass implements AuthorizationServiceAwareInterface
+{
+ use AuthorizationServiceAwareTrait;
+
+ public function doSomethingThatRequiresAuth()
+ {
+ if (! $this->getAuthorizationService()->isGranted($identity, 'deletePost')) {
+ throw new \Exception('You are not allowed !');
+ }
+ return true;
+ }
+}
+```
+
+And add your class to the right delegator:
+
+```php
+namespace MyModule;
+use Lmc\Rbac\Service\AuthorizationServiceDelegatorFactory;
+class Module
+{
+ // ...
+
+ public function getConfig()
+ {
+ return [
+ 'service_manager' => [
+ 'factories' => [
+ MyClass::class => InvokableFactory::class,
+ ],
+ 'delegators' => [
+ MyClass::class => [
+ AuthorizationServiceDelegatorFactory::class,
+ ],
+ ],
+ ],
+ ];
+ }
+}
+```
+
+
diff --git a/docs/docs/configuration.md b/docs/docs/configuration.md
index 9c1d32d..7d94088 100644
--- a/docs/docs/configuration.md
+++ b/docs/docs/configuration.md
@@ -14,5 +14,6 @@ a `config/autoload/lmcrbac.global.php` file. A sample configuration file is prov
| Key | Description |
|--|------------------------------------------------------------------------------------------------------------------------------------------------|
| `guest_role` | Defines the name of the `guest` role when no identity exists. Defaults to `'guest'`. |
-| `assertion_map` | Defines the dynamic assertions that are associated to permissions. Defaults to `[]`. See the [Dynamic Assertions](assertions) section. |
| `role_provider` | Defines the role provider. Defaults to `[]` See the [Role Providers](role-providers) section. |
+| `assertion_map` | Defines the dynamic assertions that are associated to permissions. Defaults to `[]`. See the [Dynamic Assertions](assertions) section. |
+| `assertion_manager` | Provides a configuration for the Assertion Plugin Manager. Defaults to `[]`. See the [Dynamic Assertion](assertions.md) section. |
diff --git a/docs/docs/quick-start.md b/docs/docs/quick-start.md
new file mode 100644
index 0000000..e0f57bb
--- /dev/null
+++ b/docs/docs/quick-start.md
@@ -0,0 +1,197 @@
+---
+title: Quick Start
+sidebar_position: 1
+---
+
+LmcRbac offers components and services to implement role-based access control (RBAC) in your application.
+LmcRbac extends the components provided by [laminas-permissions-rbac](https://github.com/laminas/laminas-permissions-rbac).
+
+LmcRbac can be used in Laminas MVC and in Mezzio applications.
+
+:::tip
+If you are upgrading from LmcRbac v1 or from zfc-rbac v3, please read the [Upgrading section](Upgrading/to-v2.md)
+:::
+
+## Concepts
+
+[Role-Based Access Control (RBAC)](https://en.wikipedia.org/wiki/Role-based_access_control)
+is an approach to restricting system access to authorized users by putting emphasis
+on roles and their permissions.
+
+In the RBAC model:
+
+- an **identity** has one of more roles.
+- a **role** has one of more permissions.
+- a **permission** is typically an action like "read", "write", "delete".
+- a **role** can have **child roles** thus providing a hierarchy of roles where a role will inherit the permissions of all its child roles.
+
+### Authorization
+
+An identity will be authorized to perform an action, such as accessing a resource, if it is granted
+the permission that controls the execution of the action.
+
+For example, deleting an item could be restricted to identities that have at least one role that has the
+`item.delete` permission. This could be implemented by defining a `member` role that has the `item.delete` and assigning
+this role of an authenticated user.
+
+### Dynamic Assertions
+
+In some cases, just checking if the identity has the `item.delete` permission is not enough.
+It would also be necessary to check, for example, that the `item` belongs to the identity. Dynamic assertion allow
+to specify some extra checks before granting access to perform an action such as, in this case, being the owner of the
+resource.
+
+### Identities
+
+An identity is typically provided by an authentication process within the application.
+
+Authentication is not in the scope of `LmcRbac` and it is assumed that an identity entity that can provide the assigned
+roles is available when using the authorization service. If no identity is available, as it would be the case when no
+user is "logged in", then a guest role is assumed.
+
+## Requirements
+
+- PHP 8.1 or higher
+
+## Installation
+
+LmcRbac only officially supports installation through Composer.
+
+Install the module:
+
+```sh
+$ composer require lm-commons/lmc-rbac "~1.0"
+```
+
+You will be prompted by the `laminas-component-installer` plugin to inject LM-Commons\LmcRbac.
+
+:::note
+**Manual installation:**
+
+Enable the module by adding `LmcRbac` key to your `application.config.php` or `modules.config.php` file for Laminas MVC
+applications, or to the `config/config.php` file for Mezzio applications.
+:::
+
+Customize the module by copy-pasting
+the `lmcrbac.global.php` file to your `config/autoload` folder.
+
+:::note
+On older versions of `LmcRbac`, the configuration file is named `config/config.global.php`.
+:::
+
+## Defining roles
+
+By default, no roles and no permissions are defined.
+
+Roles and permissions are defined by a Role Provider. `LmcRbac` ships with two roles providers:
+- a simple `InMemoryRoleProvider` that uses an associative array to define roles and their permission. This is the default.
+- a `ObjectRepositoyRoleProvider` that is based on Doctrine ORM.
+
+To quickly get started, let's use the `InMemoryRoleProvider` role provider.
+
+In the `config/autoload/lmcrbac.global.php`, add the following:
+
+```php
+ [
+ 'role_provider' => [
+ Lmc\Rbac\Role\InMemoryRoleProvider::class => [
+ 'guest',
+ 'user' => [
+ 'permissions' => ['create', 'edit'],
+ ],
+ 'admin' => [
+ 'children' => ['user'],
+ 'permissions' => ['delete'],
+ ],
+ ],
+ ],
+ ],
+];
+```
+
+This defines 3 roles: a `guest` role, a `user` role having 2 permissions, and a `admin` role which has the `user` role as
+a child and with its own permission. If the hierarchy is flattened:
+
+- `guest` has no permission
+- `user` has permissions `create` and `edit`
+- `admin` has permissions `create`, `edit` and `delete`
+
+## Basic authorization
+
+The authorization service can get retrieved from the service manager container and used to check if a permission
+is granted to an identity:
+
+```php
+get('\Lmc\Rbac\Service\AuthorizationServiceInterface');
+
+ /** @var \Lmc\Rbac\Identity\IdentityInterface $identity */
+ if ($authorizationService->isGranted($identity, 'create')) {
+ /** do something */
+ }
+```
+
+If `$identity` has the role `user` and/or `admin` then the authorization is granted. If the identity has the role `guest`, then authorization
+is denied.
+
+:::info
+If `$identity` is null (no identity), then the guest role is assumed which is set to `'guest'` by default. The guest role
+can be configured in the `lmcrbac.config.php` file. More on this in the [Configuration](configuration.md) section.
+:::
+
+:::warning
+`LmcRbac` does not provide any logic to instantiate an identity entity. It is assumed that
+the application will instantiate an entity that implements `\Lmc\Rbac\Identity\IdentityInterface` which defines the `getRoles()`
+method.
+:::
+
+## Using assertions
+
+Even if an identity has the `user` role granting it the `edit` permission, it should not have the authorization to edit another identity's resource.
+
+This can be achieved using dynamic assertion.
+
+An assertion is a function that implements the `\Lmc\Rbac\Assertion\AssertionInterface` and is configured in the configuration
+file.
+
+Let's modify the `lmcrbac.config.php` file as follows:
+
+```php
+ [
+ 'role_provider' => [
+ /* roles and permissions
+ ],
+ 'assertion_map' => [
+ 'edit' => function ($permission, IdentityInterface $identity = null, $resource = null) {
+ if ($resource->getOwnerId() === $identity->getId() {
+ return true;
+ } else {
+ return false;
+ }
+ ],
+ ],
+];
+```
+
+Then use the authorization service passing the resource (called a 'context') in addition to the permission:
+
+```php
+get('\Lmc\Rbac\Service\AuthorizationServiceInterface');
+
+ /** @var \Lmc\Rbac\Identity\IdentityInterface $identity */
+ if ($authorizationService->isGranted($identity, 'edit', $resource)) {
+ /** do something */
+ }
+```
+
+Dynanmic assertions are further discussed in the [Dynamic Assertions](assertions) section.
diff --git a/docs/docs/role-providers.md b/docs/docs/role-providers.md
index a65654e..a011763 100644
--- a/docs/docs/role-providers.md
+++ b/docs/docs/role-providers.md
@@ -1,60 +1,71 @@
---
-sidebar_label: Roles and Role providers
-title: Roles and Role providers
+sidebar_label: Roles, permissions and Role providers
+title: Roles, Permissions and Role providers
sidebar_position: 4
---
-## Role types
+## Roles
A role is an object that returns a list of permissions that the role has.
-`LmcRbac` support two types of roles: hierarchical roles and flat roles.
+LmcRbac uses the Role class defined by [laminas-permissions-rbac](https://github.com/laminas/laminas-permissions-rbac).
-### Flat roles
+Roles are defined using by the `\Laminas\Permissions\Rbac\Role` class or by a class
+implementing `\Laminas\Permissions\Rbac\RoleInterface`.
-A flat role is the simplest role object. It contains the list of permissions that
-the role has.
+Roles can have child roles and therefore provides a hierarchy of roles where a role inherit the permissions of all its
+child roles.
-Flat roles are defined using by the `LmcRbac\Role\Role` class or by classes
-implementing the `LmcRbac\Role\RoleInterface`.
+For example, a 'user' role may have the 'read' and 'write' permissions, and a 'admin' role
+may inherit the permissions of the 'user' role plus an additional 'delete' role. In this structure,
+the 'admin' role will have 'user' as its child role.
-### Hierarchical roles
-A hierarchical role is a role that has child roles and therefore provides
-a hierarchy of roles where a role inherit the permissions of all its child roles.
+:::tip[Flat roles]
+Previous version of LmcRbac used to make a distinction between flat roles and hierarchical roles.
+A flat role is just a simplification of a hierarchical role, i.e. a hierarchical role without children.
-For example, a 'user' role may have the 'read' and 'write' permissions, and a 'admin' role
-may inherit the permissions of the 'user' role plus an additional 'delete' role. In this structure,
-the 'admin' role will have 'user' as its child role.
+In `laminas-permissions-rbac`, roles are hierarchical.
+:::
-Hierarchical roles may have flat roles or hierarchical roles as children.
+## Permissions
-Hierarchical roles are defined using by the `LmcRbac\Role\HierarchicalRole` class or by classes
-implementing the `LmcRbac\Role\HierarchicalRoleInterface`.
+A permission in `laminas-permissions-rbac` is simply a string that represents the permission such as 'read', 'write' or 'delete'.
+But it can also be more precise like 'article.read' or 'article.write'.
+
+A permission can also be an object as long as it can be casted to a string. This could be the
+case, for example, when permissions are stored in a database where they could also have a identified and a description.
+
+:::tip
+An object can be casted to a string by implementing the `__toString()` method.
+:::
## Role Providers
A role provider is an object that returns a list of roles. A role provider must implement the
-`LmcRbac\Role\RoleProviderInterface` interface. The only required method is `getRoles`, and must return an array
-of `LmcRbac\Role\RoleInterface` objects.
+`Lmc\Rbac\Role\RoleProviderInterface` interface. The only required method is `getRoles`, and must return an array
+of `Laminas\Permissions\Rbac\RoleInterface` objects.
Roles can come from one of many sources: in memory, from a file, from a database, etc. However, you can specify only one role provider per application.
### Built-in role providers
-LmcRbac comes with two built-in role providers: `LmcRbac\Role\InMemoryRoleProvider` and `LmcRbac\Role\ObjectRepositoryRoleProvider`. A role
-provider must be added to the `role_provider` subkey in the configuration file:
+LmcRbac comes with two built-in role providers: `Lmc\Rbac\Role\InMemoryRoleProvider` and
+`Lmc\Rbac\Role\ObjectRepositoryRoleProvider`. A role provider must be added to the `role_provider` subkey in the
+configuration file. For example:
```php
return [
'lmc_rbac' => [
'role_provider' => [
- // Role provider config here!
+ Lmc\Rbac\Role\InMemoryRoleProvider::class => [
+ // configuration
+ ],
]
]
];
```
-### `LmcRbac\Role\InMemoryRoleProvider`
+### `Lmc\Rbac\Role\InMemoryRoleProvider`
This provider is ideal for small/medium sites with few roles/permissions. All the data is specified in a simple associative array in a
PHP file.
@@ -65,7 +76,7 @@ Here is an example of the format you need to use:
return [
'lmc_rbac' => [
'role_provider' => [
- 'LmcRbac\Role\InMemoryRoleProvider' => [
+ Lmc\Rbac\Role\InMemoryRoleProvider::class => [
'admin' => [
'children' => ['member'],
'permissions' => ['article.delete']
@@ -83,9 +94,8 @@ return [
];
```
-The `children` and `permissions` subkeys are entirely optional. Internally, the `LmcRbac\Role\InMemoryRoleProvider` creates
-either a `LmcRbac\Role\Role` object if the role does not have any children, or a `LmcRbac\Role\HierarchicalRole` if
-the role has at least one child.
+The `children` and `permissions` subkeys are entirely optional. Internally, the `Lmc\Rbac\Role\InMemoryRoleProvider` creates
+`Lmc\Rbac\Role\Role` objects with children, if any.
If you are more confident with flat RBAC, the previous config can be re-written to remove any inheritence between roles:
@@ -93,7 +103,7 @@ If you are more confident with flat RBAC, the previous config can be re-written
return [
'lmc_rbac' => [
'role_provider' => [
- 'LmcRbac\Role\InMemoryRoleProvider' => [
+ Lmc\Rbac\Role\InMemoryRoleProvider::class => [
'admin' => [
'permissions' => [
'article.delete',
@@ -118,7 +128,7 @@ return [
];
```
-### `LmcRbac\Role\ObjectRepositoryRoleProvider`
+### `Lmc\Rbac\Role\ObjectRepositoryRoleProvider`
This provider fetches roles from a database using `Doctrine\Common\Persistence\ObjectRepository` interface.
@@ -129,7 +139,7 @@ using the `object_repository` key:
return [
'lmc_rbac' => [
'role_provider' => [
- 'LmcRbac\Role\ObjectRepositoryRoleProvider' => [
+ Lmc\Rbac\Role\ObjectRepositoryRoleProvider::class => [
'object_repository' => 'App\Repository\RoleRepository',
'role_name_property' => 'name'
],
@@ -144,7 +154,7 @@ Or you can specify the `object_manager` and `class_name` options:
return [
'lmc_rbac' => [
'role_provider' => [
- 'LmcRbac\Role\ObjectRepositoryRoleProvider' => [
+ Lmc\Rbac\Role\ObjectRepositoryRoleProvider::class => [
'object_manager' => 'doctrine.entitymanager.orm_default',
'class_name' => 'App\Entity\Role',
'role_name_property' => 'name'
@@ -158,14 +168,14 @@ In both cases, you need to specify the `role_name_property` value, which is the
that holds the actual role name. This is used internally to only load the identity roles, instead of loading
the whole table every time.
-Please note that your entity fetched from the table MUST implement the `LmcRbac\Role\RoleInterface` interface.
+Please note that your entity fetched from the table MUST implement the `Lmc\Rbac\Role\RoleInterface` interface.
Sample ORM entity models are provided in the `/data` folder for flat role, hierarchical role and permission.
## Creating custom role providers
To create a custom role provider, you first need to create a class that implements the
-`LmcRbac\Role\RoleProviderInterface` interface.
+`Lmc\Rbac\Role\RoleProviderInterface` interface.
Then, you need to add it to the role provider manager:
@@ -173,7 +183,7 @@ Then, you need to add it to the role provider manager:
return [
'lmc_rbac' => [
'role_provider' => [
- 'Application\Role\CustomRoleProvider' => [
+ MyCustomRoleProvider::class => [
// Options
],
],
@@ -185,9 +195,25 @@ And the role provider is created using the service manager:
return [
'service_manager' => [
'factories' => [
- 'Application\Role\CustomRoleProvider' => 'Application\Factory\CustomRoleProviderFactory'
+ MyCustomRoleProvider::class => MyCustomRoleProviderFactory::class,
],
],
];
```
+## Role Service
+
+LmcRbac provides a role service that will use the Role Providers to provide the roles
+associated with a given identity.
+
+It can be retrieved from the container be requesting the `Lmc\Rbac\Service\RoleServiceIntgeface`.
+
+`Lmc\Rbac\Service\RoleServiceInterface` defines the following method:
+
+- `getIdentityRoles(?IdentityInterface $identity = null): iterable`
+
+ | Parameter | Description |
+ |----------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
+ | `$identity` | The identity whose roles to retrieve. If `$identity` is null, then the `guest` is used. The `guest` role is definable via configuration and defaults to `'guest'`. |
+
+
diff --git a/docs/docusaurus.config.js b/docs/docusaurus.config.js
index 83083dc..205bf61 100644
--- a/docs/docusaurus.config.js
+++ b/docs/docusaurus.config.js
@@ -9,7 +9,7 @@ import {themes as prismThemes} from 'prism-react-renderer';
/** @type {import('@docusaurus/types').Config} */
const config = {
title: 'LmcRbac',
- tagline: 'Role-based access control components for your Laminas or Mezzio application',
+ tagline: 'Role-based access control components for your Laminas MVC and Mezzio application',
favicon: 'img/favicon.ico',
// Set the production url of your site here
@@ -71,15 +71,21 @@ themeConfig:
logo: {
alt: 'LM-Commons Logo',
src: 'img/LMC-logo.png',
+// href: 'https://lm-commons.github.io'
},
items: [
{
type: 'docSidebar',
sidebarId: 'documentationSidebar',
position: 'left',
- label: 'Documentation',
+ label: 'Docs',
},
- {to: '/blog', label: 'Blog', position: 'left'},
+ {
+ type: "docsVersionDropdown",
+ position: "right",
+ },
+
+// {to: '/blog', label: 'Blog', position: 'right'},
{
href: 'https://lm-commons.github.io',
label: 'LM-Commons',
@@ -87,14 +93,16 @@ themeConfig:
},
{
href: 'https://github.com/lm-commons/lmcrbac',
- label: 'GitHub',
+// label: 'GitHub',
position: 'right',
+ className: 'header-github-link',
},
],
},
footer: {
style: 'dark',
links: [
+/*
{
title: 'Docs',
items: [
@@ -104,6 +112,8 @@ themeConfig:
},
],
},
+
+ */
{
title: 'Community',
items: [
@@ -116,10 +126,13 @@ themeConfig:
{
title: 'More',
items: [
+/*
{
label: 'Blog',
to: '/blog',
},
+
+ */
{
label: 'GitHub',
href: 'https://github.com/lm-commons/lmcrbac',
diff --git a/docs/package.json b/docs/package.json
index 481e16f..61fcfd4 100644
--- a/docs/package.json
+++ b/docs/package.json
@@ -14,8 +14,8 @@
"write-heading-ids": "docusaurus write-heading-ids"
},
"dependencies": {
- "@docusaurus/core": "^3.4.0",
- "@docusaurus/preset-classic": "^3.4.0",
+ "@docusaurus/core": "^3.5.2",
+ "@docusaurus/preset-classic": "^3.5.2",
"@mdx-js/react": "^3.0.0",
"clsx": "^2.0.0",
"prism-react-renderer": "^2.3.0",
@@ -23,8 +23,8 @@
"react-dom": "^18.0.0"
},
"devDependencies": {
- "@docusaurus/module-type-aliases": "^3.4.0",
- "@docusaurus/types": "^3.4.0"
+ "@docusaurus/module-type-aliases": "^3.5.2",
+ "@docusaurus/types": "^3.5.2"
},
"browserslist": {
"production": [
diff --git a/docs/src/components/HomepageFeatures/index.js b/docs/src/components/HomepageFeatures/index.js
index ab6064e..8392231 100644
--- a/docs/src/components/HomepageFeatures/index.js
+++ b/docs/src/components/HomepageFeatures/index.js
@@ -57,15 +57,9 @@ export default function HomepageFeatures() {
Introduction
-
Components and services to provide role-based access control (RBAC) to your application.
+
LmcRbac offers components and services to implement role-based access control (RBAC) in your
+ application. LmcRbac extends the components provided by laminas-permissions-rbac.
LmcRbac can be used in Laminas MVC and in Mezzio applications.