Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
98.94% covered (success)
98.94%
93 / 94
83.33% covered (warning)
83.33%
5 / 6
CRAP
0.00% covered (danger)
0.00%
0 / 1
Role
98.94% covered (success)
98.94%
93 / 94
83.33% covered (warning)
83.33%
5 / 6
18
0.00% covered (danger)
0.00%
0 / 1
 readRoleById
100.00% covered (success)
100.00%
8 / 8
100.00% covered (success)
100.00%
1 / 1
2
 readAllRoles
100.00% covered (success)
100.00%
11 / 11
100.00% covered (success)
100.00%
1 / 1
3
 addRole
100.00% covered (success)
100.00%
21 / 21
100.00% covered (success)
100.00%
1 / 1
2
 updateRole
100.00% covered (success)
100.00%
28 / 28
100.00% covered (success)
100.00%
1 / 1
4
 fetchPermissionsByNamesOrFail
93.75% covered (success)
93.75%
15 / 16
0.00% covered (danger)
0.00%
0 / 1
4.00
 deleteRole
100.00% covered (success)
100.00%
10 / 10
100.00% covered (success)
100.00%
1 / 1
3
1<?php
2
3namespace BO\Zmsdb;
4
5use BO\Zmsentities\Collection\RoleList as Collection;
6use BO\Zmsentities\Permission as PermissionEntity;
7use BO\Zmsentities\Role as Entity;
8
9class Role extends Base
10{
11    public function readRoleById(int $roleId, int $resolveReferences = 1): ?Entity
12    {
13        $query = new Query\Role(Query\Base::SELECT);
14        $query->addEntityMapping()
15            ->addResolvedReferences($resolveReferences)
16            ->addConditionRoleId($roleId);
17        $role = $this->fetchOne($query, new Entity());
18
19        if (! $role->hasId()) {
20            return null;
21        }
22
23        return $role;
24    }
25
26    public function readAllRoles(string $order = 'ASC', int $resolveReferences = 1): Collection
27    {
28        $roleList = new Collection();
29        $query = new Query\Role(Query\Base::SELECT);
30        $query->addEntityMapping()
31            ->addResolvedReferences($resolveReferences)
32            ->addOrderBy('id', $order);
33        $result = $this->fetchList($query, new Entity());
34        if (count($result)) {
35            foreach ($result as $entity) {
36                $entity = $this->readResolvedReferences($entity, $resolveReferences);
37                $roleList->addEntity($entity);
38            }
39        }
40        return $roleList;
41    }
42
43    public function addRole(Entity $role, int $resolveReferences = 1): ?Entity
44    {
45        $permissionNames = array_values(array_unique($role['permissions'] ?? []));
46        $permissions = $this->fetchPermissionsByNamesOrFail($permissionNames);
47
48        $query = new Query\Role(Query\Base::INSERT);
49        $query->addValues(
50            [
51                'name' => $role['name'],
52                'description' => $role['description'],
53            ]
54        );
55        $this->writeItem($query);
56        $newId = (int) $this->getWriter()->lastInsertId();
57
58        foreach ($permissions as $permission) {
59            $link = new Query\RolePermission(Query\Base::INSERT);
60            $link->addValues(
61                [
62                    'role_id' => $newId,
63                    'permission_id' => $permission['id'],
64                ]
65            );
66            $this->writeItem($link);
67        }
68
69        return $this->readRoleById($newId, $resolveReferences);
70    }
71
72    public function updateRole(int $roleId, Entity $role, int $resolveReferences = 1): ?Entity
73    {
74        $existing = $this->readRoleById($roleId);
75        if (!$existing || !$existing->hasId()) {
76            return null;
77        }
78
79        $permissionNames = array_values(array_unique($role['permissions'] ?? []));
80        $permissions = $this->fetchPermissionsByNamesOrFail($permissionNames);
81
82        $query = new Query\Role(Query\Base::UPDATE);
83        $query->addConditionRoleId($roleId);
84        $query->addValues(
85            [
86                'name' => $role['name'],
87                'description' => $role['description'],
88            ]
89        );
90        $this->writeItem($query);
91
92        $delLinks = new Query\RolePermission(Query\Base::DELETE);
93        $delLinks->addConditionRoleId($roleId);
94        $this->deleteItem($delLinks);
95
96        foreach ($permissions as $permission) {
97            $link = new Query\RolePermission(Query\Base::INSERT);
98            $link->addValues(
99                [
100                    'role_id' => $roleId,
101                    'permission_id' => $permission['id'],
102                ]
103            );
104            $this->writeItem($link);
105        }
106
107        (new Useraccount())->invalidateAllCaches();
108
109        return $this->readRoleById($roleId, $resolveReferences);
110    }
111
112    private function fetchPermissionsByNamesOrFail(array $permissionNames): array
113    {
114        if ($permissionNames === []) {
115            return [];
116        }
117        $permQuery = new Query\Permission(Query\Base::SELECT);
118        $permQuery->addEntityMapping()
119            ->addResolvedReferences(0)
120            ->addConditionNames($permissionNames);
121        $permissions = $this->fetchList($permQuery, new PermissionEntity());
122        if (count($permissions) !== count($permissionNames)) {
123            $found = [];
124            foreach ($permissions as $p) {
125                $found[$p['name']] = true;
126            }
127            $missing = array_values(array_filter($permissionNames, static fn($n) => !isset($found[$n])));
128            throw new \InvalidArgumentException(
129                'Unknown permission name(s): ' . implode(', ', $missing)
130            );
131        }
132        return $permissions;
133    }
134
135    public function deleteRole(int $roleId): ?Entity
136    {
137        $entity = $this->readRoleById($roleId);
138        $deleteAssignments = new Query\UserRole(Query\Base::DELETE);
139        $deleteAssignments->addConditionRoleId($roleId);
140        $this->deleteItem($deleteAssignments);
141        $query = new Query\Role(Query\Base::DELETE);
142        $query->addConditionRoleId($roleId);
143        $deleted = ($this->deleteItem($query)) ? $entity : null;
144        if ($deleted) {
145            (new Useraccount())->invalidateAllCaches();
146        }
147        return $deleted;
148    }
149}