Completed
Push — master ( 1caf4d...448bfe )
by Patrick
03:00
created

AuthProvider   C

Complexity

Total Complexity 72

Size/Duplication

Total Lines 534
Duplicated Lines 27.9 %

Coupling/Cohesion

Components 1
Dependencies 3

Importance

Changes 11
Bugs 2 Features 1
Metric Value
dl 149
loc 534
rs 5.5667
c 11
b 2
f 1
wmc 72
lcom 1
cbo 3

24 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 14 14 3
A getAuthenticator() 12 12 3
A getUserByLogin() 0 14 3
A login() 0 16 3
A isLoggedIn() 0 5 1
A getUser() 0 5 1
A mergeResult() 0 13 3
A callOnEach() 18 18 4
A addFromEach() 18 18 4
A getGroupByName() 0 9 2
A getUsersByFilter() 9 9 2
A getPendingUsersByFilter() 9 9 2
A getGroupsByFilter() 9 9 2
A getActiveUserCount() 0 9 2
A getPendingUserCount() 0 9 2
A getGroupCount() 0 9 2
A getSupplementaryLinks() 6 12 3
A impersonateUser() 0 8 2
B getTempUserByHash() 0 20 5
B createPendingUser() 0 20 5
B activatePendingUser() 21 21 5
B getUserByResetHash() 24 24 6
A deletePendingUsersByFilter() 0 14 3
A getSuplementalProviderByHost() 9 14 4

How to fix   Duplicated Code    Complexity   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

Complex Class

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

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

1
<?php
2
/**
3
 * AuthProvider class
4
 *
5
 * This file describes the AuthProvider Singleton
6
 *
7
 * PHP version 5 and 7
8
 *
9
 * @author Patrick Boyd / [email protected]
10
 * @copyright Copyright (c) 2015, Austin Artistic Reconstruction
11
 * @license http://www.apache.org/licenses/ Apache 2.0 License
12
 */
13
14
/**
15
 * Allow other classes to be loaded as needed
16
 */
17
require_once('Autoload.php');
18
/**
19
 * Require the FlipsideSettings file
20
 */
21
require_once '/var/www/secure_settings/class.FlipsideSettings.php';
22
23
/**
24
 * A Singleton class to abstract access to the authentication providers.
25
 *
26
 * This class is the primary method to access user data, login, and other authenication information.
27
 */
28
class AuthProvider extends Singleton
29
{
30
    /** The authentication methods loaded by the provider */
31
    protected $methods;
32
33
    /**
34
     * Load the authentrication providers specified in the FlipsideSettings::$authProviders array
35
     */
36 View Code Duplication
    protected function __construct()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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...
37
    {
38
        $this->methods = array();
39
        if(isset(FlipsideSettings::$authProviders))
40
        {
41
            $keys = array_keys(FlipsideSettings::$authProviders);
42
            $count = count($keys);
43
            for($i = 0; $i < $count; $i++)
44
            {
45
                $class = $keys[$i];
46
                array_push($this->methods, new $class(FlipsideSettings::$authProviders[$keys[$i]]));
47
            }
48
        }
49
    }
50
51
    /**
52
     * Get the Authenticator class instance by name
53
     *
54
     * @param string $methodName The class name of the Authenticator to get the instance for
55
     *
56
     * @return Auth\Authenticator|false The specified Authenticator class instance or false if it is not loaded
57
     */
58 View Code Duplication
    public function getAuthenticator($methodName)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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...
59
    {
60
        $count = count($this->methods);
61
        for($i = 0; $i < $count; $i++)
62
        {
63
            if(strcasecmp(get_class($this->methods[$i]), $methodName) === 0)
64
            {
65
                return $this->methods[$i];
66
            }
67
        }
68
        return false;
69
    }
70
71
    /**
72
     * Get the Auth\User class instance for the specified login
73
     *
74
     * Unlike the AuthProvider::login() function. This function will not impact the SESSION
75
     *
76
     * @param string $username The username of the User
77
     * @param string $password The password of the User
78
     *
79
     * @return Auth\User|false The User with the specified credentials or false if the credentials are not valid
80
     */
81
    public function getUserByLogin($username, $password)
82
    {
83
        $res = false;
84
        $count = count($this->methods);
85
        for($i = 0; $i < $count; $i++)
86
        {
87
            $res = $this->methods[$i]->login($username, $password);
88
            if($res !== false)
89
            {
90
                return $this->methods[$i]->getUser($res);
91
            }
92
        }
93
        return $res;
94
    }
95
96
    /**
97
     * Use the provided credetials to log the user on
98
     *
99
     * @param string $username The username of the User
100
     * @param string $password The password of the User
101
     *
102
     * @return true|false true if the login was successful, false otherwise
103
     */
104
    public function login($username, $password)
105
    {
106
        $res = false;
107
        $count = count($this->methods);
108
        for($i = 0; $i < $count; $i++)
109
        {
110
            $res = $this->methods[$i]->login($username, $password);
111
            if($res !== false)
112
            {
113
                FlipSession::setVar('AuthMethod', get_class($this->methods[$i]));
114
                FlipSession::setVar('AuthData', $res);
115
                break;
116
            }
117
        }
118
        return $res;
119
    }
120
121
    /**
122
     * Determine if the user is still logged on from the session data
123
     *
124
     * @param stdClass $data The AuthData from the session
125
     * @param string $methodName The AuthMethod from the session
126
     *
127
     * @return true|false true if user is logged on, false otherwise
128
     */
129
    public function isLoggedIn($data, $methodName)
130
    {
131
        $auth = $this->getAuthenticator($methodName);
132
        return $auth->isLoggedIn($data);
133
    }
134
135
    /**
136
     * Obtain the currently logged in user from the session data
137
     *
138
     * @param stdClass $data The AuthData from the session
139
     * @param string $methodName The AuthMethod from the session
140
     *
141
     * @return Auth\User|false The User instance if user is logged on, false otherwise
142
     */
143
    public function getUser($data, $methodName)
144
    {
145
        $auth = $this->getAuthenticator($methodName);
146
        return $auth->getUser($data);
147
    }
148
149
    /**
150
     * Merge or set the returnValue as appropriate
151
     *
152
     * @param false|Auth\Group|Auth\User $returnValue The value to merge to
153
     * @param Auth\Group|Auth\User $res The value to merge from
154
     *
155
     * @return Auth\Group|false The merged returnValue
156
     */
157
    private function mergeResult(&$returnValue, $res)
158
    {
159
        if($res === false)
160
        {
161
            return;
162
        }
163
        if($returnValue === false)
164
        {
165
            $returnValue = $res;
166
            return;
167
        }
168
        $returnValue->merge($res);
169
    }
170
171
    /**
172
     * Calls the indicated function on each Authenticator and merges the result
173
     *
174
     * @param string $functionName The function to call
175
     * @param array $args The arguments for the function
176
     * @param string $checkField A field to check if it is set a certain way before calling the function
177
     * @param mixed $checkValue The value that field should be set to to not call the function
178
     *
179
     * @return Auth\Group|Auth\User|false The merged returnValue
180
     */
181 View Code Duplication
    private function callOnEach($functionName, $args, $checkField = false, $checkValue = false)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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...
182
    {
183
        $ret = false;
184
        $count = count($this->methods);
185
        for($i = 0; $i < $count; $i++)
186
        {
187
            if($checkField)
0 ignored issues
show
Bug Best Practice introduced by
The expression $checkField of type false|string is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== false instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
188
            {
189
                if($this->methods[$i]->{$checkField} === $checkValue)
190
                {
191
                    continue;
192
                }
193
            }
194
            $res = call_user_func_array(array($this->methods[$i], $functionName), $args);
195
            $this->mergeResult($ret, $res);
196
        }
197
        return $ret;
198
    }
199
200
    /**
201
     * Calls the indicated function on each Authenticator and add the result
202
     *
203
     * @param string $functionName The function to call
204
     * @param string $checkField A field to check if it is set a certain way before calling the function
205
     * @param mixed $checkValue The value that field should be set to to not call the function
206
     *
207
     * @return integer The added returnValue
208
     */
209 View Code Duplication
    private function addFromEach($functionName, $checkField = false, $checkValue = false)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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...
210
    {
211
        $retCount = 0;
212
        $count = count($this->methods);
213
        for($i = 0; $i < $count; $i++)
214
        {
215
            if($checkField)
0 ignored issues
show
Bug Best Practice introduced by
The expression $checkField of type false|string is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== false instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
216
            {
217
                if($this->methods[$i]->{$checkField} === $checkValue)
218
                {
219
                    continue;
220
                }
221
            }
222
            $res = call_user_func(array($this->methods[$i], $functionName));
223
            $retCount += $res;
224
        }
225
        return $retCount;
226
    }
227
228
    /**
229
     * Get an Auth\Group by its name
230
     *
231
     * @param string $name The name of the group
232
     * @param string $methodName The AuthMethod if information is desired only from a particular Auth\Authenticator
233
     *
234
     * @return Auth\Group|false The Group instance if a group with that name exists, false otherwise
235
     */
236
    public function getGroupByName($name, $methodName = false)
237
    {
238
        if($methodName === false)
239
        {
240
            return $this->callOnEach('getGroupByName', array($name));
241
        }
242
        $auth = $this->getAuthenticator($methodName);
243
        return $auth->getGroupByName($name);
244
    }
245
246
    /**
247
     * Get an array of Auth\User from a filtered set
248
     *
249
     * @param Data\Filter|false $filter The filter conditions or false to retreive all
250
     * @param array|false $methodName The user fields to obtain or false to obtain all
251
     * @param integer|false $top The number of users to obtain or false to obtain all
252
     * @param integer|false $skip The number of users to skip or false to skip none
253
     * @param array|false $orderby The field to sort by and the method to sort or false to not sort
254
     * @param string|false $methodName The AuthMethod if information is desired only from a particular Auth\Authenticator
255
     *
256
     * @return array|false An array of Auth\User objects or false if no users were found
257
     */
258 View Code Duplication
    public function getUsersByFilter($filter, $select=false, $top=false, $skip=false, $orderby=false, $methodName = false)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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...
259
    {
260
        if($methodName === false)
261
        {
262
            return $this->callOnEach('getUsersByFilter', array($filter, $select, $top, $skip, $orderby), 'current');
263
        }
264
        $auth = $this->getAuthenticator($methodName);
0 ignored issues
show
Documentation introduced by
$methodName is of type array, but the function expects a string.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
265
        return $auth->getUsersByFilter($filter, $select, $top, $skip, $orderby);
266
    }
267
268
    /**
269
     * Get an array of Auth\PendingUser from a filtered set
270
     *
271
     * @param Data\Filter|false $filter The filter conditions or false to retreive all
272
     * @param array|false $methodName The user fields to obtain or false to obtain all
273
     * @param integer|false $top The number of users to obtain or false to obtain all
274
     * @param integer|false $skip The number of users to skip or false to skip none
275
     * @param array|false $orderby The field to sort by and the method to sort or false to not sort
276
     * @param string|false $methodName The AuthMethod if information is desired only from a particular Auth\Authenticator
277
     *
278
     * @return array|false An array of Auth\PendingUser objects or false if no pending users were found
279
     */
280 View Code Duplication
    public function getPendingUsersByFilter($filter, $select=false, $top=false, $skip=false, $orderby=false, $methodName = false)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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...
281
    {
282
        if($methodName === false)
283
        {
284
            return $this->callOnEach('getPendingUsersByFilter', array($filter, $select, $top, $skip, $orderby), 'pending');
285
        }
286
        $auth = $this->getAuthenticator($methodName);
0 ignored issues
show
Documentation introduced by
$methodName is of type array, but the function expects a string.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
287
        return $auth->getPendingUsersByFilter($filter, $select, $top, $skip, $orderby);
288
    }
289
290
    /**
291
     * Get an array of Auth\Group from a filtered set
292
     *
293
     * @param Data\Filter|false $filter The filter conditions or false to retreive all
294
     * @param array|false $methodName The group fields to obtain or false to obtain all
295
     * @param integer|false $top The number of groups to obtain or false to obtain all
296
     * @param integer|false $skip The number of groups to skip or false to skip none
297
     * @param array|false $orderby The field to sort by and the method to sort or false to not sort
298
     * @param string|false $methodName The AuthMethod if information is desired only from a particular Auth\Authenticator
299
     *
300
     * @return array|false An array of Auth\Group objects or false if no pending users were found
301
     */
302 View Code Duplication
    public function getGroupsByFilter($filter, $select=false, $top=false, $skip=false, $orderby=false, $methodName = false)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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...
303
    {
304
        if($methodName === false)
305
        {
306
            return $this->callOnEach('getGroupsByFilter', array($filter, $select, $top, $skip, $orderby), 'current');
307
        }
308
        $auth = $this->getAuthenticator($methodName);
0 ignored issues
show
Documentation introduced by
$methodName is of type array, but the function expects a string.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
309
        return $auth->getGroupsByFilter($filter, $select, $top, $skip, $orderby);
310
    }
311
312
    /**
313
     * Get the number of currently active users on the system
314
     *
315
     * @param string|false $methodName The AuthMethod if information is desired only from a particular Auth\Authenticator
316
     *
317
     * @return integer The number of currently active users on the system
318
     */
319
    public function getActiveUserCount($methodName = false)
320
    {
321
        if($methodName === false)
322
        {
323
            return $this->addFromEach('getActiveUserCount', 'current');
324
        }
325
        $auth = $this->getAuthenticator($methodName);
326
        return $auth->getActiveUserCount();
327
    }
328
329
    /**
330
     * Get the number of currently pending users on the system
331
     *
332
     * @param string|false $methodName The AuthMethod if information is desired only from a particular Auth\Authenticator
333
     *
334
     * @return integer The number of currently pending users on the system
335
     */
336
    public function getPendingUserCount($methodName = false)
337
    {
338
        if($methodName === false)
339
        {
340
            return $this->addFromEach('getPendingUserCount', 'pending');
341
        }
342
        $auth = $this->getAuthenticator($methodName);
343
        return $auth->getPendingUserCount();
344
    }
345
346
    /**
347
     * Get the number of current groups on the system
348
     *
349
     * @param string|false $methodName The AuthMethod if information is desired only from a particular Auth\Authenticator
350
     *
351
     * @return integer The number of current groups on the system
352
     */
353
    public function getGroupCount($methodName = false)
354
    {
355
        if($methodName === false)
356
        {
357
            return $this->addFromEach('getGroupCount', 'current');
358
        }
359
        $auth = $this->getAuthenticator($methodName);
360
        return $auth->getGroupCount();
361
    }
362
363
    /**
364
     * Get the login links for all supplementary Authenitcation mechanisms
365
     *
366
     * This will return an array of links to any supplementary authentication mechanims. For example, Goodle is 
367
     * a supplementary authentication mechanism.
368
     *
369
     * @return array An array of suppmentary authentication mechanism links
370
     */
371
    public function getSupplementaryLinks()
372
    {
373
        $ret = array();
374
        $count = count($this->methods);
375 View Code Duplication
        for($i = 0; $i < $count; $i++)
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...
376
        {
377
            if($this->methods[$i]->supplement === false) continue;
378
379
            array_push($ret, $this->methods[$i]->getSupplementLink());
380
        }
381
        return $ret;
382
    }
383
384
    /**
385
     * Impersonate the user specified
386
     *
387
     * This will replace the user in the session with the specified user. In order
388
     * to undo this operation a user must logout.
389
     *
390
     * @param array|Auth\User $userArray Data representing the user
391
     */
392
    public function impersonateUser($userArray)
393
    {
394
        if(!is_object($userArray))
395
        {
396
            $user = new $userArray['class']($userArray);
397
        }
398
        \FlipSession::setUser($user);
0 ignored issues
show
Bug introduced by
The variable $user does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
399
    }
400
401
    /**
402
     * Get the pending user reresented by the supplied hash
403
     *
404
     * @param string $hash The hash value representing the Penging User
405
     * @param string|false $methodName The AuthMethod if information is desired only from a particular Auth\Authenticator
406
     *
407
     * @return Auth\PendingUser|false The Auth\PendingUser instance or false if no user is matched by the provided hash
408
     */
409
    public function getTempUserByHash($hash, $methodName = false)
410
    {
411
        if($methodName === false)
412
        {
413
            $count = count($this->methods);
414
            for($i = 0; $i < $count; $i++)
415
            {
416
                if($this->methods[$i]->pending === false) continue;
417
418
                $ret = $this->methods[$i]->getTempUserByHash($hash);
419
                if($ret !== false)
420
                {
421
                    return $ret;
422
                }
423
            }
424
            return false;
425
        }
426
        $auth = $this->getAuthenticator($methodName);
427
        return $auth->getTempUserByHash($hash);
428
    }
429
430
    /**
431
     * Create a pending user
432
     *
433
     * @param array $user An array of information about the user to create
434
     * @param string|false $methodName The AuthMethod if information is desired only from a particular Auth\Authenticator
435
     *
436
     * @return true|false true if the user was successfully created. Otherwise false.
437
     */
438
    public function createPendingUser($user, $methodName = false)
439
    {
440
        if($methodName === false)
441
        {
442
            $count = count($this->methods);
443
            for($i = 0; $i < $count; $i++)
444
            {
445
                if($this->methods[$i]->pending === false) continue;
446
447
                $ret = $this->methods[$i]->createPendingUser($user);
448
                if($ret !== false)
449
                {
450
                    return true;
0 ignored issues
show
Bug Best Practice introduced by
The return type of return true; (boolean) is incompatible with the return type documented by AuthProvider::createPendingUser of type true|false.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
451
                }
452
            }
453
            return false;
454
        }
455
        $auth = $this->getAuthenticator($methodName);
456
        return $auth->createPendingUser($user);
0 ignored issues
show
Documentation introduced by
$user is of type array, but the function expects a object<Auth\Auth\PendingUser>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
457
    }
458
459
    /**
460
     * Convert a Auth\PendingUser into an Auth\User
461
     *
462
     * This will allow a previously pending user the ability to log on in the future as an active user. It will also
463
     * have the side effect of logging the user on now.
464
     *
465
     * @param Auth\PendingUser $user The user to turn into a current user
466
     * @param string|false $methodName The AuthMethod if information is desired only from a particular Auth\Authenticator
467
     *
468
     * @return true|false true if the user was successfully created. Otherwise false.
469
     */
470 View Code Duplication
    public function activatePendingUser($user, $methodName = false)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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...
471
    {
472
        if($methodName === false)
473
        {
474
            $count = count($this->methods);
475
            for($i = 0; $i < $count; $i++)
476
            {
477
                if($this->methods[$i]->current === false) continue;
478
479
                $ret = $this->methods[$i]->activatePendingUser($user);
480
                if($ret !== false)
481
                {
482
                    $this->impersonateUser($ret);
483
                    return true;
0 ignored issues
show
Bug Best Practice introduced by
The return type of return true; (boolean) is incompatible with the return type documented by AuthProvider::activatePendingUser of type true|false.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
484
                }
485
            }
486
            return false;
487
        }
488
        $auth = $this->getAuthenticator($methodName);
489
        return $auth->activatePendingUser($user);
0 ignored issues
show
Documentation introduced by
$user is of type object<Auth\PendingUser>, but the function expects a object<Auth\Auth\PendingUser>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
490
    }
491
492
    /**
493
     * Get a current user by a password reset hash
494
     *
495
     * @param string $hash The current password reset hash for the user
496
     * @param string|false $methodName The AuthMethod if information is desired only from a particular Auth\Authenticator
497
     *
498
     * @return Auth\User|false The user if the password reset hash is valid. Otherwise false.
499
     */
500 View Code Duplication
    public function getUserByResetHash($hash, $methodName = false)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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...
501
    {
502
        if($methodName === false)
503
        {
504
            $count = count($this->methods);
505
            for($i = 0; $i < $count; $i++)
506
            {
507
                if($this->methods[$i]->current === false) continue;
508
509
                $ret = $this->methods[$i]->getUserByResetHash($hash);
510
                if($ret !== false)
511
                {
512
                    return $ret;
513
                }
514
            }
515
            return false;
516
        }
517
        $auth = $this->getAuthenticator($methodName);
518
        if($auth === false)
519
        {
520
            return $this->getUserByResetHash($hash, false);
521
        }
522
        return $auth->getUserByResetHash($hash);
0 ignored issues
show
Bug Best Practice introduced by
The return type of return $auth->getUserByResetHash($hash); (boolean) is incompatible with the return type documented by AuthProvider::getUserByResetHash of type Auth\User|false.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
523
    }
524
525
    /**
526
     * Get the Auth\Authenticator by host name
527
     *
528
     * @param string $host The host name used by the supplemental authentication mechanism
529
     *
530
     * @return Auth\Authenticator|false The Authenticator if the host is supported by a loaded Authenticator. Otherwise false.
531
     */
532
    public function getSuplementalProviderByHost($host)
533
    {
534
        $count = count($this->methods);
535 View Code Duplication
        for($i = 0; $i < $count; $i++)
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...
536
        {
537
            if($this->methods[$i]->supplement === false) continue;
538
539
            if($this->methods[$i]->getHostName() === $host)
540
            {
541
                return $this->methods[$i];
542
            }
543
        }
544
        return false;
545
    }
546
547
    public function deletePendingUsersByFilter($filter, $methodName=false)
548
    {
549
        $users = $this->getPendingUsersByFilter($filter, false, false, false, false, $methodName);
0 ignored issues
show
Documentation introduced by
$methodName is of type boolean, but the function expects a false|array.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
550
        if($users === false)
551
        {
552
            return false;
553
        }
554
        $count = count($users);
555
        for($i = 0; $i < $count; $i++)
556
        {
557
            $users[$i]->delete();
558
        }
559
        return true;
560
    }
561
}
562
/* vim: set tabstop=4 shiftwidth=4 expandtab: */
563
?>
0 ignored issues
show
Best Practice introduced by
It is not recommended to use PHP's closing tag ?> in files other than templates.

Using a closing tag in PHP files that only contain PHP code is not recommended as you might accidentally add whitespace after the closing tag which would then be output by PHP. This can cause severe problems, for example headers cannot be sent anymore.

A simple precaution is to leave off the closing tag as it is not required, and it also has no negative effects whatsoever.

Loading history...
564