Completed
Push — ezp_31482 ( d11e83 )
by
unknown
14:30
created

getPermissionsCriterion()   C

Complexity

Conditions 15
Paths 35

Size

Total Lines 79

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 15
nc 35
nop 3
dl 0
loc 79
rs 5.1914
c 0
b 0
f 0

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

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\PermissionCriterionResolver as APIPermissionCriterionResolver;
10
use eZ\Publish\API\Repository\Values\Content\Query\Criterion\LogicalAnd;
11
use eZ\Publish\API\Repository\Values\Content\Query\Criterion\LogicalOr;
12
use eZ\Publish\API\Repository\Values\Content\Query\CriterionInterface;
13
use eZ\Publish\API\Repository\Values\User\Limitation;
14
use eZ\Publish\API\Repository\PermissionResolver as PermissionResolverInterface;
15
use eZ\Publish\API\Repository\Values\User\UserReference;
16
use eZ\Publish\Core\Limitation\TargetOnlyLimitationType;
17
use RuntimeException;
18
19
/**
20
 * Implementation of Permissions Criterion Resolver.
21
 */
22
class PermissionCriterionResolver implements APIPermissionCriterionResolver
23
{
24
    /** @var \eZ\Publish\API\Repository\PermissionResolver */
25
    private $permissionResolver;
26
27
    /** @var \eZ\Publish\Core\Repository\Permission\LimitationService */
28
    private $limitationService;
29
30
    /**
31
     * Constructor.
32
     *
33
     * @param \eZ\Publish\API\Repository\PermissionResolver $permissionResolver
34
     * @param \eZ\Publish\Core\Repository\Permission\LimitationService $limitationService
35
     */
36
    public function __construct(
37
        PermissionResolverInterface $permissionResolver,
38
        LimitationService $limitationService
39
    ) {
40
        $this->permissionResolver = $permissionResolver;
41
        $this->limitationService = $limitationService;
42
    }
43
44
    /**
45
     * Get permission criteria if needed and return false if no access at all.
46
     *
47
     * @uses \eZ\Publish\API\Repository\PermissionResolver::getCurrentUserReference()
48
     * @uses \eZ\Publish\API\Repository\PermissionResolver::hasAccess()
49
     *
50
     * @param string $module
51
     * @param string $function
52
     * @param array $targets
53
     *
54
     * @return bool|\eZ\Publish\API\Repository\Values\Content\Query\Criterion
55
     */
56
    public function getPermissionsCriterion($module = 'content', $function = 'read', ?array $targets = null)
57
    {
58
        $permissionSets = $this->permissionResolver->hasAccess($module, $function);
59
        if (is_bool($permissionSets)) {
60
            return $permissionSets;
61
        }
62
63
        if (empty($permissionSets)) {
64
            throw new RuntimeException("Received an empty array of limitations from hasAccess( '{$module}', '{$function}' )");
65
        }
66
67
        /*
68
         * RoleAssignment is a OR condition, so is policy, while limitations is a AND condition
69
         *
70
         * If RoleAssignment has limitation then policy OR conditions are wrapped in a AND condition with the
71
         * role limitation, otherwise it will be merged into RoleAssignment's OR condition.
72
         */
73
        $currentUserRef = $this->permissionResolver->getCurrentUserReference();
74
        $roleAssignmentOrCriteria = [];
75
        foreach ($permissionSets as $permissionSet) {
76
            // $permissionSet is a RoleAssignment, but in the form of role limitation & role policies hash
77
            $policyOrCriteria = [];
78
            /** @var \eZ\Publish\API\Repository\Values\User\Policy */
79
            foreach ($permissionSet['policies'] as $policy) {
80
                $limitations = $policy->getLimitations();
81
                if (empty($limitations)) {
82
                    // Given policy gives full access, optimize away all role policies (but not role limitation if any)
83
                    // This should be optimized on create/update of Roles, however we keep this here for bc with older data
84
                    $policyOrCriteria = [];
85
                    break;
86
                }
87
88
                $limitationsAndCriteria = [];
89
                foreach ($limitations as $limitation) {
90
                    $limitationsAndCriteria[] = $this->getCriterionForLimitation($limitation, $currentUserRef, $targets);
91
                }
92
93
                $policyOrCriteria[] = isset($limitationsAndCriteria[1]) ?
94
                    new LogicalAnd($limitationsAndCriteria) :
95
                    $limitationsAndCriteria[0];
96
            }
97
98
            /**
99
             * Apply role limitations if there is one.
100
             *
101
             * @var \eZ\Publish\API\Repository\Values\User\Limitation[]
102
             */
103
            if ($permissionSet['limitation'] instanceof Limitation) {
104
                // We need to match both the limitation AND *one* of the policies, aka; roleLimit AND policies(OR)
105
                if (!empty($policyOrCriteria)) {
106
                    $criterion = $this->getCriterionForLimitation($permissionSet['limitation'], $currentUserRef, $targets);
107
                    $roleAssignmentOrCriteria[] = new LogicalAnd(
108
                        [
109
                            $criterion,
110
                            isset($policyOrCriteria[1]) ? new LogicalOr($policyOrCriteria) : $policyOrCriteria[0],
111
                        ]
112
                    );
113
                } else {
114
                    $roleAssignmentOrCriteria[] = $this->getCriterionForLimitation(
115
                        $permissionSet['limitation'], $currentUserRef, $targets
116
                    );
117
                }
118
            } elseif (!empty($policyOrCriteria)) {
119
                // Otherwise merge $policyOrCriteria into $roleAssignmentOrCriteria
120
                // There is no role limitation, so any of the policies can globally match in the returned OR criteria
121
                $roleAssignmentOrCriteria = empty($roleAssignmentOrCriteria) ?
122
                    $policyOrCriteria :
123
                    array_merge($roleAssignmentOrCriteria, $policyOrCriteria);
124
            }
125
        }
126
127
        if (empty($roleAssignmentOrCriteria)) {
128
            return false;
129
        }
130
131
        return isset($roleAssignmentOrCriteria[1]) ?
132
            new LogicalOr($roleAssignmentOrCriteria) :
133
            $roleAssignmentOrCriteria[0];
134
    }
135
136
    /**
137
     * @param \eZ\Publish\API\Repository\Values\User\Limitation $limitation
138
     * @param \eZ\Publish\API\Repository\Values\User\UserReference $currentUserRef
139
     * @param array|null $targets
140
     *
141
     * @return \eZ\Publish\API\Repository\Values\Content\Query\CriterionInterface|\eZ\Publish\API\Repository\Values\Content\Query\Criterion\LogicalOperator
142
     */
143
    private function getCriterionForLimitation(Limitation $limitation, UserReference $currentUserRef, ?array $targets): CriterionInterface
144
    {
145
        $type = $this->limitationService->getLimitationType($limitation->getIdentifier());
146
        if ($type instanceof TargetOnlyLimitationType) {
147
            return $type->getCriterionByTarget($limitation, $currentUserRef, $targets);
148
        }
149
150
        return $type->getCriterion($limitation, $currentUserRef);
151
    }
152
}
153