Role   B
last analyzed

Complexity

Total Complexity 40

Size/Duplication

Total Lines 472
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 5

Test Coverage

Coverage 72.31%

Importance

Changes 0
Metric Value
wmc 40
lcom 1
cbo 5
dl 0
loc 472
ccs 81
cts 112
cp 0.7231
rs 8.2608
c 0
b 0
f 0

28 Methods

Rating   Name   Duplication   Size   Complexity  
A assignResult() 0 20 2
A displayAsLeader() 0 4 1
A getUsers() 0 9 1
A getName() 0 4 1
A isReusable() 0 4 1
A isProtected() 0 4 1
A addPerm() 0 4 1
A getPerms() 0 4 1
A getRoles() 0 9 1
A getLeaderRoles() 0 8 1
A createNewRole() 0 13 1
A getDisplayColor() 0 4 1
A getDisplayName() 0 4 1
A getDisplayOrder() 0 4 1
A getDisplayIcon() 0 4 1
A getPermIDs() 0 4 1
A getPermObjects() 0 4 1
A hasPerm() 0 4 1
A removePerm() 0 4 1
D modifyPerm() 0 29 9
B setPerms() 0 22 4
A setName() 0 4 1
A setDisplayAsLeader() 0 4 1
A setDisplayIcon() 0 4 1
A setDisplayColor() 0 4 1
A setDisplayName() 0 4 1
A setDisplayOrder() 0 4 1
A getQueryBuilder() 0 10 1

How to fix   Complexity   

Complex Class

Complex classes like Role often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use Role, and based on these observations, apply Extract Interface, too.

1
<?php
2
/**
3
 * This file contains functionality relating to roles a player can have on the website to perform certain tasks
4
 *
5
 * @package    BZiON\Models
6
 * @license    https://github.com/allejo/bzion/blob/master/LICENSE.md GNU General Public License Version 3
7
 */
8
9
/**
10
 * A role a player is assigned
11
 * @package    BZiON\Models
12
 */
13
class Role extends UrlModel implements NamedModel
14
{
15
    const DEVELOPER     = 1;
16
    const ADMINISTRATOR = 2;
17
    const COP           = 3;
18
    const REFEREE       = 4;
19
    const SYSADMIN      = 5;
20
    const PLAYER        = 6;
21
    const PLAYER_NO_PM  = 7;
22
23
    /**
24
     * The name of the role
25
     * @var string
26
     */
27
    protected $name;
28
29
    /**
30
     * Whether or not a role is reusable, when a player has a unique role, they will have their own role that isn't
31
     * reusable by other players
32
     * @var bool
33
     */
34
    protected $reusable;
35
36
    /**
37
     * Whether or not the role is protected from being deleted from the web interface
38
     * @var bool
39
     */
40
    protected $protected;
41
42
    /**
43
     * Whether or not to display this role on the 'Admins' page where it lists the league's leaders
44
     * @var bool
45
     */
46
    protected $display;
47
48
    /**
49
     * A Font Awesome CSS class for the icon to be used for the conversation
50
     *
51
     * @var string
52
     */
53
    protected $displayIcon;
54
55
    /**
56
     * A CSS class that will represent the color of the conversation in their tab
57
     *
58
     * @var string
59
     */
60
    protected $displayColor;
61
62
    /**
63
     * The collective name the conversation will be called if this role is displayed on the 'Admins' page
64
     * @var string
65
     */
66
    protected $displayName;
67
68
    /**
69
     * The order in which the role will be displayed on the 'Admins' page
70
     * @var int
71
     */
72
    protected $displayOrder;
73
74
    /**
75
     * An array of permissions a role has
76
     * @var bool[]
77
     */
78
    protected $permissions;
79
80
    /**
81
     * The name of the database table used for queries
82
     */
83
    const TABLE = "roles";
84
85
    const CREATE_PERMISSION = Permission::CREATE_ROLE;
86
    const EDIT_PERMISSION = Permission::EDIT_ROLE;
87
    const SOFT_DELETE_PERMISSION = Permission::SOFT_DELETE_ROLE;
88
    const HARD_DELETE_PERMISSION = Permission::HARD_DELETE_ROLE;
89
90
    /**
91
     * {@inheritdoc}
92
     */
93 5
    protected function assignResult($role)
94
    {
95 5
        $this->name         = $role['name'];
96 5
        $this->reusable     = $role['reusable'];
97 5
        $this->protected    = $role['protected'];
98 5
        $this->display      = $role['display'];
99 5
        $this->displayIcon  = $role['display_icon'];
100 5
        $this->displayColor = $role['display_color'];
101 5
        $this->displayName  = $role['display_name'];
102 5
        $this->displayOrder = $role['display_order'];
103 5
        $this->permissions  = array();
104
105 5
        $permissions = self::fetchIds(
106 5
            "JOIN role_permission ON role_permission.perm_id = permissions.id WHERE role_permission.role_id = ?",
107 5
            array($this->id), "permissions", "name");
108
109 5
        foreach ($permissions as $permission) {
110 4
            $this->permissions[$permission] = true;
111
        }
112 5
    }
113
114
    /**
115
     * Check whether or not this role should appear on the "Admins" page
116
     *
117
     * @return bool True if the role should be displayed on the "Admins" page
118
     */
119 2
    public function displayAsLeader()
120
    {
121 2
        return (bool) $this->display;
122
    }
123
124
    /**
125
     * Get the color this role will have as the background in their badge
126
     *
127
     * @return string The color this role will have in their badge. If there is no color set, it will return green which has chosen
128
     *                randomly by a fair dice roll.
129
     */
130 1
    public function getDisplayColor()
131
    {
132 1
        return $this->displayColor;
133
    }
134
135
    /**
136
     * Get the "display name" of a role. The display name differs from the name of the role where the "Administrators"
137
     * role can be displayed as "League Council" when the role is used to displayed players assigned to this role.
138
     *
139
     * @return string Returns the display name. If the display name is blank, the role name will be returned.
140
     */
141 1
    public function getDisplayName()
142
    {
143 1
        return $this->displayName;
144
    }
145
146
    /**
147
     * Get the order this role should be displayed on the "Admins" page
148
     *
149
     * @return int The order the role should be displayed on the "Admins" page
150
     */
151 1
    public function getDisplayOrder()
152
    {
153 1
        return $this->displayOrder;
154
    }
155
156
    /**
157
     * Get the Font Awesome class that will be used as the symbol for the role on the "Admins" page
158
     *
159
     * @return string The Font Awesome class for the symbol
160
     */
161 1
    public function getDisplayIcon()
162
    {
163 1
        return $this->displayIcon;
164
    }
165
166
    /**
167
     * Get an array of players who have this role assigned to them
168
     *
169
     * @return Player[] An array of players with this role assigned to them
170
     */
171 1
    public function getUsers()
172
    {
173 1
        return Player::arrayIdToModel(
174 1
            self::fetchIds(
175 1
                "JOIN player_roles ON player_roles.role_id = roles.id WHERE player_roles.role_id = ?",
176 1
                array($this->getId()), "roles", "player_roles.user_id"
177
            )
178
        );
179
    }
180
181
    /**
182
     * Get the name of the role as displayed in the admin interface
183
     *
184
     * @return string The name of the conversation
185
     */
186 2
    public function getName()
187
    {
188 2
        return $this->name;
189
    }
190
191
    /**
192
     * Check if this role is for a conversation of users or if it's a role for a single user
193
     *
194
     * @return bool True if multiple users can be assigned this role
195
     */
196 1
    public function isReusable()
197
    {
198 1
        return (bool) $this->reusable;
199
    }
200
201
    /**
202
     * Check if this role is protected from being deleted
203
     *
204
     * @return bool True if this role is protected from being deleted
205
     */
206 2
    public function isProtected()
207
    {
208 2
        return (bool) $this->protected;
209
    }
210
211
    /**
212
     * Add a permission to a role
213
     *
214
     * @param string|Permission $perm_name The name of the permission to add
215
     *
216
     * @return bool Whether or not the operation was successful
217
     */
218 1
    public function addPerm($perm_name)
219
    {
220 1
        return $this->modifyPerm($perm_name, "add");
221
    }
222
223
    /**
224
     * Get the permissions a role has
225
     *
226
     * @return bool[] An array of permissions
227
     */
228 76
    public function getPerms()
229
    {
230 76
        return $this->permissions;
231
    }
232
233
    /**
234
     * Return the permissions a role has as IDs
235
     *
236
     * @return int[]
237
     */
238
    protected function getPermIDs()
239
    {
240
        return self::fetchIdsFrom("role_id", array($this->id), false, "", "role_permission", "perm_id");
241
    }
242
243
    /**
244
     * Return the permissions a role has as models
245
     *
246
     * @return Permission[]
247
     */
248
    public function getPermObjects()
249
    {
250
        return Permission::arrayIdToModel($this->getPermIDs());
251
    }
252
253
    /**
254
     * Check whether a role has a specified permission
255
     *
256
     * @param string $permission The permission to check for
257
     *
258
     * @return bool Whether or not the role has the permission
259
     */
260 2
    public function hasPerm($permission)
261
    {
262 2
        return isset($this->permissions[$permission]);
263
    }
264
265
    /**
266
     * Revoke a permission from a role
267
     *
268
     * @param string|Permission $perm_name The permission to remove
269
     *
270
     * @return bool Whether or not the operation was successful
271
     */
272 1
    public function removePerm($perm_name)
273
    {
274 1
        return $this->modifyPerm($perm_name, "remove");
275
    }
276
277
    /**
278
     * Modify a permission a role has by either adding a new one or removing an old one
279
     *
280
     * @param string|Permission $perm_name The permission to add or remove
281
     * @param string            $action    Whether to "add" or "remove" a permission
282
     *
283
     * @return bool
284
     */
285 1
    private function modifyPerm($perm_name, $action)
286
    {
287 1
        $name = ($perm_name instanceof Permission) ? $perm_name->getName() : $perm_name;
288
289 1
        if (($action == "remove" && !$this->hasPerm($name)) ||
290 1
            ($action == "add" && $this->hasPerm($name))) {
291 1
            return false;
292
        }
293
294 1
        $permission = Permission::getPermissionFromName($perm_name);
295
296 1
        if ($permission->isValid()) {
297 1
            if ($action == "add") {
298 1
                $this->db->execute("INSERT INTO role_permission (role_id, perm_id) VALUES (?, ?)",
299 1
                    array($this->getId(), $permission->getId()));
300
301 1
                $this->permissions[$name] = true;
302 1
            } elseif ($action == "remove") {
303 1
                $this->db->execute("DELETE FROM role_permission WHERE role_id = ? AND perm_id = ? LIMIT 1",
304 1
                    array($this->getId(), $permission->getId()));
305
306 1
                unset($this->permissions[$name]);
307
            }
308
309 1
            return true;
310
        }
311
312 1
        return false;
313
    }
314
315
    /**
316
     * Set the permissions of the role
317
     *
318
     * @todo   Consolidate this with Bans
319
     * @param  Permission[] $perms The permissions to set
320
     * @return self
321
     */
322
    public function setPerms($perms)
323
    {
324
        foreach ($perms as &$perm) {
325
            $perm = $perm->getId();
326
        }
327
        unset($perm);
328
329
        $oldPerms = $this->getPermIDs();
330
331
        $newPerms     = array_diff($perms, $oldPerms);
332
        $removedPerms = array_diff($oldPerms, $perms);
333
334
        foreach ($newPerms as $perm) {
335
            $this->addPerm(Permission::get($perm));
336
        }
337
338
        foreach ($removedPerms as $perm) {
339
            $this->removePerm(Permission::get($perm));
340
        }
341
342
        return $this;
343
    }
344
345
    /**
346
     * Set the name of the role
347
     *
348
     * @param  string $name The new name of the role
349
     * @return self
350
     */
351
    public function setName($name)
352
    {
353
        return $this->updateProperty($this->name, 'name', $name);
354
    }
355
356
    /**
357
     * Set whether the Role is displayed as a leader role
358
     *
359
     * @param  bool $display
360
     * @return self
361
     */
362
    public function setDisplayAsLeader($display)
363
    {
364
        return $this->updateProperty($this->display, 'display', (int) $display);
365
    }
366
367
    /**
368
     * Set the icon class of the role
369
     *
370
     * @param  string $displayIcon
371
     * @return self
372
     */
373
    public function setDisplayIcon($displayIcon)
374
    {
375
        return $this->updateProperty($this->displayIcon, 'display_icon', $displayIcon);
376
    }
377
378
    /**
379
     * Set the color of the role
380
     *
381
     * @param  string $displayColor
382
     * @return self
383
     */
384
    public function setDisplayColor($displayColor)
385
    {
386
        return $this->updateProperty($this->displayColor, 'display_color', $displayColor);
387
    }
388
389
    /**
390
     * Set the display name of the role
391
     *
392
     * @param  string $displayName
393
     * @return self
394
     */
395
    public function setDisplayName($displayName)
396
    {
397
        return $this->updateProperty($this->displayName, 'display_name', $displayName);
398
    }
399
400
    /**
401
     * Set the display order of the role
402
     *
403
     * @param  int $displayOrder
404
     * @return self
405
     */
406
    public function setDisplayOrder($displayOrder)
407
    {
408
        return $this->updateProperty($this->displayOrder, 'display_order', $displayOrder);
409
    }
410
411
    /**
412
     * Create a new role
413
     *
414
     * @param string $name         The name of new role to be created
415
     * @param bool   $reusable     Whether or not to have the role
416
     * @param bool   $display      Whether or not to display the role on the 'Admins' page
417
     * @param string $displayIcon
418
     * @param string $displayColor
419
     * @param null   $displayName  The name that will be used on the 'Admins' page, if $display is set to true
420
     * @param int    $displayOrder The order the role will be displayed on, if $display is set to true
421
     *
422
     * @return \Role
423
     */
424 2
    public static function createNewRole($name, $reusable, $display = false, $displayIcon = "", $displayColor = "", $displayName = null, $displayOrder = 0)
425
    {
426 2
        return self::create(array(
427 2
            'name'          => $name,
428 2
            'reusable'      => $reusable,
429 2
            'protected'     => 0,
430 2
            'display'       => $display,
431 2
            'display_icon'  => $displayIcon,
432 2
            'display_color' => $displayColor,
433 2
            'display_name'  => $displayName,
434 2
            'display_order' => $displayOrder
435
        ));
436
    }
437
438
    /**
439
     * Get the roles a player has
440
     *
441
     * @param int $user_id The user ID to get the roles for
442
     *
443
     * @return Role[] An array of Roles a player belongs to
444
     */
445 76
    public static function getRoles($user_id)
446
    {
447 76
        return parent::arrayIdToModel(
0 ignored issues
show
Comprehensibility Bug introduced by
It seems like you call parent on a different method (arrayIdToModel() instead of getRoles()). Are you sure this is correct? If so, you might want to change this to $this->arrayIdToModel().

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...
448 76
            self::fetchIds(
449 76
                "JOIN player_roles ON player_roles.role_id = roles.id WHERE player_roles.user_id = ?",
450 76
                array($user_id), "roles", "roles.id"
451
            )
452
        );
453
    }
454
455
    /**
456
     * Get the roles that should be displayed on the "Admins" page
457
     *
458
     * @return Role[] An array of Roles that should be displayed on the "Admins" page
459
     */
460 1
    public static function getLeaderRoles()
461
    {
462 1
        return parent::arrayIdToModel(
0 ignored issues
show
Comprehensibility Bug introduced by
It seems like you call parent on a different method (arrayIdToModel() instead of getLeaderRoles()). Are you sure this is correct? If so, you might want to change this to $this->arrayIdToModel().

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...
463 1
            self::fetchIds(
464 1
                "WHERE display = 1 ORDER BY display_order ASC"
465
            )
466
        );
467
    }
468
469
    /**
470
     * Get a query builder for Roles
471
     *
472
     * @return QueryBuilder
473
     */
474
    public static function getQueryBuilder()
475
    {
476
        return new QueryBuilder('Role', array(
477
            'columns' => array(
478
                'name'          => 'name',
479
                'display_order' => 'display_order'
480
            ),
481
            'name' => 'name'
482
        ));
483
    }
484
}
485