Completed
Push — master ( 723cc3...ac603f )
by Arnold
07:30
created

ByLevel::getLevel()   B

Complexity

Conditions 7
Paths 5

Size

Total Lines 19
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 10
CRAP Score 7

Importance

Changes 0
Metric Value
dl 0
loc 19
c 0
b 0
f 0
ccs 10
cts 10
cp 1
rs 8.2222
nc 5
cc 7
eloc 10
nop 1
crap 7
1
<?php
2
3
namespace Jasny\Authz;
4
5
/**
6
 * Authorize by access level.
7
 * 
8
 * <code>
9
 *   class Auth extends Jasny\Auth
10
 *   {
11
 *     use Jasny\Authz\ByLevel;
12
 *
13
 *     protected function getAccessLevels()
14
 *     {
15
 *       return [
16
 *         'user' => 1,
17
 *         'moderator' => 100,
18
 *         'admin' => 1000
19
 *       ];
20
 *     }
21
 *   }
22
 * </code>
23
 */
24
trait ByLevel
25
{
26
    /**
27
     * Get the authenticated user
28
     * 
29
     * @return User
30
     */
31
    abstract public function user();
32
    
33
    /**
34
     * Get all access levels.
35
     *  
36
     * @return array
37
     */
38
    abstract protected function getAccessLevels();
39
    
40
    /**
41
     * Get access level by name.
42
     * 
43
     * @param string|int $role
44
     * @return int
45
     * @throws DomainException for unknown level names
46
     */
47 11
    public function getLevel($role)
48
    {
49 11
        if (is_int($role) || (is_string($role) && ctype_digit($role))) {
50 3
            return (int)$role;
51
        }
52
        
53 10
        if (!is_string($role)) {
54 2
            $type = (is_object($role) ? get_class($role) . ' ' : '') . gettype($role);
55 2
            throw new \InvalidArgumentException("Expected role to be a string, not a $type");
56
        }
57
        
58 8
        $levels = $this->getAccessLevels();
59
        
60 8
        if (!isset($levels[$role])) {
61 2
            throw new \DomainException("Authorization level '$role' isn't defined.");
62
        }
63
        
64 6
        return $levels[$role];
65
    }
66
    
67
    /**
68
     * Get all authz roles
69
     *  
70
     * @return array
71
     */
72 11
    public function getRoles()
73
    {
74 11
        $levels = $this->getAccessLevels();
75
        
76 11
        if (!is_array($levels)) {
77 1
            throw new \UnexpectedValueException("Access levels should be an array");
78
        }
79
        
80 10
        return array_keys($levels);
81
    }
82
    
83
    /**
84
     * Check if the current user is logged in and has specified role.
85
     * 
86
     * <code>
87
     *   if (!$auth->is('manager')) {
88
     *     http_response_code(403); // Forbidden
89
     *     echo "You are not allowed to view this page";
90
     *     exit();
91
     *   }
92
     * </code>
93
     * 
94
     * @param string|int $role
95
     * @return boolean
96
     */
97 9
    public function is($role)
98
    {
99 9 View Code Duplication
        if (!in_array($role, $this->getRoles())) {
1 ignored issue
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
100 1
            trigger_error("Unknown role '$role'", E_USER_NOTICE);
101 1
            return false;
102
        }
103
        
104 8
        $user = $this->user();
105
        
106 8
        if (!isset($user)) {
107 1
            return false;
108
        }
109
        
110
        try {
111 7
            $userLevel = $this->getLevel($user->getRole());
112 7
        } catch (\DomainException $ex) {
113 1
            trigger_error("Unknown user role '" . $user->getRole() . "'", E_USER_NOTICE);
114 1
            return false;
115 1
        } catch (\Exception $ex) {
116 1
            trigger_error($ex->getMessage(), E_USER_WARNING);
117 1
            return false;
118
        } 
119
        
120 5
        return $userLevel >= $this->getLevel($role);
121
    }
122
}
123