RbacManager::__construct()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

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