Completed
Push — master ( bef74a...88d31d )
by Tobias
10:04 queued 07:36
created

User::can()   A

Complexity

Conditions 4
Paths 3

Size

Total Lines 16
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Importance

Changes 4
Bugs 1 Features 1
Metric Value
c 4
b 1
f 1
dl 0
loc 16
rs 9.2
cc 4
eloc 11
nc 3
nop 3
1
<?php
2
3
namespace app\components;
4
5
/**
6
 * @link http://www.diemeisterei.de/
7
 *
8
 * @copyright Copyright (c) 2015 diemeisterei GmbH, Stuttgart
9
 *
10
 * For the full copyright and license information, please view the LICENSE
11
 * file that was distributed with this source code.
12
 */
13
14
/**
15
 * Class User.
16
 *
17
 * Custom user class with additional checks and implementation of a 'root' user, who
18
 * has all permissions (`can()` always return true)
19
 */
20
class User extends \yii\web\User
21
{
22
    const PUBLIC_ROLE = 'Public';
23
24
    /**
25
     * @var array Users with all permissions
26
     */
27
    public $rootUsers = [];
28
29
    /**
30
     * Extended permission check with `Guest` role and `route`.
31
     *
32
     * @param string    $permissionName
33
     * @param array     $params
34
     * @param bool|true $allowCaching
35
     *
36
     * @return bool
37
     */
38
    public function can($permissionName, $params = [], $allowCaching = true)
39
    {
40
        switch (true) {
41
            // root users have all permissions
42
            case \Yii::$app->user->identity && in_array(\Yii::$app->user->identity->username, $this->rootUsers):
43
                return true;
44
                break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
45
            case !empty($params['route']):
46
                \Yii::trace("Checking route permissions for '{$permissionName}'", __METHOD__);
47
48
                return $this->checkAccessRoute($permissionName, $params, $allowCaching);
49
                break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
50
            default:
51
                return parent::can($permissionName, $params, $allowCaching);
52
        }
53
    }
54
55
    /**
56
     * Checks permissions from guest role, when no user is logged in.
57
     *
58
     * @param $permissionName
59
     * @param $params
60
     * @param $allowCaching
61
     *
62
     * @return bool
63
     */
64
    private function canGuest($permissionName, $params, $allowCaching)
0 ignored issues
show
Unused Code introduced by
The parameter $params is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $allowCaching is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
65
    {
66
        $guestPermissions = $this->getAuthManager()->getPermissionsByRole(self::PUBLIC_ROLE);
67
68
        return array_key_exists($permissionName, $guestPermissions);
69
    }
70
71
    /**
72
     * Checks route permissions.
73
     *
74
     * Splits `permissionName` by underscore and match parts against more global rule
75
     * eg. a permission `app_site` will match, `app_site_foo`
76
     *
77
     * @param $permissionName
78
     * @param $params
79
     * @param $allowCaching
80
     *
81
     * @return bool
82
     */
83
    private function checkAccessRoute($permissionName, $params, $allowCaching)
84
    {
85
        $route = explode('_', $permissionName);
86
        $routePermission = '';
87
        foreach ($route as $part) {
88
            $routePermission .= $part;
89
            if (\Yii::$app->user->id) {
90
                $canRoute = parent::can($routePermission, $params, $allowCaching);
0 ignored issues
show
Comprehensibility Bug introduced by
It seems like you call parent on a different method (can() instead of checkAccessRoute()). Are you sure this is correct? If so, you might want to change this to $this->can().

This check looks for a call to a parent method whose name is different than the method from which it is called.

Consider the following code:

class Daddy
{
    protected function getFirstName()
    {
        return "Eidur";
    }

    protected function getSurName()
    {
        return "Gudjohnsen";
    }
}

class Son
{
    public function getFirstName()
    {
        return parent::getSurname();
    }
}

The getFirstName() method in the Son calls the wrong method in the parent class.

Loading history...
91
            } else {
92
                $canRoute = $this->canGuest($routePermission, $params, $allowCaching);
93
            }
94
            if ($canRoute) {
95
                return true;
96
            }
97
            $routePermission .= '_';
98
        }
99
100
        return false;
101
    }
102
}
103