Completed
Push — feature/admin-cp ( 8874f8 )
by Vladimir
08:22 queued 03:36
created

AdminController::isEditorFor()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 21
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 21
rs 9.3142
c 0
b 0
f 0
cc 3
eloc 12
nc 3
nop 2
1
<?php
2
3
class AdminController extends HTMLController
4
{
5
    public function listAction()
6
    {
7
        $rolesToDisplay = Role::getLeaderRoles();
8
        $roles = array();
9
10
        foreach ($rolesToDisplay as $role) {
11
            $roleMembers = $role->getUsers();
0 ignored issues
show
Bug introduced by
It seems like you code against a specific sub-type and not the parent class Model as the method getUsers() does only exist in the following sub-classes of Model: Role. Maybe you want to instanceof check for one of these explicitly?

Let’s take a look at an example:

abstract class User
{
    /** @return string */
    abstract public function getPassword();
}

class MyUser extends User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different sub-classes of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the parent class:

    abstract class User
    {
        /** @return string */
        abstract public function getPassword();
    
        /** @return string */
        abstract public function getDisplayName();
    }
    
Loading history...
12
13
            if (count($roleMembers) > 0) {
14
                $roles[] = array(
15
                    "role"    => $role,
16
                    "members" => $roleMembers
17
                );
18
            }
19
        }
20
21
        return array("role_sections" => $roles);
22
    }
23
24
    public function landingAction(Player $me)
25
    {
26
        if (!$me->isValid()) {
27
            throw new ForbiddenException('Please log in to view this page.');
28
        }
29
30
        // @todo Model editing should be a generic permission
31
        $canViewModelEditor = true;
32
        $canViewPageEditor = $this->isEditorFor(Page::class, $me);
33
        $canViewRoleEditor = $this->isEditorFor(Role::class, $me);
34
        $canViewVisitLog   = $me->hasPermission(Permission::VIEW_VISITOR_LOG);
35
36
        if (!$canViewPageEditor && !$canViewRoleEditor && !$canViewVisitLog) {
37
            throw new ForbiddenException('Contact a site administrator if you feel you should have access to this page.');
38
        }
39
40
        return [
41
            'canViewPageEditor' => $canViewPageEditor,
42
            'canViewRoleEditor' => $canViewRoleEditor,
43
            'canViewModelEditor' => $canViewModelEditor,
44
            'canViewVisitLog' => $canViewVisitLog,
45
        ];
46
    }
47
48
    public function pageListAction(Player $me)
49
    {
50
        if (!$me->isValid()) {
51
            throw new ForbiddenException('Please log in to view this page.');
52
        }
53
54
        if (!$this->isEditorFor(Page::class, $me)) {
55
            throw new ForbiddenException('Contact a site administrator if you feel you should have access to this page.');
56
        }
57
58
        $pages = Page::getQueryBuilder()
59
            ->where('status')->notEquals('deleted')
60
            ->getModels(true)
61
        ;
62
63
        return [
64
            'pages' => $pages,
65
            'canCreate' => $me->hasPermission(Page::CREATE_PERMISSION),
66
            'canEdit' => $me->hasPermission(Page::EDIT_PERMISSION),
67
            'canDelete' => $me->hasPermission(Page::SOFT_DELETE_PERMISSION),
68
            'canWipe' => $me->hasPermission(Page::HARD_DELETE_PERMISSION),
69
        ];
70
    }
71
72
    public function wipeAction(Player $me)
73
    {
74
        $canViewThisPage = false;
75
        $wipeable = array('Ban', 'Map', 'Match', 'News', 'NewsCategory', 'Page', 'Server', 'Team');
76
        $models   = array();
77
78
        foreach ($wipeable as $type) {
79
            if (!$me->hasPermission($type::HARD_DELETE_PERMISSION)) {
80
                continue;
81
            }
82
83
            $canViewThisPage = true;
84
            $models = array_merge($models, $type::getQueryBuilder()
85
                ->where('status')->equals('deleted')
86
                ->getModels());
87
        }
88
89
        // Permission checking
90
        if (!$me->isValid()) {
91
            throw new ForbiddenException("Please log in to view this page.");
92
        }
93
        if (!$canViewThisPage) {
94
            throw new ForbiddenException("Contact a site administrator if you feel you should have access to this page.");
95
        }
96
97
        return array('models' => $models);
98
    }
99
100
    private function isEditorFor($className, Player $me)
101
    {
102
        $permissionConstants = [
103
            'CREATE_PERMISSION',
104
            'EDIT_PERMISSION',
105
            'SOFT_DELETE_PERMISSION',
106
            'HARD_DELETE_PERMISSION',
107
        ];
108
109
        $reflector = new ReflectionClass($className);
110
111
        foreach ($permissionConstants as $permission) {
112
            $permissionName = $reflector->getConstant($permission);
113
114
            if ($me->hasPermission($permissionName)) {
115
                return true;
116
            }
117
        }
118
119
        return false;
120
    }
121
}
122