Passed
Push — master ( c86d4d...b204e9 )
by
unknown
03:35 queued 12s
created

AuthorizationService::getCanHandler()   A

Complexity

Conditions 3
Paths 2

Size

Total Lines 8
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 5
CRAP Score 3

Importance

Changes 0
Metric Value
eloc 4
c 0
b 0
f 0
dl 0
loc 8
ccs 5
cts 5
cp 1
rs 10
cc 3
nc 2
nop 2
crap 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