Completed
Push — master ( 2a4315...ac93b3 )
by Nicolaas
01:25
created

PermissionProviderFactory   C

Complexity

Total Complexity 62

Size/Duplication

Total Lines 324
Duplicated Lines 0 %

Coupling/Cohesion

Components 2
Dependencies 12

Importance

Changes 0
Metric Value
wmc 62
lcom 2
cbo 12
dl 0
loc 324
rs 5.9493
c 0
b 0
f 0

15 Methods

Rating   Name   Duplication   Size   Complexity  
A inst() 0 8 2
A setEmail() 0 1 1
A setFirstName() 0 1 1
A setSurname() 0 1 1
A setPassword() 0 1 1
A setCode() 0 1 1
A setName() 0 1 1
A setParentGroup() 0 1 1
A setPermissionCode() 0 1 1
A setRoleTitle() 0 1 1
A setPermissionArray() 0 1 1
A setMember() 0 1 1
A CreateGroupAndMember() 0 20 1
F CreateDefaultMember() 0 47 10
F CreateGroup() 0 191 38

How to fix   Complexity   

Complex Class

Complex classes like PermissionProviderFactory 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 PermissionProviderFactory, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
4
class PermissionProviderFactory extends Object
0 ignored issues
show
Coding Style Compatibility introduced by
PSR1 recommends that each class must be in a namespace of at least one level to avoid collisions.

You can fix this by adding a namespace to your class:

namespace YourVendor;

class YourClass { }

When choosing a vendor namespace, try to pick something that is not too generic to avoid conflicts with other libraries.

Loading history...
5
{
6
7
    private static $_instance = null;
8
9
    public static function inst()
10
    {
11
        if(self::$_instance === null) {
12
            self::$_instance = Injector::inst()->get('PermissionProviderFactory');
13
        }
14
15
        return self::$_instance;
16
    }
17
18
    protected $email = '';
19
    protected $firstName = '';
20
    protected $surname = '';
21
    protected $code = '';
22
    protected $name = '';
23
    protected $parentGroup = null;
24
    protected $permissionCode = '';
25
    protected $roleTitle = '';
26
    protected $permissionArray = [];
27
    protected $member = null;
28
29
    public function setEmail($email){$this->email = $email; return $this;}
0 ignored issues
show
Coding Style introduced by
It is generally recommended to place each PHP statement on a line by itself.

Let’s take a look at an example:

// Bad
$a = 5; $b = 6; $c = 7;

// Good
$a = 5;
$b = 6;
$c = 7;
Loading history...
30
    public function setFirstName($firstName){$this->firstName = $firstName; return $this;}
0 ignored issues
show
Coding Style introduced by
It is generally recommended to place each PHP statement on a line by itself.

Let’s take a look at an example:

// Bad
$a = 5; $b = 6; $c = 7;

// Good
$a = 5;
$b = 6;
$c = 7;
Loading history...
31
    public function setSurname($surname){$this->surname = $surname; return $this;}
0 ignored issues
show
Coding Style introduced by
It is generally recommended to place each PHP statement on a line by itself.

Let’s take a look at an example:

// Bad
$a = 5; $b = 6; $c = 7;

// Good
$a = 5;
$b = 6;
$c = 7;
Loading history...
32
    public function setPassword($password){$this->password = $password; return $this;}
0 ignored issues
show
Bug introduced by
The property password does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
Coding Style introduced by
It is generally recommended to place each PHP statement on a line by itself.

Let’s take a look at an example:

// Bad
$a = 5; $b = 6; $c = 7;

// Good
$a = 5;
$b = 6;
$c = 7;
Loading history...
33
    public function setCode($code){$this->code = $code; return $this;}
0 ignored issues
show
Coding Style introduced by
It is generally recommended to place each PHP statement on a line by itself.

Let’s take a look at an example:

// Bad
$a = 5; $b = 6; $c = 7;

// Good
$a = 5;
$b = 6;
$c = 7;
Loading history...
34
    public function setName($name){$this->name = $name; return $this;}
0 ignored issues
show
Coding Style introduced by
It is generally recommended to place each PHP statement on a line by itself.

Let’s take a look at an example:

// Bad
$a = 5; $b = 6; $c = 7;

// Good
$a = 5;
$b = 6;
$c = 7;
Loading history...
35
    public function setParentGroup($parentGroup){$this->parentGroup = $parentGroup; return $this;}
0 ignored issues
show
Coding Style introduced by
It is generally recommended to place each PHP statement on a line by itself.

Let’s take a look at an example:

// Bad
$a = 5; $b = 6; $c = 7;

// Good
$a = 5;
$b = 6;
$c = 7;
Loading history...
36
    public function setPermissionCode($permissionCode){$this->permissionCode = $permissionCode; return $this;}
0 ignored issues
show
Coding Style introduced by
It is generally recommended to place each PHP statement on a line by itself.

Let’s take a look at an example:

// Bad
$a = 5; $b = 6; $c = 7;

// Good
$a = 5;
$b = 6;
$c = 7;
Loading history...
37
    public function setRoleTitle($roleTitle){$this->roleTitle = $roleTitle; return $this;}
0 ignored issues
show
Coding Style introduced by
It is generally recommended to place each PHP statement on a line by itself.

Let’s take a look at an example:

// Bad
$a = 5; $b = 6; $c = 7;

// Good
$a = 5;
$b = 6;
$c = 7;
Loading history...
38
    public function setPermissionArray($permissionArray){$this->permissionArray = $permissionArray; return $this;}
0 ignored issues
show
Coding Style introduced by
It is generally recommended to place each PHP statement on a line by itself.

Let’s take a look at an example:

// Bad
$a = 5; $b = 6; $c = 7;

// Good
$a = 5;
$b = 6;
$c = 7;
Loading history...
39
    public function setMember($member){$this->member = $member; return $this;}
0 ignored issues
show
Coding Style introduced by
It is generally recommended to place each PHP statement on a line by itself.

Let’s take a look at an example:

// Bad
$a = 5; $b = 6; $c = 7;

// Good
$a = 5;
$b = 6;
$c = 7;
Loading history...
40
41
    /**
42
     *
43
     * @return Group and member, using the default settings
44
     */
45
    function CreateGroupAndMember()
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
46
    {
47
        $member = $this->CreateDefaultMember(
48
            $this->email,
49
            $this->firstName,
50
            $this->surname,
51
            $this->password
52
        );
53
        $group = $this->CreateGroup(
54
            $this->code,
55
            $this->name,
56
            $this->parentGroup,
57
            $this->permissionCode,
58
            $this->roleTitle,
59
            $this->permissionArray,
60
            $member
61
        );
62
63
        return $group;
64
    }
65
66
67
    /**
68
     * Create a member
69
     * @param       string $email
70
     * @param       string $firstName   OPTIONAL
71
     * @param       string $surname     OPTIONAL
72
     * @param       string $password    OPTIONAL
73
     *
74
     * @return Member
75
     */
76
    public function CreateDefaultMember(
77
        $email,
78
        $firstName = '',
79
        $surname = '',
80
        $password = ''
81
    )
82
    {
83
        if(! $email) {$email = $this->email;}
84
        if(! $firstName) {$firstName = $this->firstName;}
85
        if(! $surname) {$surname = $this->surname;}
86
        if(! $password) {$password = $this->password;}
87
88
        if(! $email) {
89
            $baseURL = Director::absoluteBaseURL();
90
            $baseURL = str_replace('https://', '', $baseURL);
91
            $baseURL = str_replace('http://', '', $baseURL);
92
            $baseURL = trim( $baseURL, '/' );
93
            $email = 'random.email.'.rand(0,999999).'@'.$baseURL;
94
        }
95
        if(! $firstName) {
96
            $firstName = 'Default';
97
        }
98
        if(! $surname) {
99
            $surname = 'User';
100
        }
101
102
        $filter = array('Email' => $email);
103
        $member = DataObject::get_one(
104
            'Member',
105
            $filter,
106
            $cacheDataObjectGetOne = false
107
        );
108
        if (! $member) {
109
            $member = Member::create($filter);
110
        }
111
112
        $member->FirstName = $firstName;
113
        $member->Surname = $surname;
114
        $member->write();
115
        if ($password) {
116
            $member->changePassword($password);
117
            $member->PasswordExpiry = date('Y-m-d');
118
            $member->write();
119
        }
120
121
        return $member;
122
    }
123
124
    /**
125
     * set up a group with permissions, roles, etc...
126
     * also note that this class implements PermissionProvider.
127
     *
128
     * @param string          $code            code for the group - will always be converted to lowercase
129
     * @param string          $name            title for the group
130
     * @param Group | String  $parentGroup     group object that is the parent of the group. You can also provide a string (name / title of group)
131
     * @param string          $permissionCode  Permission Code for the group (e.g. CMS_DO_THIS_OR_THAT)
132
     * @param string          $roleTitle       Role Title - e.g. Store Manager
133
     * @param array           $permissionArray Permission Array - list of permission codes applied to the group
134
     * @param Member | String $member          Default Member added to the group (e.g. [email protected]). You can also provide an email address
135
     */
136
    public function CreateGroup(
0 ignored issues
show
Documentation introduced by
The return type could not be reliably inferred; please add a @return annotation.

Our type inference engine in quite powerful, but sometimes the code does not provide enough clues to go by. In these cases we request you to add a @return annotation as described here.

Loading history...
137
        $code = '',
138
        $name,
0 ignored issues
show
Coding Style introduced by
Parameters which have default values should be placed at the end.

If you place a parameter with a default value before a parameter with a default value, the default value of the first parameter will never be used as it will always need to be passed anyway:

// $a must always be passed; it's default value is never used.
function someFunction($a = 5, $b) { }
Loading history...
139
        $parentGroup = null,
140
        $permissionCode = '',
141
        $roleTitle = '',
142
        array $permissionArray = [],
143
        $member = null
144
    )
145
    {
146
        if(! $name) {$name = $this->name;}
147
        if(! $code) {$code = $this->code;}
148
        if(! $parentGroup) { $parentGroup = $this->parentGroup;}
149
        if(! $permissionCode) { $permissionCode = $this->permissionCode;}
150
        if(! $permissionArray || count($permissionArray) === 0) { $permissionArray = $this->permissionArray;}
0 ignored issues
show
Bug Best Practice introduced by
The expression $permissionArray of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
151
        if(! $member) { $member = $this->member;}
152
        if(!$name) {
153
            $name = 'New Group '.rand(0,999999);
154
        }
155
        if(!$code) {
156
            $code = $name;
157
        }
158
        $code = str_replace(' ', '_', $code);
159
        $code = preg_replace("/[\W_]+/u", '', $code);
160
        //changing to lower case seems to be very important
161
        //unidentified bug so far
162
        $code = strtolower($code);
163
164
        $filterArrayForGroup = array('Code' => $code);
165
        $groupDataList = Group::get()->filter($filterArrayForGroup);
166
        $groupCount = $groupDataList->count();
167
        $groupStyle = 'updated';
168
        if ($groupCount > 1) {
169
            user_error("There is more than one group with the $name ($code) Code");
170
        }
171
        if ($groupCount == 0) {
172
            $group = Group::create($filterArrayForGroup);
173
            $groupStyle = 'created';
174
        } else {
175
            $group = $groupDataList->First();
176
        }
177
        $group->Locked = 1;
178
        $group->Title = $name;
179
        $parentGroupStyle = 'updated';
0 ignored issues
show
Unused Code introduced by
$parentGroupStyle is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
180
        if ($parentGroup) {
181
            DB::alteration_message('adding parent group');
182
            if (is_string($parentGroup)) {
183
                $parentGroupName = $parentGroup;
184
                $parentGroup = DataObject::get_one(
185
                    'Group',
186
                    array('Title' => $parentGroupName),
187
                    $cacheDataObjectGetOne = false
188
                );
189
                if (!$parentGroup) {
190
                    $parentGroup = Group::create();
191
                    $parentGroupStyle = 'created';
192
                    $parentGroup->Title = $parentGroupName;
193
                    $parentGroup->write();
194
                    DB::alteration_message("$parentGroupStyle $parentGroupName", $parentGroupStyle);
195
                }
196
            }
197
            if ($parentGroup) {
198
                $group->ParentID = $parentGroup->ID;
199
            }
200
        }
201
        $group->write();
202
        DB::alteration_message("$groupStyle $name ($code) group", $groupStyle);
203
        $doubleGroups = Group::get()
204
            ->filter(array('Code' => $code))
205
            ->exclude(array('ID' => $group->ID));
206
        if ($doubleGroups->count()) {
207
            DB::alteration_message($doubleGroups->count().' groups with the same name', 'deleted');
208
            $realMembers = $group->Members();
209
            foreach ($doubleGroups as $doubleGroup) {
210
                $fakeMembers = $doubleGroup->Members();
211
                foreach ($fakeMembers as $fakeMember) {
212
                    DB::alteration_message('adding customers: '.$fakeMember->Email, 'created');
213
                    $realMembers->add($fakeMember);
214
                }
215
                DB::alteration_message('deleting double group ', 'deleted');
216
                $doubleGroup->delete();
217
            }
218
        }
219
        if ($permissionCode) {
220
            $permissionCodeCount = DB::query("SELECT * FROM \"Permission\" WHERE \"GroupID\" = '".$group->ID."' AND \"Code\" LIKE '".$permissionCode."'")->numRecords();
221
            if ($permissionCodeCount == 0) {
222
                DB::alteration_message('granting '.$name." permission code $permissionCode ", 'created');
223
                Permission::grant($group->ID, $permissionCode);
224
            } else {
225
                DB::alteration_message($name." permission code $permissionCode already granted");
226
            }
227
        }
228
        //we unset it here to avoid confusion with the
229
        //other codes we use later on
230
        $permissionArray[] = $permissionCode;
231
        unset($permissionCode);
232
        if ($roleTitle) {
233
            $permissionRoleCount = PermissionRole::get()
234
                ->Filter(array('Title' => $roleTitle))
235
                ->Count();
236
            if ($permissionRoleCount > 1) {
237
                db::alteration_message("There is more than one Permission Role with title $roleTitle ($permissionRoleCount)", 'deleted');
238
                $permissionRolesFirst = DataObject::get_one(
239
                    'PermissionRole',
240
                    array('Title' => $roleTitle),
241
                    $cacheDataObjectGetOne = false
242
                );
243
                $permissionRolesToDelete = PermissionRole::get()
244
                    ->Filter(array('Title' => $roleTitle))
245
                    ->Exclude(array('ID' => $permissionRolesFirst->ID));
246
                foreach ($permissionRolesToDelete as $permissionRoleToDelete) {
247
                    db::alteration_message("DELETING double permission role $roleTitle", 'deleted');
248
                    $permissionRoleToDelete->delete();
249
                }
250
            }
251
            elseif ($permissionRoleCount == 1) {
252
                //do nothing
253
                DB::alteration_message("$roleTitle role in place");
254
            } else {
255
                DB::alteration_message("adding $roleTitle role", 'created');
256
                $permissionRole = PermissionRole::create();
257
                $permissionRole->Title = $roleTitle;
258
                $permissionRole->OnlyAdminCanApply = true;
259
                $permissionRole->write();
260
            }
261
            $permissionRole = DataObject::get_one(
262
                'PermissionRole',
263
                array('Title' => $roleTitle),
264
                $cacheDataObjectGetOne = false
265
            );
266
            if ($permissionRole) {
267
                if (is_array($permissionArray) && count($permissionArray)) {
268
                    DB::alteration_message('working with '.implode(', ', $permissionArray));
269
                    foreach ($permissionArray as $permissionRoleCode) {
270
                        $permissionRoleCodeObject = DataObject::get_one(
271
                            'PermissionRoleCode',
272
                            array('Code' => $permissionRoleCode, 'RoleID' => $permissionRole->ID),
273
                            $cacheDataObjectGetOne = false
274
                        );
275
                        $permissionRoleCodeObjectCount = PermissionRoleCode::get()
276
                            ->Filter(array('Code' => $permissionRoleCode, 'RoleID' => $permissionRole->ID))
277
                            ->Count();
278
                        if ($permissionRoleCodeObjectCount > 1) {
279
                            $permissionRoleCodeObjectsToDelete = PermissionRoleCode::get()
280
                                ->Filter(array('Code' => $permissionRoleCode, 'RoleID' => $permissionRole->ID))
281
                                ->Exclude(array('ID' => $permissionRoleCodeObject->ID));
282
                            foreach ($permissionRoleCodeObjectsToDelete as $permissionRoleCodeObjectToDelete) {
283
                                db::alteration_message("DELETING double permission code $permissionRoleCode for ".$permissionRole->Title, 'deleted');
284
                                $permissionRoleCodeObjectToDelete->delete();
285
                            }
286
                            db::alteration_message('There is more than one Permission Role Code in '.$permissionRole->Title." with Code = $permissionRoleCode ($permissionRoleCodeObjectCount)", 'deleted');
287
                        }
288
                        elseif ($permissionRoleCodeObjectCount == 1) {
0 ignored issues
show
Unused Code introduced by
This elseif statement is empty, and could be removed.

This check looks for the bodies of elseif statements that have no statements or where all statements have been commented out. This may be the result of changes for debugging or the code may simply be obsolete.

These elseif bodies can be removed. If you have an empty elseif but statements in the else branch, consider inverting the condition.

Loading history...
289
                            //do nothing
290
                        } else {
291
                            $permissionRoleCodeObject = PermissionRoleCode::create();
292
                            $permissionRoleCodeObject->Code = $permissionRoleCode;
293
                            $permissionRoleCodeObject->RoleID = $permissionRole->ID;
294
                        }
295
                        DB::alteration_message('adding '.$permissionRoleCodeObject->Code.' to '.$permissionRole->Title);
296
                        $permissionRoleCodeObject->write();
297
                    }
298
                }
299
                if ($group && $permissionRole) {
300
                    if (DB::query('SELECT COUNT(*) FROM Group_Roles WHERE GroupID = '.$group->ID.' AND PermissionRoleID = '.$permissionRole->ID)->value() == 0) {
301
                        db::alteration_message('ADDING '.$permissionRole->Title.' permission role  to '.$group->Title.' group', 'created');
302
                        $existingGroups = $permissionRole->Groups();
303
                        $existingGroups->add($group);
304
                    } else {
305
                        db::alteration_message('CHECKED '.$permissionRole->Title.' permission role  to '.$group->Title.' group');
306
                    }
307
                } else {
308
                    db::alteration_message('ERROR: missing group or permissionRole', 'deleted');
309
                }
310
            }
311
        }
312
        if ($member) {
313
            if (is_string($member)) {
314
                $email = $member;
315
                $member = $this->CreateDefaultMember($email, $code, $name);
316
            }
317
            if ($member) {
318
                DB::alteration_message(' adding member '.$member->Email.' to group '.$group->Title, 'created');
319
                $member->Groups()->add($group);
320
            }
321
        } else {
322
            DB::alteration_message('No user provided.');
323
        }
324
325
        return $group;
326
    }
327
}
328