Passed
Push — master ( a1c8ef...32b200 )
by ABDULMALIK
10:56
created

RbacManager::createPermission()   A

Complexity

Conditions 3
Paths 4

Size

Total Lines 16
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Importance

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