Passed
Branch master (c62005)
by ABDULMALIK
02:15
created

RbacManager   A

Complexity

Total Complexity 18

Size/Duplication

Total Lines 166
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
wmc 18
eloc 63
c 0
b 0
f 0
dl 0
loc 166
rs 10

8 Methods

Rating   Name   Duplication   Size   Complexity  
A attachPermission() 0 11 2
A saveEntity() 0 7 2
A createPermission() 0 16 3
A attachChildRole() 0 13 2
A checkForCyclicHierarchy() 0 8 2
A createRole() 0 16 3
A removeAll() 0 17 2
A assign() 0 11 2
1
<?php
2
3
namespace Potievdev\SlimRbac\Component;
4
5
use Doctrine\DBAL\Exception\UniqueConstraintViolationException;
6
use Doctrine\ORM\OptimisticLockException;
7
use Doctrine\ORM\Query\QueryException;
8
use Exception;
9
use Potievdev\SlimRbac\Exception\CyclicException;
10
use Potievdev\SlimRbac\Exception\DatabaseException;
11
use Potievdev\SlimRbac\Exception\NotUniqueException;
12
use Potievdev\SlimRbac\Models\Entity\Permission;
13
use Potievdev\SlimRbac\Models\Entity\Role;
14
use Potievdev\SlimRbac\Models\Entity\RoleHierarchy;
15
use Potievdev\SlimRbac\Models\Entity\RolePermission;
16
use Potievdev\SlimRbac\Models\Entity\UserRole;
17
18
/**
19
 * Component for creating and controlling with role and permissions.
20
 * Class RbacManager
21
 * @package Potievdev\SlimRbac\Component
22
 */
23
class RbacManager extends BaseComponent
24
{
25
    /**
26
     * Deletes all data from database. Use carefully!!!
27
     *
28
     * @throws DatabaseException
29
     * @throws \Doctrine\DBAL\Driver\Exception|\Doctrine\DBAL\Exception
30
     */
31
    public function removeAll()
32
    {
33
        $pdo = $this->entityManager->getConnection()->getWrappedConnection();
34
        $pdo->beginTransaction();
35
36
        try {
37
            $pdo->exec('DELETE FROM role_permission WHERE 1 > 0');
38
            $pdo->exec('DELETE FROM role_hierarchy WHERE 1 > 0');
39
            $pdo->exec('DELETE FROM permission WHERE 1 > 0');
40
            $pdo->exec('DELETE FROM user_role WHERE 1 > 0');
41
            $pdo->exec('DELETE FROM role WHERE 1 > 0');
42
43
            $pdo->commit();
44
45
        } catch (Exception $e) {
46
            $pdo->rollBack();
47
            throw new DatabaseException($e->getMessage());
48
        }
49
    }
50
51
    /**
52
     * Creates permission instance with given name and return it.
53
     * @throws NotUniqueException|DatabaseException
54
     */
55
    public function createPermission(string $permissionMane, ?string $description = null): Permission
56
    {
57
        $permission = new Permission();
58
        $permission->setName($permissionMane);
59
60
        if (isset($description)) {
61
            $permission->setDescription($description);
62
        }
63
64
        try {
65
            $this->saveEntity($permission);
66
        } catch (UniqueConstraintViolationException $e) {
67
            throw new NotUniqueException('Permission with name ' . $permissionMane . ' already created');
68
        }
69
70
        return $permission;
71
    }
72
73
    /**
74
     * Creates role instance with given name and return it.
75
     *
76
     * @throws NotUniqueException|DatabaseException
77
     */
78
    public function createRole(string $roleName, ?string $description = null): Role
79
    {
80
        $role = new Role();
81
        $role->setName($roleName);
82
83
        if (isset($description)) {
84
            $role->setDescription($description);
85
        }
86
87
        try {
88
            $this->saveEntity($role);
89
        } catch (UniqueConstraintViolationException $e) {
90
            throw new NotUniqueException('Role with name ' . $roleName . ' already created');
91
        }
92
93
        return $role;
94
    }
95
96
    /**
97
     * Add permission to role.
98
     *
99
     * @throws DatabaseException
100
     * @throws NotUniqueException
101
     */
102
    public function attachPermission(Role $role, Permission $permission)
103
    {
104
        $rolePermission = new RolePermission();
105
106
        $rolePermission->setPermission($permission);
107
        $rolePermission->setRole($role);
108
109
        try {
110
            $this->saveEntity($rolePermission);
111
        } catch (UniqueConstraintViolationException $e) {
112
            throw new NotUniqueException('Permission ' . $permission->getName() . ' is already assigned to role ' . $role->getName());
113
        }
114
    }
115
116
    /**
117
     * Add child role to role.
118
     *
119
     * @throws CyclicException
120
     * @throws DatabaseException
121
     * @throws NotUniqueException
122
     * @throws QueryException
123
     */
124
    public function attachChildRole(Role $parentRole, Role $childRole)
125
    {
126
        $roleHierarchy = new RoleHierarchy();
127
128
        $roleHierarchy->setParentRole($parentRole);
129
        $roleHierarchy->setChildRole($childRole);
130
131
        $this->checkForCyclicHierarchy($childRole->getId(), $parentRole->getId());
132
133
        try {
134
            $this->saveEntity($roleHierarchy);
135
        }  catch (UniqueConstraintViolationException $e) {
136
            throw new NotUniqueException('Child role ' . $childRole->getName() . ' is already has parent role ' . $parentRole->getName());
137
        }
138
    }
139
140
    /**
141
     * Assign role to user.
142
     *
143
     * @throws NotUniqueException
144
     * @throws DatabaseException
145
     */
146
    public function assign(Role $role, int $userId)
147
    {
148
        $userRole = new UserRole();
149
150
        $userRole->setUserId($userId);
151
        $userRole->setRole($role);
152
153
        try {
154
            $this->saveEntity($userRole);
155
        } catch (UniqueConstraintViolationException $e) {
156
            throw new NotUniqueException('Role ' . $role->getName() . 'is already assigned to user with identifier ' . $userId);
157
        }
158
    }
159
160
    /**
161
     * Checking hierarchy cyclic line.
162
     *
163
     * @throws CyclicException
164
     * @throws QueryException
165
     */
166
    private function checkForCyclicHierarchy(int $parentRoleId, int $childRoleId): void
167
    {
168
        $result = $this->repositoryRegistry
169
            ->getRoleHierarchyRepository()
170
            ->hasChildRoleId($parentRoleId, $childRoleId);
171
172
        if ($result === true) {
173
            throw new CyclicException('There detected cyclic line. Role with id = ' . $parentRoleId . ' has child role with id =' . $childRoleId);
174
        }
175
    }
176
177
    /**
178
     * Insert or update entity.
179
     *
180
     * @throws DatabaseException|UniqueConstraintViolationException
181
     */
182
    private function saveEntity(object $entity): void
183
    {
184
        try {
185
            $this->entityManager->persist($entity);
186
            $this->entityManager->flush($entity);
187
        } catch (OptimisticLockException $e) {
188
            throw new DatabaseException($e->getMessage());
189
        }
190
    }
191
}
192