Completed
Push — master ( e4829c...bae43a )
by Lars
03:15
created

Acl::isAllowedReturnResultSimple()   C

Complexity

Conditions 11
Paths 3

Size

Total Lines 48
Code Lines 27

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 27
CRAP Score 11.121

Importance

Changes 1
Bugs 0 Features 1
Metric Value
c 1
b 0
f 1
dl 0
loc 48
ccs 27
cts 30
cp 0.9
rs 5.2653
cc 11
eloc 27
nc 3
nop 4
crap 11.121

How to fix   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
namespace SimpleAcl;
3
4
use SimpleAcl\Exception\InvalidArgumentException;
5
use SimpleAcl\Exception\RuntimeException;
6
use SimpleAcl\Resource\ResourceAggregateInterface;
7
use SimpleAcl\Role\RoleAggregateInterface;
8
9
/**
10
 * Access Control List (ACL) management.
11
 *
12
 * @package SimpleAcl
13
 */
14
class Acl
15
{
16
  /**
17
   * Contains registered rules.
18
   *
19
   * @var Rule[]
20
   */
21
  protected $rules = array();
22
23
  /**
24
   * Class name used when rule created from string.
25
   *
26
   * @var string
27
   */
28
  protected $ruleClass = 'SimpleAcl\Rule';
29
30
  /**
31
   * Adds rule.
32
   *
33
   * Assign $role, $resource and $action to added rule.
34
   * If rule was already registered only change $role, $resource and $action for that rule.
35
   *
36
   * This method accept 1, 2, 3 or 4 arguments:
37
   *
38
   * addRule($rule)
39
   * addRule($rule, $action)
40
   * addRule($role, $resource, $rule)
41
   * addRule($role, $resource, $rule, $action)
42
   *
43
   * @param Role     ..$role
44
   * @param Resource ..$resource
45
   * @param Rule|string ..$rule
46
   * @param mixed    ..$action
47
   *
48
   * @throws InvalidArgumentException
49
   */
50 37
  public function addRule()
51
  {
52 37
    $args = func_get_args();
53 37
    $argsCount = count($args);
54
55 37
    $role = null;
56 37
    $resource = null;
57 37
    $action = null;
58
59 37
    if ($argsCount == 4 || $argsCount == 3) {
60
61 34
      $role = $args[0];
62 34
      $resource = $args[1];
63 34
      $rule = $args[2];
64
65 34
      if ($argsCount == 4) {
66 33
        $action = $args[3];
67 33
      }
68
69 37
    } elseif ($argsCount == 2) {
70
71 2
      $rule = $args[0];
72 2
      $action = $args[1];
73
74 4
    } elseif ($argsCount == 1) {
75 2
      $rule = $args[0];
76 2
    } else {
77 1
      throw new InvalidArgumentException(__METHOD__ . ' accepts only one, tow, three or four arguments');
78
    }
79
80
    if (
81 36
        null !== $role
82 36
        &&
83
        !$role instanceof Role
84 36
    ) {
85 1
      throw new InvalidArgumentException('Role must be an instance of SimpleAcl\Role or null');
86
    }
87
88
    if (
89 35
        null !== $resource
90 35
        &&
91
        !$resource instanceof Resource
92 35
    ) {
93 1
      throw new InvalidArgumentException('Resource must be an instance of SimpleAcl\Resource or null');
94
    }
95
96 34
    if (is_string($rule)) {
97 3
      $ruleClass = $this->getRuleClass();
98 3
      $rule = new $ruleClass($rule);
99 3
    }
100
101 34
    if (!$rule instanceof Rule) {
102 1
      throw new InvalidArgumentException('Rule must be an instance of SimpleAcl\Rule or string');
103
    }
104
105 33
    $exchange = $this->hasRule($rule);
106
107 33
    if ($exchange) {
108 5
      $rule = $exchange;
109 5
    } else {
110 33
      $this->rules[] = $rule;
111
    }
112
113 33
    if ($argsCount == 3 || $argsCount == 4) {
114 31
      $rule->setRole($role);
115 31
      $rule->setResource($resource);
116 31
    }
117
118 33
    if ($argsCount == 2 || $argsCount == 4) {
119 31
      $rule->setAction($action);
120 31
    }
121 33
  }
122
123
  /**
124
   * Return rule class.
125
   *
126
   * @return string
127
   */
128 5
  public function getRuleClass()
129
  {
130 5
    return $this->ruleClass;
131
  }
132
133
  /**
134
   * Set rule class.
135
   *
136
   * @param string $ruleClass
137
   */
138 5
  public function setRuleClass($ruleClass)
139
  {
140 5
    if (!class_exists($ruleClass)) {
141 1
      throw new RuntimeException('Rule class not exist');
142
    }
143
144
    if (
145
        $ruleClass != 'SimpleAcl\Rule'
146 4
        &&
147 2
        !is_subclass_of($ruleClass, 'SimpleAcl\Rule')
148 4
    ) {
149 1
      throw new RuntimeException('Rule class must be instance of SimpleAcl\Rule');
150
    }
151
152 3
    $this->ruleClass = $ruleClass;
153 3
  }
154
155
  /**
156
   * Return true if rule was already added.
157
   *
158
   * @param Rule | mixed $needRule Rule or rule's id
159
   *
160
   * @return bool
161
   */
162 33
  public function hasRule($needRule)
163
  {
164 33
    if ($needRule instanceof Rule) {
165 33
      $needRuleId = $needRule->id;
166 33
    } else {
167 1
      $needRuleId = $needRule;
168
    }
169
170 33
    foreach ($this->rules as $rule) {
171 24
      if ($rule->id === $needRuleId) {
172 6
        return $rule;
173
      }
174 33
    }
175
176 33
    return false;
177
  }
178
179
  /**
180
   * Checks is access allowed.
181
   *
182
   * @param string|RoleAggregateInterface     $roleName
183
   * @param string|ResourceAggregateInterface $resourceName
184
   * @param string                            $ruleName
185
   *
186
   * @return bool
187
   */
188 28
  public function isAllowed($roleName, $resourceName, $ruleName)
189
  {
190 28
    return $this->isAllowedReturnResult($roleName, $resourceName, $ruleName)->get();
191
  }
192
193
  /**
194
   * Simple checks is access allowed.
195
   *
196
   * @param string|RoleAggregateInterface     $roleAggregate
197
   * @param string|ResourceAggregateInterface $resourceAggregate
198
   * @param string                            $ruleName
199
   * @param RuleResultCollection              $ruleResultCollection
200
   *
201
   * @return RuleResultCollection|null null if there wasn't a clear result
202
   */
203 28
  protected function isAllowedReturnResultSimple($roleAggregate, $resourceAggregate, $ruleName, $ruleResultCollection)
204
  {
205
    if (
206 28
        is_string($ruleName)
207 28
        &&
208 28
        is_string($roleAggregate)
209 28
        &&
210 24
        is_string($resourceAggregate)
211 28
    ) {
212
213 22
      foreach ($this->rules as $ruleTmp) {
214
215 21
        if ($ruleTmp->getName() !== $ruleName) {
216 9
          continue;
217
        }
218
219 19
        $resourceTmp = $ruleTmp->getResource();
220 19
        $roleTmp = $ruleTmp->getRole();
221
222
        if (
223
            (
224
                $resourceTmp instanceof Resource
225 19
                &&
226 19
                $resourceTmp->getName() === $resourceAggregate
227 19
            )
228 19
            &&
229
            (
230
                $roleTmp instanceof Role
231 19
                &&
232 18
                $roleTmp->getName() === $roleAggregate
233 18
            )
234 19
        ) {
235 17
          $resultTmp = $ruleTmp->isAllowed($ruleName, $roleAggregate, $resourceAggregate);
236
237 17
          if (null === $resultTmp->getAction()) {
238
            unset($resultTmp);
239
          } else {
240
            // Set null if rule don't match any role or resource.
241 17
            $ruleResultCollection->add($resultTmp);
242
243 17
            return $ruleResultCollection;
244
          }
245
        }
246 15
      }
247 15
    }
248
249 22
    return null;
250
  }
251
252
  /**
253
   * Checks is access allowed.
254
   *
255
   * @param string|RoleAggregateInterface     $roleAggregate
256
   * @param string|ResourceAggregateInterface $resourceAggregate
257
   * @param string                            $ruleName
258
   *
259
   * @return RuleResultCollection
260
   */
261 28
  public function isAllowedReturnResult($roleAggregate, $resourceAggregate, $ruleName)
262
  {
263 28
    $ruleResultCollection = new RuleResultCollection();
264
265 28
    $tmpResult = $this->isAllowedReturnResultSimple($roleAggregate, $resourceAggregate, $ruleName, $ruleResultCollection);
266 28
    if ($tmpResult !== null) {
267 17
      return $tmpResult;
268
    }
269
270 22
    $roles = $this->getNames($roleAggregate);
271 22
    $resources = $this->getNames($resourceAggregate);
272
273 22
    foreach ($roles as $roleName) {
274 21
      foreach ($resources as $resourceName) {
275 20
        foreach ($this->rules as $rule) {
276
277
          if (
278 18
              is_string($ruleName)
279 18
              &&
280 18
              !is_subclass_of($rule, 'SimpleAcl\Rule')
281 18
              &&
282 17
              $rule->getName() !== $ruleName
283 18
          ) {
284 7
            continue;
285
          }
286
287 17
          $rule->resetAggregate($roleAggregate, $resourceAggregate);
288
289 17
          $result = $rule->isAllowed($ruleName, $roleName, $resourceName);
290
291
          // Set null if rule don't match any role or resource.
292 17
          $ruleResultCollection->add($result);
293 20
        }
294 21
      }
295 22
    }
296
297 22
    return $ruleResultCollection;
298
  }
299
300
  /**
301
   * Get names.
302
   *
303
   * @param string|RoleAggregateInterface|ResourceAggregateInterface $object
304
   *
305
   * @return array
306
   */
307 22
  protected function getNames($object)
308
  {
309 22
    if (is_string($object) || null === $object) {
310 19
      return array($object);
311 7
    } elseif ($object instanceof RoleAggregateInterface) {
312 5
      return $object->getRolesNames();
313 5
    } elseif ($object instanceof ResourceAggregateInterface) {
314 4
      return $object->getResourcesNames();
315
    }
316
317 1
    return array();
318
  }
319
320
  /**
321
   * Remove rules by rule name and (or) role and resource.
322
   *
323
   * @param null|string $roleName
324
   * @param null|string $resourceName
325
   * @param null|string $ruleName
326
   * @param bool        $all
327
   */
328 3
  public function removeRule($roleName = null, $resourceName = null, $ruleName = null, $all = true)
329
  {
330
    if (
331 3
        null === $roleName
332 3
        &&
333 3
        null === $resourceName
334 3
        &&
335 3
        null === $ruleName
336 3
    ) {
337 2
      $this->removeAllRules();
338
339 2
      return;
340
    }
341
342 2
    foreach ($this->rules as $ruleIndex => $rule) {
343
      if (
344
          (
345
              $ruleName === null
346 2
              ||
347
              (
348
                  $ruleName !== null
349 2
                  &&
350 2
                  $ruleName === $rule->getName()
351 2
              )
352 2
          )
353 2
          &&
354
          (
355
              $roleName === null
356 2
              ||
357
              (
358
                  $roleName !== null
359 2
                  &&
360 2
                  $rule->getRole() && $rule->getRole()->getName() === $roleName
361 2
              )
362 2
          )
363 2
          &&
364
          (
365
              $resourceName === null
366 2
              ||
367
              (
368
                  $resourceName !== null
369 2
                  &&
370 2
                  $rule->getResource()
371 2
                  &&
372 2
                  $rule->getResource()->getName() === $resourceName
373 2
              )
374 2
          )
375 2
      ) {
376
377 1
        unset($this->rules[$ruleIndex]);
378 1
        if (!$all) {
379
          return;
380
        }
381
382 1
      }
383 2
    }
384 2
  }
385
386
  /**
387
   * Remove all rules.
388
   *
389
   */
390 3
  public function removeAllRules()
391
  {
392 3
    $this->rules = array();
393 3
  }
394
395
  /**
396
   * Removes rule by its id.
397
   *
398
   * @param mixed $ruleId
399
   */
400 2
  public function removeRuleById($ruleId)
401
  {
402 2
    foreach ($this->rules as $ruleIndex => $rule) {
403 2
      if ($rule->id === $ruleId) {
404 2
        unset($this->rules[$ruleIndex]);
405
406 2
        return;
407
      }
408 1
    }
409 1
  }
410
}
411