Skip to content

Commit 7a09416

Browse files
author
Marcin Stodulski
committed
initial commit
0 parents  commit 7a09416

File tree

11 files changed

+703
-0
lines changed

11 files changed

+703
-0
lines changed

.gitignore

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
tests/.phpunit.cache
2+
/composer.phar
3+
/composer
4+
/composer.lock
5+
/.idea/**
6+
/vendor/

LICENSE

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
MIT License
2+
3+
Copyright (c) 2022 mstodulski
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE.

composer.json

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
{
2+
"name": "mstodulski/rbac-with-permissions",
3+
"license": "MIT",
4+
"description": "",
5+
"require": {
6+
"php": ">=8.1",
7+
"phpunit/phpunit": "9.5.*"
8+
},
9+
"keywords": ["rbac", "permissions"],
10+
"homepage": "https://devsprint.pl",
11+
"authors": [
12+
{
13+
"name": "Marcin Stodulski",
14+
"homepage": "https://devsprint.pl",
15+
"role": "Developer"
16+
}
17+
],
18+
"autoload": {
19+
"psr-4": {
20+
"mstodulski\\RbacWithPermissions\\": "src"
21+
}
22+
}
23+
}

src/entities/Permission.php

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
<?php
2+
/**
3+
* This file is part of the EasySoft package.
4+
*
5+
* (c) Marcin Stodulski <[email protected]>
6+
*
7+
* For the full copyright and license information, please view the LICENSE
8+
* file that was distributed with this source code.
9+
*/
10+
11+
namespace mstodulski\RbacWithPermissions\entities;
12+
13+
use mstodulski\RbacWithPermissions\interfaces\PermissionInterface;
14+
15+
class Permission implements PermissionInterface
16+
{
17+
private ?self $parent = null;
18+
private string $code = '';
19+
private string $name = '';
20+
21+
public function setCode(string $code): void
22+
{
23+
$this->code = $code;
24+
}
25+
26+
public function getCode(): string
27+
{
28+
return $this->code;
29+
}
30+
31+
public function getName(): string
32+
{
33+
return $this->name;
34+
}
35+
36+
public function setName(string $name): void
37+
{
38+
$this->name = $name;
39+
}
40+
41+
public function getParent(): ?PermissionInterface
42+
{
43+
return $this->parent;
44+
}
45+
46+
public function setParent(?PermissionInterface $parent): void
47+
{
48+
$this->parent = $parent;
49+
}
50+
}

src/entities/Role.php

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
<?php
2+
/**
3+
* This file is part of the EasySoft package.
4+
*
5+
* (c) Marcin Stodulski <[email protected]>
6+
*
7+
* For the full copyright and license information, please view the LICENSE
8+
* file that was distributed with this source code.
9+
*/
10+
11+
namespace mstodulski\RbacWithPermissions\entities;
12+
13+
use mstodulski\RbacWithPermissions\interfaces\PermissionInterface;
14+
use mstodulski\RbacWithPermissions\interfaces\RoleInterface;
15+
16+
class Role implements RoleInterface
17+
{
18+
private string $code = '';
19+
private ?self $parent = null;
20+
private string $name = '';
21+
/** @var $permissions PermissionInterface[] */
22+
private array $permissions = [];
23+
private bool $hasAllPermissions = false;
24+
25+
public function getCode(): string
26+
{
27+
return $this->code;
28+
}
29+
30+
public function setCode(string $code): void
31+
{
32+
$this->code = $code;
33+
}
34+
35+
public function getName(): string
36+
{
37+
return $this->name;
38+
}
39+
40+
public function setName(string $name): void
41+
{
42+
$this->name = $name;
43+
}
44+
45+
public function getParent(): ?RoleInterface
46+
{
47+
return $this->parent;
48+
}
49+
50+
public function setParent(?RoleInterface $parent): void
51+
{
52+
$this->parent = $parent;
53+
}
54+
55+
public function getPermissions(): array
56+
{
57+
return $this->permissions;
58+
}
59+
60+
public function setPermissions(array $permissions): void
61+
{
62+
$this->permissions = $permissions;
63+
}
64+
65+
public function addPermission(PermissionInterface $permission)
66+
{
67+
$this->permissions[$permission->getCode()] = $permission;
68+
}
69+
70+
public function isHasAllPermissions(): bool
71+
{
72+
return $this->hasAllPermissions;
73+
}
74+
75+
public function setHasAllPermissions(bool $hasAllPermissions): void
76+
{
77+
$this->hasAllPermissions = $hasAllPermissions;
78+
}
79+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
<?php
2+
/**
3+
* This file is part of the EasySoft package.
4+
*
5+
* (c) Marcin Stodulski <[email protected]>
6+
*
7+
* For the full copyright and license information, please view the LICENSE
8+
* file that was distributed with this source code.
9+
*/
10+
11+
namespace mstodulski\RbacWithPermissions\interfaces;
12+
13+
interface PermissionInterface
14+
{
15+
public function getParent(): ?PermissionInterface;
16+
public function getCode(): string;
17+
}

src/interfaces/RoleInterface.php

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
<?php
2+
/**
3+
* This file is part of the EasySoft package.
4+
*
5+
* (c) Marcin Stodulski <[email protected]>
6+
*
7+
* For the full copyright and license information, please view the LICENSE
8+
* file that was distributed with this source code.
9+
*/
10+
11+
namespace mstodulski\RbacWithPermissions\interfaces;
12+
13+
interface RoleInterface
14+
{
15+
public function getParent(): ?RoleInterface;
16+
public function getCode(): string;
17+
public function getPermissions(): array;
18+
public function isHasAllPermissions(): bool;
19+
}

src/services/Authorization.php

Lines changed: 150 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,150 @@
1+
<?php
2+
/**
3+
* This file is part of the EasySoft package.
4+
*
5+
* (c) Marcin Stodulski <[email protected]>
6+
*
7+
* For the full copyright and license information, please view the LICENSE
8+
* file that was distributed with this source code.
9+
*/
10+
11+
namespace mstodulski\RbacWithPermissions\services;
12+
13+
use mstodulski\RbacWithPermissions\interfaces\PermissionInterface;
14+
use mstodulski\RbacWithPermissions\interfaces\RoleInterface;
15+
16+
class Authorization {
17+
18+
private array $roles = [];
19+
private array $permissions = [];
20+
private array $rolesTree = [];
21+
private array $permissionsTree = [];
22+
private array $permissionsForRoles = [];
23+
24+
public function defineRoles(RoleInterface ...$roles) : void
25+
{
26+
$this->roles = $roles;
27+
}
28+
29+
public function definePermissions(PermissionInterface ...$permissions) : void
30+
{
31+
$this->permissions = $permissions;
32+
}
33+
34+
public function processRolesAndPermissions() : void
35+
{
36+
$this->rolesTree = $this->buildTree($this->roles);
37+
$this->permissionsTree = $this->buildTree($this->permissions);
38+
}
39+
40+
public function rolesHasPermission(array $roles, string $permissionCode) : bool
41+
{
42+
/** @var RoleInterface $role */
43+
foreach ($roles as $role) {
44+
if ($this->roleHasPermission($role, $permissionCode)) {
45+
return true;
46+
}
47+
}
48+
return false;
49+
}
50+
51+
public function roleHasPermission(RoleInterface $role, $permissionCode): bool
52+
{
53+
if ($role->isHasAllPermissions()) {
54+
return true;
55+
} else {
56+
if (isset($this->permissionsForRoles[$role->getCode()])) {
57+
$permissionsArray = $this->permissionsForRoles[$role->getCode()];
58+
} else {
59+
[, $permissionsArray] = $this->getAllSubRolesAndPermissionsForRole($role);
60+
$this->permissionsForRoles[$role->getCode()] = $permissionsArray;
61+
}
62+
63+
return in_array($permissionCode, $permissionsArray);
64+
}
65+
}
66+
67+
public function setPermissionsTree(array $permissionsTree): void
68+
{
69+
$this->permissionsTree = $permissionsTree;
70+
}
71+
72+
public function getPermissionsTree(): array
73+
{
74+
return $this->permissionsTree;
75+
}
76+
77+
public function getAllSubRolesAndPermissionsForRole(RoleInterface $role): array
78+
{
79+
$rolesArray = [$role->getCode()];
80+
$permissionsArray = [];
81+
$this->getSubRolesCodes($rolesArray, $permissionsArray, $this->rolesTree);
82+
$this->getSubPermissionsForPermissions($permissionsArray, $this->permissionsTree);
83+
84+
return [$rolesArray, $permissionsArray];
85+
}
86+
87+
private function getSubPermissionsForPermissions(&$permissionsArray, $permissionsTree = null) : void
88+
{
89+
/** @var PermissionInterface $permission */
90+
foreach ($permissionsTree as $permission) {
91+
if (in_array($permission->getCode(), $permissionsArray)) {
92+
if (isset($permission->children)) {
93+
/** @var PermissionInterface $childPermission */
94+
foreach ($permission->children as $childPermission) {
95+
$permissionsArray[$childPermission->getCode()] = $childPermission->getCode();
96+
}
97+
}
98+
}
99+
100+
if (isset($permission->children)) {
101+
$this->getSubPermissionsForPermissions($permissionsArray, $permission->children);
102+
}
103+
}
104+
}
105+
106+
private function getSubRolesCodes(&$rolesArray, &$permissionsArray, $rolesTree = null) : void
107+
{
108+
/** @var RoleInterface $role */
109+
foreach ($rolesTree as $role) {
110+
if (in_array($role->getCode(), $rolesArray)) {
111+
foreach ($role->getPermissions() as $permission) {
112+
$permissionsArray[$permission->getCode()] = $permission->getCode();
113+
}
114+
115+
if (isset($role->children)) {
116+
/** @var RoleInterface $childRole */
117+
foreach ($role->children as $childRole) {
118+
$rolesArray[] = $childRole->getCode();
119+
foreach ($childRole->getPermissions() as $permission) {
120+
$permissionsArray[$permission->getCode()] = $permission->getCode();
121+
}
122+
}
123+
}
124+
}
125+
126+
if (isset($role->children)) {
127+
$this->getSubRolesCodes($rolesArray, $permissionsArray, $role->children);
128+
}
129+
}
130+
}
131+
132+
private function buildTree(array $elements, $parentId = null): array
133+
{
134+
$branch = array();
135+
136+
/** @var RoleInterface|PermissionInterface $element */
137+
foreach ($elements as $element) {
138+
$elementParentId = ($element->getParent() !== null) ? $element->getParent()->getCode() : null;
139+
if ($elementParentId == $parentId) {
140+
$children = $this->buildTree($elements, $element->getCode());
141+
if ($children) {
142+
$element->children = $children;
143+
}
144+
$branch[] = $element;
145+
}
146+
}
147+
148+
return $branch;
149+
}
150+
}

0 commit comments

Comments
 (0)