Completed
Push — master ( 736ea4...748881 )
by Mathieu
12:57
created

Manager::addRoleAndPermissions()   C

Complexity

Conditions 11
Paths 48

Size

Total Lines 36
Code Lines 22

Duplication

Lines 20
Ratio 55.56 %

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 20
loc 36
rs 5.2653
cc 11
eloc 22
nc 48
nop 4

How to fix   Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
namespace Charcoal\User\Acl;
4
5
// Dependencies from `ext-pdo`
6
use PDO;
7
use PDOException;
8
9
// Dependencies from 'PSR-3' (Logging)
10
use Psr\Log\LoggerAwareInterface;
11
use Psr\Log\LoggerAwareTrait;
12
13
// Dependencies from `zendframework/zend-permissions`
14
use Zend\Permissions\Acl\Acl;
15
use Zend\Permissions\Acl\Role\GenericRole as Role;
0 ignored issues
show
Bug introduced by
This use statement conflicts with another class in this namespace, Charcoal\User\Acl\Role.

Let’s assume that you have a directory layout like this:

.
|-- OtherDir
|   |-- Bar.php
|   `-- Foo.php
`-- SomeDir
    `-- Foo.php

and let’s assume the following content of Bar.php:

// Bar.php
namespace OtherDir;

use SomeDir\Foo; // This now conflicts the class OtherDir\Foo

If both files OtherDir/Foo.php and SomeDir/Foo.php are loaded in the same runtime, you will see a PHP error such as the following:

PHP Fatal error:  Cannot use SomeDir\Foo as Foo because the name is already in use in OtherDir/Foo.php

However, as OtherDir/Foo.php does not necessarily have to be loaded and the error is only triggered if it is loaded before OtherDir/Bar.php, this problem might go unnoticed for a while. In order to prevent this error from surfacing, you must import the namespace with a different alias:

// Bar.php
namespace OtherDir;

use SomeDir\Foo as SomeDirFoo; // There is no conflict anymore.
Loading history...
16
use Zend\Permissions\Acl\Resource\GenericResource as Resource;
17
18
/**
19
 * Manage ACL roles and permissions from config (arrays) or database.
20
 */
21
class Manager implements LoggerAwareInterface
22
{
23
    use LoggerAwareTrait;
24
25
    /**
26
     * Constructor options:
27
     * - `logger`
28
     *
29
     * @param array $data Constructor options.
30
     */
31
    public function __construct(array $data)
32
    {
33
        $this->setLogger($data['logger']);
34
    }
35
36
    /**
37
     * @param Acl    $acl         The Zend Acl instant to load permissions to.
38
     * @param array  $permissions The array of permissions, in [role=>details] array.
39
     * @param string $resource    The Acl resource (string identifier) to load roles and permissions into.
40
     * @return void
41
     */
42
    public function loadPermissions(Acl &$acl, array $permissions, $resource = '')
43
    {
44
        foreach ($permissions as $role => $rolePermissions) {
45
            $this->addRoleAndPermissions($acl, $role, $rolePermissions, $resource);
46
        }
47
    }
48
49
    /**
50
     * @param Acl    $acl      The Zend Acl instance to load permissions to.
51
     * @param PDO    $db       The PDO database instance.
52
     * @param string $table    The table where to fetch the roles and permissions.
53
     * @param string $resource The Acl resource (string identifier) to load roles and permissions into.
54
     * @return void
55
     */
56
    public function loadDatabasePermissions(Acl &$acl, PDO $db, $table, $resource = '')
57
    {
58
        // Quick-and-dirty sanitization
59
        $table = preg_replace('/[^A-Za-z0-9 ]/', '', $table);
60
61
        $q = '
62
            SELECT
63
                `ident`,
64
                `parent`,
65
                `denied`,
66
                `allowed`,
67
                `superuser`
68
            FROM
69
                `'.$table.'`
70
            ORDER BY
71
                `position` ASC';
72
73
        $this->logger->debug($q);
74
75
        // Put inside a try-catch block because ACL is optional; table might not exist.
76
        try {
77
            $sth = $db->query($q);
78
            while ($row = $sth->fetch(PDO::FETCH_ASSOC)) {
79
                $this->addRoleAndPermissions($acl, $row['ident'], $row, $resource);
80
            }
81
        } catch (PDOException $e) {
82
            $this->logger->warning('Can not fetch ACL roles: '.$e->getMessage());
83
        }
84
    }
85
86
    /**
87
     * @param Acl    $acl         The Zend Acl instant to add permissions to.
88
     * @param string $role        The role (string identifier) to add.
89
     * @param array  $permissions The permissions details (array) to add.
90
     * @param string $resource    The Acl resource (string identifier) to add roles and permissions into.
91
     * @return void
92
     */
93
    private function addRoleAndPermissions(Acl &$acl, $role, array $permissions, $resource)
94
    {
95
        if (!$acl->hasRole($role)) {
96
            // Add role
97
            $parentRole = isset($permissions['parent']) ? $permissions['parent'] : null;
98
            $newRole = new Role($role);
99
            $acl->addRole($newRole, $parentRole);
100
        }
101
102
        if (isset($permissions['superuser']) && $permissions['superuser']) {
103
            $acl->allow($role);
104
            return;
105
        }
106
107 View Code Duplication
        if (isset($permissions['allowed'])) {
0 ignored issues
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...
108
            if (is_string($permissions['allowed'])) {
109
                $allowedPermissions = explode(',', $permissions['allowed']);
110
            } else {
111
                $allowedPermissions = $permissions['allowed'];
112
            }
113
            foreach ($allowedPermissions as $allowed) {
114
                $acl->allow($role, $resource, $allowed);
115
            }
116
        }
117
118 View Code Duplication
        if (isset($permissions['denied'])) {
0 ignored issues
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...
119
            if (is_string($permissions['denied'])) {
120
                $deniedPermissions = explode(',', $permissions['denied']);
121
            } else {
122
                $deniedPermissions = $permissions['denied'];
123
            }
124
            foreach ($deniedPermissions as $denied) {
125
                $acl->deny($role, $resource, $denied);
126
            }
127
        }
128
    }
129
}
130