Completed
Push — master ( 80fdf3...351fbc )
by Vladimir
02:43
created

controllers/AdminController.php (1 issue)

strict.coding_against_specific_subtype

Bug Minor

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
3
use Symfony\Component\HttpFoundation\Request;
4
5
/**
6
 * @todo Configure the AdminController to be behind a Symfony firewall
7
 */
8
class AdminController extends HTMLController
9
{
10
    private static $wipeableModels = ['Ban', 'Map', 'Match', 'News', 'NewsCategory', 'Page', 'Server', 'Team'];
11
12
    public function listAction()
13
    {
14
        $rolesToDisplay = Role::getLeaderRoles();
15
        $roles = array();
16
17
        foreach ($rolesToDisplay as $role) {
18
            $roleMembers = $role->getUsers();
0 ignored issues
show
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...
19
20
            if (count($roleMembers) > 0) {
21
                $roles[] = array(
22
                    "role"    => $role,
23
                    "members" => $roleMembers
24
                );
25
            }
26
        }
27
28
        return array("role_sections" => $roles);
29
    }
30
31
    public function landingAction(Player $me)
32
    {
33
        if (!$me->isValid()) {
34
            throw new ForbiddenException('Please log in to view this page.');
35
        }
36
37
        // @todo Model editing should be a generic permission
38
        $canViewModelEditor = true;
39
        $canViewPageEditor = $this->isEditorFor(Page::class, $me);
40
        $canViewRoleEditor = $this->isEditorFor(Role::class, $me);
41
        $canViewVisitLog   = $me->hasPermission(Permission::VIEW_VISITOR_LOG);
42
43
        if (!$canViewPageEditor && !$canViewRoleEditor && !$canViewVisitLog) {
44
            throw new ForbiddenException('Contact a site administrator if you feel you should have access to this page.');
45
        }
46
47
        return [
48
            'canViewPageEditor' => $canViewPageEditor,
49
            'canViewRoleEditor' => $canViewRoleEditor,
50
            'canViewModelEditor' => $canViewModelEditor,
51
            'canViewVisitLog' => $canViewVisitLog,
52
        ];
53
    }
54
55 View Code Duplication
    public function pageListAction(Player $me)
56
    {
57
        if (!$me->isValid()) {
58
            throw new ForbiddenException('Please log in to view this page.');
59
        }
60
61
        if (!$this->isEditorFor(Page::class, $me)) {
62
            throw new ForbiddenException('Contact a site administrator if you feel you should have access to this page.');
63
        }
64
65
        $pages = Page::getQueryBuilder()
66
            ->where('status')->notEquals('deleted')
67
            ->getModels(true)
68
        ;
69
70
        return [
71
            'pages' => $pages,
72
            'canCreate' => $me->hasPermission(Page::CREATE_PERMISSION),
73
            'canEdit' => $me->hasPermission(Page::EDIT_PERMISSION),
74
            'canDelete' => $me->hasPermission(Page::SOFT_DELETE_PERMISSION),
75
            'canWipe' => $me->hasPermission(Page::HARD_DELETE_PERMISSION),
76
        ];
77
    }
78
79 View Code Duplication
    public function roleListAction(Player $me)
80
    {
81
        if (!$me->isValid()) {
82
            throw new ForbiddenException('Please log in to view this page.');
83
        }
84
85
        if (!$this->isEditorFor(Role::class, $me)) {
86
            throw new ForbiddenException('Contact a site administrator if you feel you should have access to this page.');
87
        }
88
89
        $roles = Role::getQueryBuilder()
90
            ->sortBy('display_order')
91
            ->getModels($fast = true)
92
        ;
93
94
        return [
95
            'roles' => $roles,
96
            'canCreate' => $me->hasPermission(Role::CREATE_PERMISSION),
97
            'canEdit' => $me->hasPermission(Role::EDIT_PERMISSION),
98
            'canDelete' => $me->hasPermission(Role::SOFT_DELETE_PERMISSION),
99
            'canWipe' => $me->hasPermission(Role::HARD_DELETE_PERMISSION),
100
        ];
101
    }
102
103
    public function modelsAction(Player $me)
104
    {
105
        if (!$me->isValid()) {
106
            throw new ForbiddenException('Please log in to view this page.');
107
        }
108
109
        // @todo Implement a new and proper "Model Editor" permission
110
        if (!$me->hasPermission(Team::SOFT_DELETE_PERMISSION)) {
111
            throw new ForbiddenException('Contact a site administrator if you feel you should have access to this page.');
112
        }
113
114
        return [
115
116
        ];
117
    }
118
119
    public function modelListAction(Request $request, Player $me, $type)
120
    {
121
        $type = ucfirst($type);
122
123
        if (!$me->isValid()) {
124
            throw new ForbiddenException('Please log in to view this page.');
125
        }
126
127
        if (!$me->hasPermission($type::SOFT_DELETE_PERMISSION)) {
128
            throw new ForbiddenException('Contact a site administrator if you feel you should have access to this page.');
129
        }
130
131
        $searchTerm = $request->get('search');
132
133
        $currentPage = $this->getCurrentPage();
134
135
        /** @var QueryBuilder $qb */
136
        $qb = $type::getQueryBuilder()
137
            ->where('status')->equals('deleted')
138
            ->sortBy('name')
139
        ;
140
141
        if ($searchTerm !== null) {
142
            $qb->where('name')->isLike($searchTerm);
143
        }
144
145
        $models = $qb
146
            ->limit(15)
147
            ->fromPage($currentPage)
148
            ->getModels()
149
        ;
150
151
        return [
152
            'type' => $type,
153
            'models' => $models,
154
            'canRestore' => $me->hasPermission($type::SOFT_DELETE_PERMISSION),
155
            'canWipe' => $me->hasPermission($type::HARD_DELETE_PERMISSION),
156
            'currentPage' => $currentPage,
157
            'totalPages' => $qb->countPages(),
158
            'searchTerm' => $searchTerm,
159
        ];
160
    }
161
162
    public function wipeAction(Player $me)
163
    {
164
        $canViewThisPage = false;
165
        $wipeable = array('Ban', 'Map', 'Match', 'News', 'NewsCategory', 'Page', 'Server', 'Team');
166
        $models   = array();
167
168
        foreach ($wipeable as $type) {
169
            if (!$me->hasPermission($type::HARD_DELETE_PERMISSION)) {
170
                continue;
171
            }
172
173
            $canViewThisPage = true;
174
            $models = array_merge($models, $type::getQueryBuilder()
175
                ->where('status')->equals('deleted')
176
                ->getModels());
177
        }
178
179
        // Permission checking
180
        if (!$me->isValid()) {
181
            throw new ForbiddenException("Please log in to view this page.");
182
        }
183
        if (!$canViewThisPage) {
184
            throw new ForbiddenException("Contact a site administrator if you feel you should have access to this page.");
185
        }
186
187
        return array('models' => $models);
188
    }
189
190
    private function isEditorFor($className, Player $me)
191
    {
192
        $permissionConstants = [
193
            'CREATE_PERMISSION',
194
            'EDIT_PERMISSION',
195
            'SOFT_DELETE_PERMISSION',
196
            'HARD_DELETE_PERMISSION',
197
        ];
198
199
        $reflector = new ReflectionClass($className);
200
201
        foreach ($permissionConstants as $permission) {
202
            $permissionName = $reflector->getConstant($permission);
203
204
            if ($me->hasPermission($permissionName)) {
205
                return true;
206
            }
207
        }
208
209
        return false;
210
    }
211
}
212