AuthorizationService   A
last analyzed

Complexity

Total Complexity 14

Size/Duplication

Total Lines 116
Duplicated Lines 0 %

Test Coverage

Coverage 94.59%

Importance

Changes 1
Bugs 0 Features 0
Metric Value
wmc 14
eloc 32
c 1
b 0
f 0
dl 0
loc 116
ccs 35
cts 37
cp 0.9459
rs 10

7 Methods

Rating   Name   Duplication   Size   Complexity  
A authorizationChecked() 0 3 1
A __construct() 0 3 1
A skipAuthorization() 0 4 1
A applyScope() 0 6 1
A can() 0 23 5
A getScopeHandler() 0 8 2
A getCanHandler() 0 8 3
1
<?php
2
3
/**
4
 * CakePHP(tm) : Rapid Development Framework (https://cakephp.org)
5
 * Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
6
 *
7
 * Licensed under The MIT License
8
 * For full copyright and license information, please see the LICENSE.txt
9
 * Redistributions of files must retain the above copyright notice.
10
 *
11
 * @copyright     Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
12
 * @link          https://cakephp.org CakePHP(tm) Project
13
 * @since         1.0.0
14
 * @license       https://opensource.org/licenses/mit-license.php MIT License
15
 */
16
17
declare(strict_types=1);
18
19
namespace Phauthentic\Authorization;
20
21
use Phauthentic\Authorization\Policy\BeforePolicyInterface;
22
use Phauthentic\Authorization\Policy\Exception\MissingMethodException;
23
use Phauthentic\Authorization\Policy\ResolverInterface;
24
use Phauthentic\Authorization\Policy\Result;
25
use Phauthentic\Authorization\Policy\ResultInterface;
26
use RuntimeException;
27
28
/**
29
 * Authorization Service
30
 */
31
class AuthorizationService implements AuthorizationServiceInterface
32
{
33
    /**
34
     * Authorization policy resolver.
35
     *
36
     * @var \Phauthentic\Authorization\Policy\ResolverInterface
37
     */
38
    protected $resolver;
39
40
    /**
41
     * Track whether or not authorization was checked.
42
     *
43
     * @var bool
44
     */
45
    protected $authorizationChecked = false;
46
47
    /**
48
     * Constructor
49
     *
50
     * @param \Phauthentic\Authorization\Policy\ResolverInterface $resolver Authorization policy resolver.
51
     */
52 30
    public function __construct(ResolverInterface $resolver)
53
    {
54 30
        $this->resolver = $resolver;
55 30
    }
56
57
    /**
58
     * {@inheritDoc}
59
     */
60 22
    public function can(?IdentityInterface $user, string $action, $resource): ResultInterface
61
    {
62 22
        $this->authorizationChecked = true;
63 22
        $policy = $this->resolver->getPolicy($resource);
64 22
        if ($policy instanceof BeforePolicyInterface) {
65 10
            $result = $policy->before($user, $resource, $action);
66
67 10
            if ($result) {
68 8
                return $result;
69
            }
70
        }
71
72 14
        $handler = $this->getCanHandler($policy, $action);
73 12
        $result = $handler($user, $resource);
74 12
        if (is_bool($result)) {
75
            return new Result($result);
76
        }
77
78 12
        if ($result instanceof ResultInterface) {
79 12
            return $result;
80
        }
81
82
        throw new RuntimeException(sprintf('Policy action handler must return instance of `%s` or `bool`.', ResultInterface::class));
83
    }
84
85
    /**
86
     * {@inheritDoc}
87
     */
88 6
    public function applyScope(?IdentityInterface $user, string $action, $resource)
89
    {
90 6
        $this->authorizationChecked = true;
91 6
        $policy = $this->resolver->getPolicy($resource);
92 6
        $handler = $this->getScopeHandler($policy, $action);
93 4
        return $handler($user, $resource);
94
    }
95
96
    /**
97
     * Returns a policy action handler.
98
     *
99
     * @param mixed $policy Policy object.
100
     * @param string $action Action name.
101
     * @return callable
102
     * @throws \Phauthentic\Authorization\Policy\Exception\MissingMethodException
103
     */
104 14
    protected function getCanHandler($policy, $action): callable
105
    {
106 14
        $method = 'can' . ucfirst($action);
107 14
        if (!method_exists($policy, $method) && !method_exists($policy, '__call')) {
108 2
            throw (new MissingMethodException())->setMessageVars([$method, $action, get_class($policy)]);
109
        }
110
111 12
        return [$policy, $method];
112
    }
113
114
    /**
115
     * Returns a policy scope action handler.
116
     *
117
     * @param mixed $policy Policy object.
118
     * @param string $action Action name.
119
     * @return callable
120
     * @throws \Phauthentic\Authorization\Policy\Exception\MissingMethodException
121
     */
122 6
    protected function getScopeHandler($policy, $action): callable
123
    {
124 6
        $method = 'scope' . ucfirst($action);
125 6
        if (!method_exists($policy, $method)) {
126 2
            throw (new MissingMethodException())->setMessageVars([$method, $action, get_class($policy)]);
127
        }
128
129 4
        return [$policy, $method];
130
    }
131
132
    /**
133
     * {@inheritDoc}
134
     */
135 6
    public function authorizationChecked(): bool
136
    {
137 6
        return $this->authorizationChecked;
138
    }
139
140
    /**
141
     * {@inheritDoc}
142
     */
143 2
    public function skipAuthorization(): AuthorizationServiceInterface
144
    {
145 2
        $this->authorizationChecked = true;
146 2
        return $this;
147
    }
148
}
149