RuleAcl::getTarget()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 0
loc 4
ccs 2
cts 2
cp 1
rs 10
cc 1
eloc 2
nc 1
nop 0
crap 1
1
<?php
2
declare(strict_types=1);
3
/**
4
 * Caridea
5
 *
6
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
7
 * use this file except in compliance with the License. You may obtain a copy of
8
 * the License at
9
 *
10
 * http://www.apache.org/licenses/LICENSE-2.0
11
 *
12
 * Unless required by applicable law or agreed to in writing, software
13
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
14
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
15
 * License for the specific language governing permissions and limitations under
16
 * the License.
17
 *
18
 * @copyright 2015-2018 LibreWorks contributors
19
 * @license   Apache-2.0
20
 */
21
namespace Caridea\Acl;
22
23
/**
24
 * An immutable, serializable list of access rules.
25
 *
26
 * @copyright 2015-2018 LibreWorks contributors
27
 * @license   Apache-2.0
28
 */
29
class RuleAcl implements Acl
30
{
31
    /**
32
     * @var \Caridea\Acl\Acl The parent
33
     */
34
    private $parent;
35
    /**
36
     * @var \Caridea\Acl\Target The resource
37
     */
38
    private $target;
39
    /**
40
     * @var \Caridea\Acl\Subject[] The subjects for which the rules apply
41
     */
42
    private $subjects;
43
    /**
44
     * @var Rule[] The rules
45
     */
46
    private $rules = [];
47
48
    /**
49
     * Creates a new RuleAcl.
50
     *
51
     * @param \Caridea\Acl\Target $target The resource to which this applies
52
     * @param \Caridea\Acl\Subject[] $subjects An array of `Subject`s the rules cover
53
     * @param \Caridea\Acl\Rule[] $rules An array of `Rule`s
54
     * @param \Caridea\Acl\Acl|null $parent Optional parent ACL
55
     * @throws \InvalidArgumentException If subjects contains a non-Subject
56
     *     value, or if rules contains a non-Rule value
57
     */
58 4
    public function __construct(Target $target, array $subjects, array $rules, ?Acl $parent = null)
59
    {
60 4
        $this->target = $target;
61 4
        foreach ($subjects as $subject) {
62 3
            if (!($subject instanceof Subject)) {
63 3
                throw new \InvalidArgumentException("Only instances of Subject are permitted in the subjects argument");
64
            }
65
        }
66 3
        $this->subjects = $subjects;
67 3
        foreach ($rules as $rule) {
68 3
            if (!($rule instanceof Rule)) {
69 3
                throw new \InvalidArgumentException("Only instances of Rule are permitted in the rules argument");
70
            }
71
        }
72 2
        $this->rules = $rules;
73 2
        $this->parent = $parent;
74 2
    }
75
76
    /**
77
     * Determines whether this ACL has rules for all of the provided subjects.
78
     *
79
     * @param \Caridea\Acl\Subject[] $subjects a list of subjects
80
     * @return bool Whether all subjects are covered
81
     */
82 4
    protected function hasAllSubjects(array $subjects): bool
83
    {
84 4
        return count(array_diff($subjects, $this->subjects)) === 0;
85
    }
86
87
    /**
88
     * {@inheritDoc}
89
     */
90 4
    public function can(array $subjects, string $verb): bool
91
    {
92 4
        if (!$this->hasAllSubjects($subjects)) {
93 1
            throw new \InvalidArgumentException("This ACL does not apply to one of the provided subjects");
94
        }
95 3
        foreach ($this->rules as $rule) {
96 2
            foreach ($subjects as $subject) {
97 2
                if ($rule->match($subject, $verb)) {
98 2
                    return $rule->isAllowed();
99
                }
100
            }
101
        }
102 2
        return $this->parent ? $this->parent->can($subjects, $verb) : false;
103
    }
104
105
    /**
106
     * {@inheritDoc}
107
     */
108 1
    public function getParent(): ?Acl
109
    {
110 1
        return $this->parent;
111
    }
112
113
    /**
114
     * {@inheritDoc}
115
     */
116 1
    public function getTarget(): Target
117
    {
118 1
        return $this->target;
119
    }
120
}
121