Completed
Push — symfony5 ( 074008...b11eb2 )
by
unknown
267:19 queued 255:17
created

Handler::deleteRole()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 10

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
nc 2
nop 2
dl 0
loc 10
rs 9.9332
c 0
b 0
f 0
1
<?php
2
3
/**
4
 * File containing the UserHandler interface.
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\Legacy\User;
10
11
use eZ\Publish\API\Repository\Exceptions\NotImplementedException;
12
use eZ\Publish\SPI\Persistence\User;
13
use eZ\Publish\SPI\Persistence\User\UserTokenUpdateStruct;
14
use eZ\Publish\SPI\Persistence\User\Handler as BaseUserHandler;
15
use eZ\Publish\SPI\Persistence\User\Role;
16
use eZ\Publish\SPI\Persistence\User\RoleCreateStruct;
17
use eZ\Publish\SPI\Persistence\User\RoleUpdateStruct;
18
use eZ\Publish\SPI\Persistence\User\Policy;
19
use eZ\Publish\Core\Persistence\Legacy\Exception\RoleNotFound;
20
use eZ\Publish\Core\Persistence\Legacy\User\Role\Gateway as RoleGateway;
21
use eZ\Publish\Core\Persistence\Legacy\User\Role\LimitationConverter;
22
use eZ\Publish\Core\Base\Exceptions\NotFoundException as NotFound;
23
use LogicException;
24
25
/**
26
 * Storage Engine handler for user module.
27
 */
28
class Handler implements BaseUserHandler
29
{
30
    /**
31
     * Gateway for storing user data.
32
     *
33
     * @var \eZ\Publish\Core\Persistence\Legacy\User\Gateway
34
     */
35
    protected $userGateway;
36
37
    /**
38
     * Gateway for storing role data.
39
     *
40
     * @var \eZ\Publish\Core\Persistence\Legacy\User\Role\Gateway
41
     */
42
    protected $roleGateway;
43
44
    /**
45
     * Mapper for user related objects.
46
     *
47
     * @var \eZ\Publish\Core\Persistence\Legacy\User\Mapper
48
     */
49
    protected $mapper;
50
51
    /** @var \eZ\Publish\Core\Persistence\Legacy\User\Role\LimitationConverter */
52
    protected $limitationConverter;
53
54
    /**
55
     * Construct from userGateway.
56
     *
57
     * @param \eZ\Publish\Core\Persistence\Legacy\User\Gateway $userGateway
58
     * @param \eZ\Publish\Core\Persistence\Legacy\User\Role\Gateway $roleGateway
59
     * @param \eZ\Publish\Core\Persistence\Legacy\User\Mapper $mapper
60
     * @param \eZ\Publish\Core\Persistence\Legacy\User\Role\LimitationConverter $limitationConverter
61
     */
62
    public function __construct(Gateway $userGateway, RoleGateway $roleGateway, Mapper $mapper, LimitationConverter $limitationConverter)
63
    {
64
        $this->userGateway = $userGateway;
65
        $this->roleGateway = $roleGateway;
66
        $this->mapper = $mapper;
67
        $this->limitationConverter = $limitationConverter;
68
    }
69
70
    /**
71
     * Create a user.
72
     *
73
     * The User struct used to create the user will contain an ID which is used
74
     * to reference the user.
75
     *
76
     * @param \eZ\Publish\SPI\Persistence\User $user
77
     *
78
     * @throws \eZ\Publish\API\Repository\Exceptions\NotImplementedException
79
     */
80
    public function create(User $user)
81
    {
82
        throw new NotImplementedException('This method should not be called, creation is done via content handler.');
83
    }
84
85
    /**
86
     * Loads user with user ID.
87
     *
88
     * @param mixed $userId
89
     *
90
     * @throws \eZ\Publish\API\Repository\Exceptions\NotFoundException If user is not found
91
     *
92
     * @return \eZ\Publish\SPI\Persistence\User
93
     */
94 View Code Duplication
    public function load($userId)
95
    {
96
        $data = $this->userGateway->load($userId);
97
98
        if (empty($data)) {
99
            throw new NotFound('user', $userId);
100
        }
101
102
        return $this->mapper->mapUser(reset($data));
103
    }
104
105
    /**
106
     * Loads user with user login.
107
     *
108
     * @param string $login
109
     *
110
     * @throws \eZ\Publish\API\Repository\Exceptions\NotFoundException If user is not found
111
     *
112
     * @return \eZ\Publish\SPI\Persistence\User
113
     */
114 View Code Duplication
    public function loadByLogin($login)
115
    {
116
        $data = $this->userGateway->loadByLogin($login);
117
118
        if (empty($data)) {
119
            throw new NotFound('user', $login);
120
        } elseif (count($data) > 1) {
121
            throw new LogicException("Found more then one user with login '{$login}'");
122
        }
123
124
        return $this->mapper->mapUser($data[0]);
125
    }
126
127
    /**
128
     * Loads user(s) with user email.
129
     *
130
     * As earlier eZ Publish versions supported several users having same email (ini config),
131
     * this function may return several users.
132
     *
133
     * @param string $email
134
     *
135
     * @return \eZ\Publish\SPI\Persistence\User
136
     */
137 View Code Duplication
    public function loadByEmail(string $email): User
138
    {
139
        $data = $this->userGateway->loadByEmail($email);
140
141
        if (empty($data)) {
142
            throw new NotFound('user', $email);
143
        } elseif (count($data) > 1) {
144
            throw new LogicException("Found more then one user with login '{$email}'");
145
        }
146
147
        return $this->mapper->mapUser($data[0]);
148
    }
149
150
    /**
151
     * Loads user(s) with user email.
152
     *
153
     * As earlier eZ Publish versions supported several users having same email (ini config),
154
     * this function may return several users.
155
     *
156
     * @param string $email
157
     *
158
     * @return \eZ\Publish\SPI\Persistence\User[]
159
     */
160
    public function loadUsersByEmail(string $email): array
161
    {
162
        $data = $this->userGateway->loadByEmail($email);
163
164
        if (empty($data)) {
165
            return [];
166
        }
167
168
        return $this->mapper->mapUsers($data);
169
    }
170
171
    /**
172
     * Loads user with user hash.
173
     *
174
     * @param string $hash
175
     *
176
     * @throws \eZ\Publish\API\Repository\Exceptions\NotFoundException If user is not found
177
     *
178
     * @return \eZ\Publish\SPI\Persistence\User
179
     */
180 View Code Duplication
    public function loadUserByToken($hash)
181
    {
182
        $data = $this->userGateway->loadUserByToken($hash);
183
184
        if (empty($data)) {
185
            throw new NotFound('user', $hash);
186
        }
187
188
        return $this->mapper->mapUser(reset($data));
189
    }
190
191
    /**
192
     * Update the user information specified by the user struct.
193
     *
194
     * @param \eZ\Publish\SPI\Persistence\User $user
195
     *
196
     * @throws \eZ\Publish\API\Repository\Exceptions\NotImplementedException
197
     */
198
    public function update(User $user)
199
    {
200
        throw new NotImplementedException('This method should not be called, update is done via content handler.');
201
    }
202
203
    /**
204
     * Update the user token information specified by the userToken struct.
205
     *
206
     * @param \eZ\Publish\SPI\Persistence\User\UserTokenUpdateStruct $userTokenUpdateStruct
207
     */
208
    public function updateUserToken(UserTokenUpdateStruct $userTokenUpdateStruct)
209
    {
210
        $this->userGateway->updateUserToken($userTokenUpdateStruct);
211
    }
212
213
    /**
214
     * Expires user account key with user hash.
215
     *
216
     * @param string $hash
217
     */
218
    public function expireUserToken($hash)
219
    {
220
        $this->userGateway->expireUserToken($hash);
221
    }
222
223
    /**
224
     * Delete user with the given ID.
225
     *
226
     * @param mixed $userId
227
     *
228
     * @throws \eZ\Publish\API\Repository\Exceptions\NotImplementedException
229
     */
230
    public function delete($userId)
231
    {
232
        throw new NotImplementedException('This method should not be called, delete is done via content handler.');
233
    }
234
235
    /**
236
     * Create new role draft.
237
     *
238
     * Sets status to Role::STATUS_DRAFT on the new returned draft.
239
     *
240
     * @param \eZ\Publish\SPI\Persistence\User\RoleCreateStruct $createStruct
241
     *
242
     * @return \eZ\Publish\SPI\Persistence\User\Role
243
     */
244
    public function createRole(RoleCreateStruct $createStruct)
245
    {
246
        return $this->internalCreateRole($createStruct);
247
    }
248
249
    /**
250
     * Creates a draft of existing defined role.
251
     *
252
     * Sets status to Role::STATUS_DRAFT on the new returned draft.
253
     *
254
     * @param mixed $roleId
255
     *
256
     * @throws \eZ\Publish\API\Repository\Exceptions\NotFoundException If role with defined status is not found
257
     *
258
     * @return \eZ\Publish\SPI\Persistence\User\Role
259
     */
260
    public function createRoleDraft($roleId)
261
    {
262
        $createStruct = $this->mapper->createCreateStructFromRole(
263
            $this->loadRole($roleId)
264
        );
265
266
        return $this->internalCreateRole($createStruct, $roleId);
267
    }
268
269
    /**
270
     * Internal method for creating Role.
271
     *
272
     * Used by self::createRole() and self::createRoleDraft()
273
     *
274
     * @param \eZ\Publish\SPI\Persistence\User\RoleCreateStruct $createStruct
275
     * @param mixed|null $roleId Used by self::createRoleDraft() to retain Role id in the draft
276
     *
277
     * @return \eZ\Publish\SPI\Persistence\User\Role
278
     */
279
    protected function internalCreateRole(RoleCreateStruct $createStruct, $roleId = null)
280
    {
281
        $createStruct = clone $createStruct;
282
        $role = $this->mapper->createRoleFromCreateStruct(
283
            $createStruct
284
        );
285
        $role->id = $roleId;
286
        $role->status = Role::STATUS_DRAFT;
287
288
        $this->roleGateway->createRole($role);
289
290
        foreach ($role->policies as $policy) {
291
            $this->addPolicyByRoleDraft($role->id, $policy);
292
        }
293
294
        return $role;
295
    }
296
297
    /**
298
     * Loads a specified role (draft) by $roleId and $status.
299
     *
300
     * @param mixed $roleId
301
     * @param int $status One of Role::STATUS_DEFINED|Role::STATUS_DRAFT
302
     *
303
     * @throws \eZ\Publish\API\Repository\Exceptions\NotFoundException If role with given status does not exist
304
     *
305
     * @return \eZ\Publish\SPI\Persistence\User\Role
306
     */
307 View Code Duplication
    public function loadRole($roleId, $status = Role::STATUS_DEFINED)
308
    {
309
        $data = $this->roleGateway->loadRole($roleId, $status);
310
311
        if (empty($data)) {
312
            throw new RoleNotFound($roleId, $status);
313
        }
314
315
        $role = $this->mapper->mapRole($data);
316
        foreach ($role->policies as $policy) {
317
            $this->limitationConverter->toSPI($policy);
318
        }
319
320
        return $role;
321
    }
322
323
    /**
324
     * Loads a specified role (draft) by $identifier and $status.
325
     *
326
     * @param string $identifier
327
     * @param int $status One of Role::STATUS_DEFINED|Role::STATUS_DRAFT
328
     *
329
     * @throws \eZ\Publish\API\Repository\Exceptions\NotFoundException If role is not found
330
     *
331
     * @return \eZ\Publish\SPI\Persistence\User\Role
332
     */
333 View Code Duplication
    public function loadRoleByIdentifier($identifier, $status = Role::STATUS_DEFINED)
334
    {
335
        $data = $this->roleGateway->loadRoleByIdentifier($identifier, $status);
336
337
        if (empty($data)) {
338
            throw new RoleNotFound($identifier, $status);
339
        }
340
341
        $role = $this->mapper->mapRole($data);
342
        foreach ($role->policies as $policy) {
343
            $this->limitationConverter->toSPI($policy);
344
        }
345
346
        return $role;
347
    }
348
349
    /**
350
     * Loads a role draft by the original role ID.
351
     *
352
     * @param mixed $roleId ID of the role the draft was created from.
353
     *
354
     * @throws \eZ\Publish\API\Repository\Exceptions\NotFoundException If role is not found
355
     *
356
     * @return \eZ\Publish\SPI\Persistence\User\Role
357
     */
358 View Code Duplication
    public function loadRoleDraftByRoleId($roleId)
359
    {
360
        $data = $this->roleGateway->loadRoleDraftByRoleId($roleId);
361
362
        if (empty($data)) {
363
            throw new RoleNotFound($roleId, Role::STATUS_DRAFT);
364
        }
365
366
        $role = $this->mapper->mapRole($data);
367
        foreach ($role->policies as $policy) {
368
            $this->limitationConverter->toSPI($policy);
369
        }
370
371
        return $role;
372
    }
373
374
    /**
375
     * Loads all roles.
376
     *
377
     * @return \eZ\Publish\SPI\Persistence\User\Role[]
378
     */
379 View Code Duplication
    public function loadRoles()
380
    {
381
        $data = $this->roleGateway->loadRoles();
382
383
        $roles = $this->mapper->mapRoles($data);
384
        foreach ($roles as $role) {
385
            foreach ($role->policies as $policy) {
386
                $this->limitationConverter->toSPI($policy);
387
            }
388
        }
389
390
        return $roles;
391
    }
392
393
    /**
394
     * Update role (draft).
395
     *
396
     * @param \eZ\Publish\SPI\Persistence\User\RoleUpdateStruct $role
397
     */
398
    public function updateRole(RoleUpdateStruct $role)
399
    {
400
        $this->roleGateway->updateRole($role);
401
    }
402
403
    /**
404
     * Delete the specified role (draft).
405
     *
406
     * @param mixed $roleId
407
     * @param int $status One of Role::STATUS_DEFINED|Role::STATUS_DRAFT
408
     */
409
    public function deleteRole($roleId, $status = Role::STATUS_DEFINED)
410
    {
411
        $role = $this->loadRole($roleId, $status);
412
413
        foreach ($role->policies as $policy) {
414
            $this->roleGateway->removePolicy($policy->id);
415
        }
416
417
        $this->roleGateway->deleteRole($role->id, $status);
418
    }
419
420
    /**
421
     * Publish the specified role draft.
422
     *
423
     * @param mixed $roleDraftId
424
     */
425
    public function publishRoleDraft($roleDraftId)
426
    {
427
        $roleDraft = $this->loadRole($roleDraftId, Role::STATUS_DRAFT);
428
429
        try {
430
            $originalRoleId = $roleDraft->originalId;
431
            $role = $this->loadRole($originalRoleId);
432
            $roleAssignments = $this->loadRoleAssignmentsByRoleId($role->id);
433
            $this->deleteRole($role->id);
434
435
            foreach ($roleAssignments as $roleAssignment) {
436
                if (empty($roleAssignment->limitationIdentifier)) {
437
                    $this->assignRole($roleAssignment->contentId, $originalRoleId);
438
                } else {
439
                    $this->assignRole(
440
                        $roleAssignment->contentId,
441
                        $originalRoleId,
442
                        [$roleAssignment->limitationIdentifier => $roleAssignment->values]
443
                    );
444
                }
445
            }
446
            $this->roleGateway->publishRoleDraft($roleDraft->id, $role->id);
447
        } catch (NotFound $e) {
448
            // If no published role is found, only publishing is needed, without specifying original role ID as there is none.
449
            $this->roleGateway->publishRoleDraft($roleDraft->id);
450
        }
451
    }
452
453
    /**
454
     * Adds a policy to a role draft.
455
     *
456
     * @param mixed $roleId
457
     * @param \eZ\Publish\SPI\Persistence\User\Policy $policy
458
     *
459
     * @return \eZ\Publish\SPI\Persistence\User\Policy
460
     */
461
    public function addPolicyByRoleDraft($roleId, Policy $policy)
462
    {
463
        $legacyPolicy = clone $policy;
464
        $legacyPolicy->originalId = $policy->id;
465
        $this->limitationConverter->toLegacy($legacyPolicy);
466
467
        $this->roleGateway->addPolicy($roleId, $legacyPolicy);
468
        $policy->id = $legacyPolicy->id;
469
        $policy->originalId = $legacyPolicy->originalId;
470
        $policy->roleId = $legacyPolicy->roleId;
471
472
        return $policy;
473
    }
474
475
    /**
476
     * Adds a policy to a role.
477
     *
478
     * @param mixed $roleId
479
     * @param \eZ\Publish\SPI\Persistence\User\Policy $policy
480
     *
481
     * @return \eZ\Publish\SPI\Persistence\User\Policy
482
     */
483
    public function addPolicy($roleId, Policy $policy)
484
    {
485
        $legacyPolicy = clone $policy;
486
        $this->limitationConverter->toLegacy($legacyPolicy);
487
488
        $this->roleGateway->addPolicy($roleId, $legacyPolicy);
489
        $policy->id = $legacyPolicy->id;
490
        $policy->roleId = $legacyPolicy->roleId;
491
492
        return $policy;
493
    }
494
495
    /**
496
     * Update a policy.
497
     *
498
     * Replaces limitations values with new values.
499
     *
500
     * @param \eZ\Publish\SPI\Persistence\User\Policy $policy
501
     */
502
    public function updatePolicy(Policy $policy)
503
    {
504
        $policy = clone $policy;
505
        $this->limitationConverter->toLegacy($policy);
506
507
        $this->roleGateway->removePolicyLimitations($policy->id);
508
        $this->roleGateway->addPolicyLimitations($policy->id, $policy->limitations === '*' ? [] : $policy->limitations);
0 ignored issues
show
Bug introduced by
It seems like $policy->limitations ===... : $policy->limitations can also be of type string; however, eZ\Publish\Core\Persiste...:addPolicyLimitations() does only seem to accept array, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
509
    }
510
511
    /**
512
     * Removes a policy from a role.
513
     *
514
     * @param mixed $policyId
515
     * @param mixed $roleId
516
     */
517
    public function deletePolicy($policyId, $roleId)
518
    {
519
        // Each policy can only be associated to exactly one role. Thus it is
520
        // sufficient to use the policyId for identification and just remove
521
        // the policy completely.
522
        $this->roleGateway->removePolicy($policyId);
523
    }
524
525
    /**
526
     * Returns the user policies associated with the user (including inherited policies from user groups).
527
     *
528
     * @param mixed $userId
529
     *
530
     * @return \eZ\Publish\SPI\Persistence\User\Policy[]
531
     */
532 View Code Duplication
    public function loadPoliciesByUserId($userId)
533
    {
534
        $data = $this->roleGateway->loadPoliciesByUserId($userId);
535
536
        $policies = $this->mapper->mapPolicies($data);
537
538
        foreach ($policies as $policy) {
539
            $this->limitationConverter->toSPI($policy);
540
        }
541
542
        return $policies;
543
    }
544
545
    /**
546
     * Assigns role to a user or user group with given limitations.
547
     *
548
     * The limitation array looks like:
549
     * <code>
550
     *  array(
551
     *      'Subtree' => array(
552
     *          '/1/2/',
553
     *          '/1/4/',
554
     *      ),
555
     *      'Foo' => array( 'Bar' ),
556
     *      …
557
     *  )
558
     * </code>
559
     *
560
     * Where the keys are the limitation identifiers, and the respective values
561
     * are an array of limitation values. The limitation parameter is optional.
562
     *
563
     * @param mixed $contentId The groupId or userId to assign the role to.
564
     * @param mixed $roleId
565
     * @param array $limitation
566
     */
567
    public function assignRole($contentId, $roleId, array $limitation = null)
568
    {
569
        $limitation = $limitation ?: ['' => ['']];
570
        $this->userGateway->assignRole($contentId, $roleId, $limitation);
571
    }
572
573
    /**
574
     * Un-assign a role.
575
     *
576
     * @param mixed $contentId The user or user group Id to un-assign the role from.
577
     * @param mixed $roleId
578
     */
579
    public function unassignRole($contentId, $roleId)
580
    {
581
        $this->userGateway->removeRole($contentId, $roleId);
582
    }
583
584
    /**
585
     * Un-assign a role by assignment ID.
586
     *
587
     * @param mixed $roleAssignmentId The assignment ID.
588
     */
589
    public function removeRoleAssignment($roleAssignmentId)
590
    {
591
        $this->userGateway->removeRoleAssignmentById($roleAssignmentId);
592
    }
593
594
    /**
595
     * Loads role assignment for specified assignment ID.
596
     *
597
     * @param mixed $roleAssignmentId
598
     *
599
     * @throws \eZ\Publish\API\Repository\Exceptions\NotFoundException If role assignment is not found
600
     *
601
     * @return \eZ\Publish\SPI\Persistence\User\RoleAssignment
602
     */
603
    public function loadRoleAssignment($roleAssignmentId)
604
    {
605
        $data = $this->roleGateway->loadRoleAssignment($roleAssignmentId);
606
607
        if (empty($data)) {
608
            throw new NotFound('roleAssignment', $roleAssignmentId);
609
        }
610
611
        return $this->mapper->mapRoleAssignments($data)[0];
612
    }
613
614
    /**
615
     * Loads roles assignments Role.
616
     *
617
     * Role Assignments with same roleId and limitationIdentifier will be merged together into one.
618
     *
619
     * @param mixed $roleId
620
     *
621
     * @return \eZ\Publish\SPI\Persistence\User\RoleAssignment[]
622
     */
623 View Code Duplication
    public function loadRoleAssignmentsByRoleId($roleId)
624
    {
625
        $data = $this->roleGateway->loadRoleAssignmentsByRoleId($roleId);
626
627
        if (empty($data)) {
628
            return [];
629
        }
630
631
        return $this->mapper->mapRoleAssignments($data);
632
    }
633
634
    /**
635
     * Loads roles assignments to a user/group.
636
     *
637
     * Role Assignments with same roleId and limitationIdentifier will be merged together into one.
638
     *
639
     * @param mixed $groupId In legacy storage engine this is the content object id roles are assigned to in ezuser_role.
640
     *                      By the nature of legacy this can currently also be used to get by $userId.
641
     * @param bool $inherit If true also return inherited role assignments from user groups.
642
     *
643
     * @return \eZ\Publish\SPI\Persistence\User\RoleAssignment[]
644
     */
645 View Code Duplication
    public function loadRoleAssignmentsByGroupId($groupId, $inherit = false)
646
    {
647
        $data = $this->roleGateway->loadRoleAssignmentsByGroupId($groupId, $inherit);
648
649
        if (empty($data)) {
650
            return [];
651
        }
652
653
        return $this->mapper->mapRoleAssignments($data);
654
    }
655
}
656