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

ByLevel   A

Complexity

Total Complexity 14

Size/Duplication

Total Lines 99
Duplicated Lines 4.04 %

Coupling/Cohesion

Components 1
Dependencies 1

Test Coverage

Coverage 100%

Importance

Changes 0
Metric Value
dl 4
loc 99
c 0
b 0
f 0
wmc 14
lcom 1
cbo 1
ccs 30
cts 30
cp 1
rs 10

5 Methods

Rating   Name   Duplication   Size   Complexity  
user() 0 1 ?
getAccessLevels() 0 1 ?
B getLevel() 0 19 7
A getRoles() 0 10 2
B is() 4 25 5

How to fix   Duplicated Code   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

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