Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
80.85% covered (warning)
80.85%
38 / 47
70.59% covered (warning)
70.59%
12 / 17
CRAP
0.00% covered (danger)
0.00%
0 / 1
CachedProfilePermissionRepository
80.43% covered (warning)
80.43%
37 / 46
70.59% covered (warning)
70.59%
12 / 17
32.46
0.00% covered (danger)
0.00%
0 / 1
 __construct
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getProfile
100.00% covered (success)
100.00%
6 / 6
100.00% covered (success)
100.00%
1 / 1
3
 getAllProfiles
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getModulePermissions
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
1 / 1
2
 getFieldPermissions
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 canViewModule
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
2
 canCreateInModule
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
6
 canEditInModule
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
6
 canDeleteInModule
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
2
 getFieldPermission
100.00% covered (success)
100.00%
6 / 6
100.00% covered (success)
100.00%
1 / 1
2
 setModulePermission
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 bulkSetModulePermission
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 setFieldPermission
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 bulkSetFieldPermissions
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 saveMatrix
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
2
 copyPermissions
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 invalidateCache
66.67% covered (warning)
66.67%
4 / 6
0.00% covered (danger)
0.00%
0 / 1
3.33
1<?php
2
3declare(strict_types=1);
4
5/** @license For full copyright and license information, please see the LICENSE.md file. */
6
7namespace App\Modules\Profiles\Infrastructure\Repository;
8
9defined('AMMONLY_APP') || exit('Direct script access is forbidden.');
10
11use App\Modules\Profiles\Domain\Model\FieldPermissionType;
12use App\Modules\Profiles\Domain\Model\PermissionProfile;
13use App\Modules\Profiles\Domain\Model\ProfileFieldPermission;
14use App\Modules\Profiles\Domain\Model\ProfileModulePermission;
15use App\Modules\Profiles\Domain\Repository\ProfilePermissionRepositoryInterface;
16
17/**
18 * Cached Profile Permission Repository Decorator.
19 *
20 * Provides ultra-fast 0ms in-memory and request-scoped caching for permission lookups.
21 *
22 * @package App\Modules\Profiles\Infrastructure\Repository
23 */
24final class CachedProfilePermissionRepository implements ProfilePermissionRepositoryInterface
25{
26    /** @var array<int, PermissionProfile> */
27    private array $profileCache = [];
28
29    /** @var array<int, array<string, ProfileModulePermission>> */
30    private array $modulePermsCache = [];
31
32    /** @var array<string, FieldPermissionType> */
33    private array $fieldPermCache = [];
34
35    /**
36     * CachedProfilePermissionRepository constructor.
37     *
38     * @param ProfilePermissionRepositoryInterface $inner Concrete persistence repository.
39     */
40    public function __construct(private readonly ProfilePermissionRepositoryInterface $inner)
41    {
42    }
43
44    /**
45     * @inheritDoc
46     */
47    public function getProfile(int $profileId): ?PermissionProfile
48    {
49        if (isset($this->profileCache[$profileId])) {
50            return $this->profileCache[$profileId];
51        }
52
53        $profile = $this->inner->getProfile($profileId);
54        if ($profile !== null) {
55            $this->profileCache[$profileId] = $profile;
56        }
57
58        return $profile;
59    }
60
61    /**
62     * @inheritDoc
63     */
64    public function getAllProfiles(): array
65    {
66        return $this->inner->getAllProfiles();
67    }
68
69    /**
70     * @inheritDoc
71     */
72    public function getModulePermissions(int $profileId): array
73    {
74        if (isset($this->modulePermsCache[$profileId])) {
75            return $this->modulePermsCache[$profileId];
76        }
77
78        $perms = $this->inner->getModulePermissions($profileId);
79        $this->modulePermsCache[$profileId] = $perms;
80
81        return $perms;
82    }
83
84    /**
85     * @inheritDoc
86     */
87    public function getFieldPermissions(int $profileId, ?string $moduleName = null): array
88    {
89        return $this->inner->getFieldPermissions($profileId, $moduleName);
90    }
91
92    /**
93     * @inheritDoc
94     */
95    public function canViewModule(int $profileId, string $moduleName): bool
96    {
97        $perms = $this->getModulePermissions($profileId);
98
99        return isset($perms[$moduleName]) ? $perms[$moduleName]->canView : true;
100    }
101
102    /**
103     * @inheritDoc
104     */
105    public function canCreateInModule(int $profileId, string $moduleName): bool
106    {
107        $perms = $this->getModulePermissions($profileId);
108
109        return isset($perms[$moduleName]) ? $perms[$moduleName]->canCreate : true;
110    }
111
112    /**
113     * @inheritDoc
114     */
115    public function canEditInModule(int $profileId, string $moduleName): bool
116    {
117        $perms = $this->getModulePermissions($profileId);
118
119        return isset($perms[$moduleName]) ? $perms[$moduleName]->canEdit : true;
120    }
121
122    /**
123     * @inheritDoc
124     */
125    public function canDeleteInModule(int $profileId, string $moduleName): bool
126    {
127        $perms = $this->getModulePermissions($profileId);
128
129        return isset($perms[$moduleName]) ? $perms[$moduleName]->canDelete : true;
130    }
131
132    /**
133     * @inheritDoc
134     */
135    public function getFieldPermission(int $profileId, string $moduleName, string $fieldKey): FieldPermissionType
136    {
137        $cacheKey = "{$profileId}:{$moduleName}:{$fieldKey}";
138        if (isset($this->fieldPermCache[$cacheKey])) {
139            return $this->fieldPermCache[$cacheKey];
140        }
141
142        $perm = $this->inner->getFieldPermission($profileId, $moduleName, $fieldKey);
143        $this->fieldPermCache[$cacheKey] = $perm;
144
145        return $perm;
146    }
147
148    /**
149     * @inheritDoc
150     */
151    public function setModulePermission(
152        int    $profileId,
153        string $moduleName,
154        bool   $canView,
155        bool   $canCreate,
156        bool   $canEdit,
157        bool   $canDelete
158    ): void {
159        $this->inner->setModulePermission($profileId, $moduleName, $canView, $canCreate, $canEdit, $canDelete);
160        $this->invalidateCache($profileId);
161    }
162
163    /**
164     * @inheritDoc
165     */
166    public function bulkSetModulePermission(int $profileId, string $action, bool $value): void
167    {
168        $this->inner->bulkSetModulePermission($profileId, $action, $value);
169        $this->invalidateCache($profileId);
170    }
171
172    /**
173     * @inheritDoc
174     */
175    public function setFieldPermission(
176        int                 $profileId,
177        string              $moduleName,
178        string              $fieldKey,
179        FieldPermissionType $permission
180    ): void {
181        $this->inner->setFieldPermission($profileId, $moduleName, $fieldKey, $permission);
182        unset($this->fieldPermCache["{$profileId}:{$moduleName}:{$fieldKey}"]);
183    }
184
185    /**
186     * @inheritDoc
187     */
188    public function bulkSetFieldPermissions(
189        int                 $profileId,
190        string              $moduleName,
191        FieldPermissionType $permission
192    ): void {
193        $this->inner->bulkSetFieldPermissions($profileId, $moduleName, $permission);
194        $this->invalidateCache($profileId);
195    }
196
197    /**
198     * @inheritDoc
199     */
200    public function saveMatrix(int $profileId, array $modules, array $fields): void
201    {
202        $this->inner->saveMatrix($profileId, $modules, $fields);
203        $this->invalidateCache($profileId);
204    }
205
206    /**
207     * @inheritDoc
208     */
209    public function copyPermissions(int $sourceProfileId, int $targetProfileId): void
210    {
211        $this->inner->copyPermissions($sourceProfileId, $targetProfileId);
212        $this->invalidateCache($targetProfileId);
213    }
214
215    /**
216     * @inheritDoc
217     */
218    public function invalidateCache(int $profileId): void
219    {
220        unset($this->profileCache[$profileId], $this->modulePermsCache[$profileId]);
221
222        $prefix = "{$profileId}:";
223        foreach (array_keys($this->fieldPermCache) as $key) {
224            if (str_starts_with($key, $prefix)) {
225                unset($this->fieldPermCache[$key]);
226            }
227        }
228
229        $this->inner->invalidateCache($profileId);
230    }
231}