Completed
Push — master ( 2d5a91...5e6a60 )
by André
72:09 queued 53:20
created

CachedPermissionService::getPermissionsCriterion()   B

Complexity

Conditions 5
Paths 4

Size

Total Lines 20
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 5
eloc 9
nc 4
nop 2
dl 0
loc 20
rs 8.8571
c 0
b 0
f 0
1
<?php
2
3
/**
4
 * @copyright Copyright (C) eZ Systems AS. All rights reserved.
5
 * @license For full copyright and license information view LICENSE file distributed with this source code.
6
 */
7
namespace eZ\Publish\Core\Repository\Permission;
8
9
use eZ\Publish\API\Repository\PermissionResolver as APIPermissionResolver;
10
use eZ\Publish\API\Repository\PermissionCriterionResolver as APIPermissionCriterionResolver;
11
use eZ\Publish\API\Repository\Repository as RepositoryInterface;
12
use eZ\Publish\API\Repository\Values\User\UserReference;
13
use eZ\Publish\API\Repository\Values\ValueObject;
14
15
/**
16
 * Cache implementation of PermissionResolver and PermissionCriterionResolver interface.
17
 *
18
 * Implements both interfaces as the cached permission criterion lookup needs to be
19
 * expired when a different user is set as current users in the system.
20
 *
21
 * Cache is only done for content/read policy, as that is the one needed by search service.
22
 *
23
 * The logic here uses a cache TTL of a few seconds, as this is in-memory cache we are not
24
 * able to know if any other concurrent user might be changing permissions.
25
 */
26
class CachedPermissionService implements APIPermissionResolver, APIPermissionCriterionResolver
27
{
28
    /**
29
     * @var \eZ\Publish\API\Repository\PermissionResolver
30
     */
31
    private $permissionResolver;
32
33
    /**
34
     * @var \eZ\Publish\API\Repository\PermissionCriterionResolver
35
     */
36
    private $permissionCriterionResolver;
37
38
    /**
39
     * @var int
40
     */
41
    private $cacheTTL;
42
43
    /**
44
     * Cached value for current user's getCriterion() result.
45
     *
46
     * Value is null if not yet set or cleared.
47
     *
48
     * @var bool|\eZ\Publish\API\Repository\Values\Content\Query\Criterion
49
     */
50
    private $permissionCriterion;
51
52
    /**
53
     * Cache time stamp.
54
     *
55
     * @var int
56
     */
57
    private $permissionCriterionTs;
58
59
    /**
60
     * CachedPermissionService constructor.
61
     *
62
     * @param \eZ\Publish\API\Repository\PermissionResolver $permissionResolver
63
     * @param \eZ\Publish\API\Repository\PermissionCriterionResolver $permissionCriterionResolver
64
     * @param int $cacheTTL By default set to 5 seconds, should be low to avoid to many permission exceptions on long running requests / processes (even if tolerant search service should handle that)
65
     */
66
    public function __construct(
67
        APIPermissionResolver $permissionResolver,
68
        APIPermissionCriterionResolver $permissionCriterionResolver,
69
        $cacheTTL = 5
70
    ) {
71
        $this->permissionResolver = $permissionResolver;
72
        $this->permissionCriterionResolver = $permissionCriterionResolver;
73
        $this->cacheTTL = $cacheTTL;
74
    }
75
76
    public function getCurrentUserReference()
77
    {
78
        return $this->permissionResolver->getCurrentUserReference();
79
    }
80
81
    public function setCurrentUserReference(UserReference $userReference)
82
    {
83
        $this->permissionCriterion = null;
84
85
        return $this->permissionResolver->setCurrentUserReference($userReference);
86
    }
87
88
    public function hasAccess($module, $function, UserReference $userReference = null)
89
    {
90
        return $this->permissionResolver->hasAccess($module, $function, $userReference);
91
    }
92
93
    public function canUser($module, $function, ValueObject $object, array $targets = [])
94
    {
95
        return $this->permissionResolver->canUser($module, $function, $object, $targets);
96
    }
97
98
    public function getPermissionsCriterion($module = 'content', $function = 'read')
99
    {
100
        // We only cache content/read lookup as those are the once frequently done, and it's only one we can safely
101
        // do that won't harm the system if it becomes stale (but user might experience permissions exceptions if it do)
102
        if ($module !== 'content' || $function !== 'read') {
103
            return $this->permissionCriterionResolver->getPermissionsCriterion($module, $function);
104
        }
105
106
        if ($this->permissionCriterion !== null) {
107
            // If we are still within the cache TTL, then return the cached value
108
            if ((time() - $this->permissionCriterionTs) < $this->cacheTTL) {
109
                return $this->permissionCriterion;
110
            }
111
        }
112
113
        $this->permissionCriterionTs = time();
114
        $this->permissionCriterion = $this->permissionCriterionResolver->getPermissionsCriterion($module, $function);
115
116
        return $this->permissionCriterion;
117
    }
118
119
    /**
120
     * @internal For internal use only, do not depend on this method.
121
     */
122
    public function sudo(\Closure $callback, RepositoryInterface $outerRepository)
123
    {
124
        return $this->permissionResolver->sudo($callback, $outerRepository);
125
    }
126
}
127