Completed
Push — EZP-31383 ( 83ce0c )
by
unknown
19:12
created

UserHandler   A

Complexity

Total Complexity 39

Size/Duplication

Total Lines 527
Duplicated Lines 19.73 %

Coupling/Cohesion

Components 1
Dependencies 13

Importance

Changes 0
Metric Value
dl 104
loc 527
c 0
b 0
f 0
rs 9.28
wmc 39
lcom 1
cbo 13

31 Methods

Rating   Name   Duplication   Size   Complexity  
A init() 0 34 1
A create() 0 15 1
A load() 12 12 1
A loadByLogin() 13 13 1
A loadByEmail() 0 12 1
A loadUserByToken() 0 27 1
A update() 12 12 1
A updateUserToken() 11 11 1
A expireUserToken() 0 8 1
A delete() 10 10 1
A createRole() 0 6 1
A createRoleDraft() 0 6 1
A copyRole() 0 6 1
A loadRole() 18 18 2
A loadRoleByIdentifier() 19 19 2
A loadRoleDraftByRoleId() 0 6 1
A loadRoles() 0 6 1
A loadRoleAssignment() 0 12 1
A loadRoleAssignmentsByRoleId() 0 16 1
A loadRoleAssignmentsByGroupId() 0 32 4
A updateRole() 0 7 1
A deleteRole() 0 11 2
A publishRoleDraft() 0 14 2
A addPolicyByRoleDraft() 0 6 1
A addPolicy() 0 9 1
A updatePolicy() 0 9 1
A deletePolicy() 0 7 1
A loadPoliciesByUserId() 0 6 1
A assignRole() 0 15 2
A unassignRole() 9 9 1
A removeRoleAssignment() 0 9 1

How to fix   Duplicated Code   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

1
<?php
2
3
/**
4
 * File containing a User Handler impl.
5
 *
6
 * @copyright Copyright (C) eZ Systems AS. All rights reserved.
7
 * @license For full copyright and license information view LICENSE file distributed with this source code.
8
 */
9
namespace eZ\Publish\Core\Persistence\Cache;
10
11
use eZ\Publish\SPI\Persistence\User\UserTokenUpdateStruct;
12
use eZ\Publish\SPI\Persistence\User\Handler as UserHandlerInterface;
13
use eZ\Publish\SPI\Persistence\User;
14
use eZ\Publish\SPI\Persistence\User\Role;
15
use eZ\Publish\SPI\Persistence\User\RoleAssignment;
16
use eZ\Publish\SPI\Persistence\User\RoleCreateStruct;
17
use eZ\Publish\SPI\Persistence\User\RoleCopyStruct;
18
use eZ\Publish\SPI\Persistence\User\RoleUpdateStruct;
19
use eZ\Publish\SPI\Persistence\User\Policy;
20
21
/**
22
 * Cache handler for user module.
23
 */
24
class UserHandler extends AbstractInMemoryPersistenceHandler implements UserHandlerInterface
25
{
26
    /** @var callable */
27
    private $getUserTags;
28
29
    /** @var callable */
30
    private $getUserKeys;
31
32
    /** @var callable */
33
    private $getRoleTags;
34
35
    /** @var callable */
36
    private $getRoleKeys;
37
38
    /** @var callable */
39
    private $getRoleAssignmentTags;
40
41
    /** @var callable */
42
    private $getRoleAssignmentKeys;
43
44
    /**
45
     * Set callback functions for use in cache retrival.
46
     */
47
    public function init(): void
48
    {
49
        $this->getUserTags = static function (User $user) {
50
            return ['content-' . $user->id, 'user-' . $user->id];
51
        };
52
        $this->getUserKeys = function (User $user) {
53
            return [
54
                'ez-user-' . $user->id,
55
                'ez-user-' . $this->escapeForCacheKey($user->login) . '-by-login',
56
                //'ez-user-' . $hash . '-by-account-key',
57
            ];
58
        };
59
        $this->getRoleTags = static function (Role $role) {
60
            return ['role-' . $role->id];
61
        };
62
        $this->getRoleKeys = static function (Role $role) {
63
            return [
64
                'ez-role-' . $role->id,
65
                'ez-role-' . $role->identifier . '-by-identifier',
66
            ];
67
        };
68
        $this->getRoleAssignmentTags = static function (RoleAssignment $roleAssignment) {
69
            return [
70
                'role-assignment-' . $roleAssignment->id,
71
                'role-assignment-group-list-' . $roleAssignment->contentId,
72
                'role-assignment-role-list-' . $roleAssignment->roleId,
73
            ];
74
        };
75
        $this->getRoleAssignmentKeys = static function (RoleAssignment $roleAssignment) {
76
            return [
77
                'ez-role-assignment-' . $roleAssignment->id,
78
            ];
79
        };
80
    }
81
82
    /**
83
     * {@inheritdoc}
84
     */
85
    public function create(User $user)
86
    {
87
        $this->logger->logCall(__METHOD__, ['struct' => $user]);
88
        $return = $this->persistenceHandler->userHandler()->create($user);
89
90
        // Clear corresponding content cache as creation of the User changes it's external data
91
        $this->cache->invalidateTags(['content-' . $user->id]);
92
        $this->cache->deleteItems([
93
            'ez-user-' . $user->id,
94
            'ez-user-' . $this->escapeForCacheKey($user->login) . '-by-login',
95
            'ez-user-' . $this->escapeForCacheKey($user->email) . '-by-email',
96
        ]);
97
98
        return $return;
99
    }
100
101
    /**
102
     * {@inheritdoc}
103
     */
104 View Code Duplication
    public function load($userId)
105
    {
106
        return $this->getCacheValue(
107
            $userId,
108
            'ez-user-',
109
            function ($userId) {
110
                return $this->persistenceHandler->userHandler()->load($userId);
111
            },
112
            $this->getUserTags,
113
            $this->getUserKeys
114
        );
115
    }
116
117
    /**
118
     * {@inheritdoc}
119
     */
120 View Code Duplication
    public function loadByLogin($login)
121
    {
122
        return $this->getCacheValue(
123
            $this->escapeForCacheKey($login),
124
            'ez-user-',
125
            function ($escapedLogin) use ($login) {
0 ignored issues
show
Unused Code introduced by
The parameter $escapedLogin is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
126
                return $this->persistenceHandler->userHandler()->loadByLogin($login);
127
            },
128
            $this->getUserTags,
129
            $this->getUserKeys,
130
            '-by-login'
131
        );
132
    }
133
134
    /**
135
     * {@inheritdoc}
136
     */
137
    public function loadByEmail($email)
138
    {
139
        // As load by email can return several items we threat it like a list here.
140
        return $this->getListCacheValue(
141
            'ez-user-' . $this->escapeForCacheKey($email) . '-by-email',
142
            function () use ($email) {
143
                return $this->persistenceHandler->userHandler()->loadByEmail($email);
144
            },
145
            $this->getUserTags,
146
            $this->getUserKeys
147
        );
148
    }
149
150
    /**
151
     * {@inheritdoc}
152
     */
153
    public function loadUserByToken($hash)
154
    {
155
        $getUserKeysFn = $this->getUserKeys;
156
        $getUserTagsFn = $this->getUserTags;
157
158
        return $this->getCacheValue(
159
            $hash,
160
            'ez-user-',
161
            function ($hash) {
162
                return $this->persistenceHandler->userHandler()->loadUserByToken($hash);
163
            },
164
            static function (User $user) use ($getUserTagsFn) {
165
                $tags = $getUserTagsFn($user);
166
                // See updateUserToken()
167
                $tags[] = 'user-' . $user->id . '-account-key';
168
169
                return $tags;
170
            },
171
            static function (User $user) use ($hash, $getUserKeysFn) {
172
                $keys = $getUserKeysFn($user);
173
                $keys[] = 'ez-user-' . $hash . '-by-account-key';
174
175
                return $keys;
176
            },
177
            '-by-account-key'
178
        );
179
    }
180
181
    /**
182
     * {@inheritdoc}
183
     */
184 View Code Duplication
    public function update(User $user)
185
    {
186
        $this->logger->logCall(__METHOD__, ['struct' => $user]);
187
        $return = $this->persistenceHandler->userHandler()->update($user);
188
189
        // Clear corresponding content cache as update of the User changes it's external data
190
        $this->cache->invalidateTags(['content-' . $user->id, 'user-' . $user->id]);
191
        // Clear especially by email key as it might already be cached and this might represent change to email
192
        $this->cache->deleteItems(['ez-user-' . $this->escapeForCacheKey($user->email) . '-by-email']);
193
194
        return $return;
195
    }
196
197
    /**
198
     * {@inheritdoc}
199
     */
200 View Code Duplication
    public function updateUserToken(UserTokenUpdateStruct $userTokenUpdateStruct)
201
    {
202
        $this->logger->logCall(__METHOD__, ['struct' => $userTokenUpdateStruct]);
203
        $return = $this->persistenceHandler->userHandler()->updateUserToken($userTokenUpdateStruct);
204
205
        // As we 1. don't know original hash, and 2. hash is not guaranteed to be unique, we do it like this for now
206
        $this->cache->invalidateTags(['user-' . $userTokenUpdateStruct->userId . '-account-key']);
207
        $this->cache->deleteItems(['ez-user-' . $userTokenUpdateStruct->hashKey . '-by-account-key']);
208
209
        return $return;
210
    }
211
212
    /**
213
     * {@inheritdoc}
214
     */
215
    public function expireUserToken($hash)
216
    {
217
        $this->logger->logCall(__METHOD__, ['hash' => $hash]);
218
        $return = $this->persistenceHandler->userHandler()->expireUserToken($hash);
219
        $this->cache->deleteItems(['ez-user-' . $hash . '-by-account-key']);
220
221
        return $return;
222
    }
223
224
    /**
225
     * {@inheritdoc}
226
     */
227 View Code Duplication
    public function delete($userId)
228
    {
229
        $this->logger->logCall(__METHOD__, ['user' => $userId]);
230
        $return = $this->persistenceHandler->userHandler()->delete($userId);
231
232
        // user id == content id == group id
233
        $this->cache->invalidateTags(['content-' . $userId, 'user-' . $userId]);
234
235
        return $return;
236
    }
237
238
    /**
239
     * {@inheritdoc}
240
     */
241
    public function createRole(RoleCreateStruct $createStruct)
242
    {
243
        $this->logger->logCall(__METHOD__, ['struct' => $createStruct]);
244
245
        return $this->persistenceHandler->userHandler()->createRole($createStruct);
246
    }
247
248
    /**
249
     * {@inheritdoc}
250
     */
251
    public function createRoleDraft($roleId)
252
    {
253
        $this->logger->logCall(__METHOD__, ['role' => $roleId]);
254
255
        return $this->persistenceHandler->userHandler()->createRoleDraft($roleId);
256
    }
257
258
    /**
259
     * {@inheritdoc}
260
     */
261
    public function copyRole(RoleCopyStruct $copyStruct)
262
    {
263
        $this->logger->logCall(__METHOD__, ['struct' => $copyStruct]);
264
265
        return $this->persistenceHandler->userHandler()->copyRole($copyStruct);
266
    }
267
268
    /**
269
     * {@inheritdoc}
270
     */
271 View Code Duplication
    public function loadRole($roleId, $status = Role::STATUS_DEFINED)
272
    {
273
        if ($status !== Role::STATUS_DEFINED) {
274
            $this->logger->logCall(__METHOD__, ['role' => $roleId]);
275
276
            return $this->persistenceHandler->userHandler()->loadRole($roleId, $status);
277
        }
278
279
        return $this->getCacheValue(
280
            $roleId,
281
            'ez-role-',
282
            function ($roleId) {
283
                return $this->persistenceHandler->userHandler()->loadRole($roleId);
284
            },
285
            $this->getRoleTags,
286
            $this->getRoleKeys
287
        );
288
    }
289
290
    /**
291
     * {@inheritdoc}
292
     */
293 View Code Duplication
    public function loadRoleByIdentifier($identifier, $status = Role::STATUS_DEFINED)
294
    {
295
        if ($status !== Role::STATUS_DEFINED) {
296
            $this->logger->logCall(__METHOD__, ['role' => $identifier]);
297
298
            return $this->persistenceHandler->userHandler()->loadRoleByIdentifier($identifier, $status);
299
        }
300
301
        return $this->getCacheValue(
302
            $identifier,
303
            'ez-role-',
304
            function ($identifier) {
305
                return $this->persistenceHandler->userHandler()->loadRoleByIdentifier($identifier);
306
            },
307
            $this->getRoleTags,
308
            $this->getRoleKeys,
309
            '-by-identifier'
310
        );
311
    }
312
313
    /**
314
     * {@inheritdoc}
315
     */
316
    public function loadRoleDraftByRoleId($roleId)
317
    {
318
        $this->logger->logCall(__METHOD__, ['role' => $roleId]);
319
320
        return $this->persistenceHandler->userHandler()->loadRoleDraftByRoleId($roleId);
321
    }
322
323
    /**
324
     * {@inheritdoc}
325
     */
326
    public function loadRoles()
327
    {
328
        $this->logger->logCall(__METHOD__);
329
330
        return $this->persistenceHandler->userHandler()->loadRoles();
331
    }
332
333
    /**
334
     * {@inheritdoc}
335
     */
336
    public function loadRoleAssignment($roleAssignmentId)
337
    {
338
        return $this->getCacheValue(
339
            $roleAssignmentId,
340
            'ez-role-assignment-',
341
            function ($roleAssignmentId) {
342
                return $this->persistenceHandler->userHandler()->loadRoleAssignment($roleAssignmentId);
343
            },
344
            $this->getRoleAssignmentTags,
345
            $this->getRoleAssignmentKeys
346
        );
347
    }
348
349
    /**
350
     * {@inheritdoc}
351
     */
352
    public function loadRoleAssignmentsByRoleId($roleId)
353
    {
354
        return $this->getListCacheValue(
355
            "ez-role-assignment-${roleId}-by-role",
356
            function () use ($roleId) {
357
                return $this->persistenceHandler->userHandler()->loadRoleAssignmentsByRoleId($roleId);
358
            },
359
            $this->getRoleAssignmentTags,
360
            $this->getRoleAssignmentKeys,
361
            /* Role update (policies) changes role assignment id, also need list tag in case of empty result */
362
            static function () use ($roleId) {
363
                return ['role-assignment-role-list-' . $roleId, 'role-' . $roleId];
364
            },
365
            [$roleId]
366
        );
367
    }
368
369
    /**
370
     * {@inheritdoc}
371
     */
372
    public function loadRoleAssignmentsByGroupId($groupId, $inherit = false)
373
    {
374
        $innerHandler = $this->persistenceHandler;
375
        if ($inherit) {
376
            $key = "ez-role-assignment-${groupId}-by-group-inherited";
377
        } else {
378
            $key = "ez-role-assignment-${groupId}-by-group";
379
        }
380
381
        return $this->getListCacheValue(
382
            $key,
383
            function () use ($groupId, $inherit) {
384
                return $this->persistenceHandler->userHandler()->loadRoleAssignmentsByGroupId($groupId, $inherit);
385
            },
386
            $this->getRoleAssignmentTags,
387
            $this->getRoleAssignmentKeys,
388
            static function () use ($groupId, $innerHandler) {
389
                // Tag needed for empty results, if not empty will alse be added by getRoleAssignmentTags().
390
                $cacheTags = ['role-assignment-group-list-' . $groupId];
391
                // To make sure tree operations affecting this can clear the permission cache
392
                $locations = $innerHandler->locationHandler()->loadLocationsByContent($groupId);
393
                foreach ($locations as $location) {
394
                    foreach (explode('/', trim($location->pathString, '/')) as $pathId) {
395
                        $cacheTags[] = 'location-path-' . $pathId;
396
                    }
397
                }
398
399
                return $cacheTags;
400
            },
401
            [$groupId, $inherit]
402
        );
403
    }
404
405
    /**
406
     * {@inheritdoc}
407
     */
408
    public function updateRole(RoleUpdateStruct $struct)
409
    {
410
        $this->logger->logCall(__METHOD__, ['struct' => $struct]);
411
        $this->persistenceHandler->userHandler()->updateRole($struct);
412
413
        $this->cache->invalidateTags(['role-' . $struct->id]);
414
    }
415
416
    /**
417
     * {@inheritdoc}
418
     */
419
    public function deleteRole($roleId, $status = Role::STATUS_DEFINED)
420
    {
421
        $this->logger->logCall(__METHOD__, ['role' => $roleId]);
422
        $return = $this->persistenceHandler->userHandler()->deleteRole($roleId, $status);
423
424
        if ($status === Role::STATUS_DEFINED) {
425
            $this->cache->invalidateTags(['role-' . $roleId, 'role-assignment-role-list-' . $roleId]);
426
        }
427
428
        return $return;
429
    }
430
431
    /**
432
     * {@inheritdoc}
433
     */
434
    public function publishRoleDraft($roleDraftId)
435
    {
436
        $this->logger->logCall(__METHOD__, ['role' => $roleDraftId]);
437
        $userHandler = $this->persistenceHandler->userHandler();
438
        $roleDraft = $userHandler->loadRole($roleDraftId, Role::STATUS_DRAFT);
439
        $return = $userHandler->publishRoleDraft($roleDraftId);
440
441
        // If there was a original role for the draft, then we clean cache for it
442
        if ($roleDraft->originalId > -1) {
443
            $this->cache->invalidateTags(['role-' . $roleDraft->originalId]);
444
        }
445
446
        return $return;
447
    }
448
449
    /**
450
     * {@inheritdoc}
451
     */
452
    public function addPolicyByRoleDraft($roleId, Policy $policy)
453
    {
454
        $this->logger->logCall(__METHOD__, ['role' => $roleId, 'struct' => $policy]);
455
456
        return $this->persistenceHandler->userHandler()->addPolicyByRoleDraft($roleId, $policy);
457
    }
458
459
    /**
460
     * {@inheritdoc}
461
     */
462
    public function addPolicy($roleId, Policy $policy)
463
    {
464
        $this->logger->logCall(__METHOD__, ['role' => $roleId, 'struct' => $policy]);
465
        $return = $this->persistenceHandler->userHandler()->addPolicy($roleId, $policy);
466
467
        $this->cache->invalidateTags(['role-' . $roleId]);
468
469
        return $return;
470
    }
471
472
    /**
473
     * {@inheritdoc}
474
     */
475
    public function updatePolicy(Policy $policy)
476
    {
477
        $this->logger->logCall(__METHOD__, ['struct' => $policy]);
478
        $return = $this->persistenceHandler->userHandler()->updatePolicy($policy);
479
480
        $this->cache->invalidateTags(['policy-' . $policy->id, 'role-' . $policy->roleId]);
481
482
        return $return;
483
    }
484
485
    /**
486
     * {@inheritdoc}
487
     */
488
    public function deletePolicy($policyId, $roleId)
489
    {
490
        $this->logger->logCall(__METHOD__, ['policy' => $policyId]);
491
        $this->persistenceHandler->userHandler()->deletePolicy($policyId, $roleId);
492
493
        $this->cache->invalidateTags(['policy-' . $policyId, 'role-' . $roleId]);
494
    }
495
496
    /**
497
     * {@inheritdoc}
498
     */
499
    public function loadPoliciesByUserId($userId)
500
    {
501
        $this->logger->logCall(__METHOD__, ['user' => $userId]);
502
503
        return $this->persistenceHandler->userHandler()->loadPoliciesByUserId($userId);
0 ignored issues
show
Deprecated Code introduced by
The method eZ\Publish\SPI\Persisten...:loadPoliciesByUserId() has been deprecated with message: Since 6.8, not currently in use as permission system needs to know about role assignment limitations.

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
504
    }
505
506
    /**
507
     * {@inheritdoc}
508
     */
509
    public function assignRole($contentId, $roleId, array $limitation = null)
510
    {
511
        $this->logger->logCall(__METHOD__, ['group' => $contentId, 'role' => $roleId, 'limitation' => $limitation]);
512
        $return = $this->persistenceHandler->userHandler()->assignRole($contentId, $roleId, $limitation);
513
514
        $tags = ['role-assignment-group-list-' . $contentId, 'role-assignment-role-list-' . $roleId];
515
        $locations = $this->persistenceHandler->locationHandler()->loadLocationsByContent($contentId);
516
        foreach ($locations as $location) {
517
            $tags[] = 'location-path-' . $location->id;
518
        }
519
520
        $this->cache->invalidateTags($tags);
521
522
        return $return;
523
    }
524
525
    /**
526
     * {@inheritdoc}
527
     */
528 View Code Duplication
    public function unassignRole($contentId, $roleId)
529
    {
530
        $this->logger->logCall(__METHOD__, ['group' => $contentId, 'role' => $roleId]);
531
        $return = $this->persistenceHandler->userHandler()->unassignRole($contentId, $roleId);
532
533
        $this->cache->invalidateTags(['role-assignment-group-list-' . $contentId, 'role-assignment-role-list-' . $roleId]);
534
535
        return $return;
536
    }
537
538
    /**
539
     * {@inheritdoc}
540
     */
541
    public function removeRoleAssignment($roleAssignmentId)
542
    {
543
        $this->logger->logCall(__METHOD__, ['assignment' => $roleAssignmentId]);
544
        $return = $this->persistenceHandler->userHandler()->removeRoleAssignment($roleAssignmentId);
545
546
        $this->cache->invalidateTags(['role-assignment-' . $roleAssignmentId]);
547
548
        return $return;
549
    }
550
}
551