Completed
Push — master ( 8e26dc...2fb1c1 )
by Vitaly
03:49
created

Collection::handler()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 7
Code Lines 3

Duplication

Lines 0
Ratio 0 %
Metric Value
dl 0
loc 7
rs 9.4285
cc 1
eloc 3
nc 1
nop 2
1
<?php
2
/**
3
 * Created by PhpStorm.
4
 * User: egorov
5
 * Date: 26.12.2014
6
 * Time: 16:22
7
 */
8
namespace samsoncms\api;
9
10
use samsonframework\orm\Condition;
11
use samsonframework\collection\Paged;
12
use samsonframework\orm\Relation;
13
use samsonframework\pager\PagerInterface;
14
use samsonframework\core\RenderInterface;
15
use samsonframework\orm\QueryInterface;
16
17
/**
18
 * Collection query builder for filtering
19
 * @package samsonos\cms\collection
20
 * @author Egorov Vitaly <[email protected]>
21
 * @deprecated Use generated Entities and EntityQueries classes.
22
 */
23
class Collection extends Paged
24
{
25
    /** @var string Entity manager instance */
26
    protected $managerEntity = '\samsoncms\api\query\Generic';
27
28
    /** @var array Collection for current filtered material identifiers */
29
    protected $materialIDs = array();
30
31
    /** @var array Collection of navigation filters */
32
    protected $navigation = array();
33
34
    /** @var array Collection of field filters */
35
    protected $field = array();
36
37
    /** @var array Collection of query handlers */
38
    protected $idHandlers = array();
39
40
    /** @var array External material handler and params array */
41
    protected $entityHandlers = array();
42
43
    /** @var array Base material entity handler callbacks array */
44
    protected $baseEntityHandlers = array();
45
46
    /** @var string Collection entities class name */
47
    protected $entityName = 'samson\cms\CMSMaterial';
48
49
    /**
50
     * Generic collection constructor
51
     * @param RenderInterface $renderer View render object
52
     * @param QueryInterface $query Query object
53
     */
54
    public function __construct(RenderInterface $renderer, QueryInterface $query, PagerInterface $pager)
55
    {
56
        // Call parent initialization
57
        parent::__construct($renderer, $query->className('material'), $pager);
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface samsonframework\orm\QueryInterface as the method className() does only exist in the following implementations of said interface: samson\activerecord\dbQuery.

Let’s take a look at an example:

interface User
{
    /** @return string */
    public function getPassword();
}

class MyUser implements 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 implementation 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 interface:

    interface User
    {
        /** @return string */
        public function getPassword();
    
        /** @return string */
        public function getDisplayName();
    }
    
Loading history...
58
    }
59
60
    /**
61
     * Render products collection block
62
     * @param string $prefix Prefix for view variables
63
     * @param array $restricted Collection of ignored keys
64
     * @return array Collection key => value
65
     */
66
    public function toView($prefix = null, array $restricted = array())
67
    {
68
        // Render pager and collection
69
        return array(
70
            $prefix.'html' => $this->render(),
71
            $prefix.'pager' => $this->pager->total > 1 ? $this->pager->toHTML() : ''
0 ignored issues
show
Bug introduced by
Accessing total on the interface samsonframework\pager\PagerInterface suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
Bug introduced by
The method toHTML() does not seem to exist on object<samsonframework\pager\PagerInterface>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
72
        );
73
    }
74
75
    /**
76
     * Add external identifier filter handler
77
     * @param callback $handler
78
     * @param array $params
79
     * @return self Chaining
80
     */
81
    public function handler($handler, array $params = array())
82
    {
83
        // Add callback with parameters to array
84
        $this->idHandlers[] = array($handler, $params);
85
86
        return $this;
87
    }
88
89
    /**
90
     * Set external entity handler
91
     * @param callback $handler
92
     * @param array $params
93
     * @return self Chaining
94
     */
95
    public function baseEntityHandler($handler, array $params = array())
96
    {
97
        // Add callback with parameters to array
98
        $this->baseEntityHandlers[] = array($handler, $params);
99
100
        return $this;
101
    }
102
103
    /**
104
     * Set external entity handler
105
     * @param callback $handler
106
     * @param array $params
107
     * @return self Chaining
108
     */
109
    public function entityHandler($handler, array $params = array())
110
    {
111
        // Add callback with parameters to array
112
        $this->entityHandlers[] = array($handler, $params);
113
114
        return $this;
115
    }
116
117
    /**
118
     * Set collection sorter parameters
119
     * @param string|integer $field Field identifier or name
120
     * @param string $destination ASC|DESC
121
     * @return void
122
     */
123
    public function sorter($field, $destination = 'ASC')
124
    {
125
        /**@var \samson\activerecord\field $field */
126
        // TODO: Add ability to sort with entity fields
127
        if (in_array($field, \samson\activerecord\material::$_attributes)) {
128
            $this->sorter = array(
129
                'field' => $field,
130
                'name' => $field,
131
                'destination' => $destination
132
            );
133
        } else if ($this->isFieldObject($field)) {
134
            $this->sorter = array(
135
                'entity' => $field,
136
                'name' => $field->Name,
137
                'field' => in_array($field->Type, array(3, 7, 10)) ? 'numeric_value' : 'value',
138
                'destination' => $destination
139
            );
140
        }
141
    }
142
143
    /**
144
     * Filter collection using navigation entity or collection of them.
145
     * If collection of navigation Url or Ids is passed then this group will be
146
     * applied as single navigation filter to retrieve materials.
147
     *
148
     * @param string|integer|array $navigation Navigation URL or identifier for filtering
149
     * @return self Chaining
150
     */
151
    public function navigation($navigation)
152
    {
153
        // Do not allow empty strings
154
        if (!empty($navigation)) {
155
            // Create id or URL condition
156
            $idOrUrl = new Condition('OR');
157
            $idOrUrl->add('StructureID', $navigation)->add('Url', $navigation);
158
159
            /** @var array $navigationIds  */
160
            $navigationIds = null;
161
            if ($this->query->className('structure')->cond($idOrUrl)->fields('StructureID', $navigationIds)) {
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface samsonframework\orm\QueryInterface as the method className() does only exist in the following implementations of said interface: samson\activerecord\dbQuery.

Let’s take a look at an example:

interface User
{
    /** @return string */
    public function getPassword();
}

class MyUser implements 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 implementation 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 interface:

    interface User
    {
        /** @return string */
        public function getPassword();
    
        /** @return string */
        public function getDisplayName();
    }
    
Loading history...
162
                // Store all retrieved navigation elements as navigation collection filter
163
                $this->navigation[] = $navigationIds;
164
            }
165
        }
166
167
        // Chaining
168
        return $this;
169
    }
170
171
    /**
172
     * Filter collection using additional field entity.
173
     *
174
     * @param string|integer|Field $field Additional field identifier or name
175
     * @param mixed $value Additional field value for filtering
176
     * @param string $relation Additional field relation for filtering
177
     * @return self Chaining
178
     */
179
    public function field($field, $value, $relation = Relation::EQUAL)
180
    {
181
        // Do not allow empty strings
182
        if ($this->isFieldObject($field)) {
183
            // Get field value column
184
            $valueField = in_array($field->Type, array(3, 7, 10)) ? 'numeric_value' : 'value';
185
			$valueField = $field->Type == 6 ? 'key_value' : $valueField;
186
			
187
            /** @var Condition $condition Ranged condition */
188
            $condition = new Condition('AND');
189
190
            // Add min value for ranged condition
191
            $condition->add($valueField, $value, $relation);
192
193
            // Store retrieved field element and its value as field collection filter
194
            $this->field[] = array($field, $condition);
195
        }
196
197
        // Chaining
198
        return $this;
199
    }
200
201
    /**
202
     * Filter collection using additional field entity values and LIKE relation.
203
     * If this method is called more then once, it will use materials, previously filtered by this method.
204
     *
205
     * @param string $search Search string
206
     * @return self Chaining
207
     */
208
    public function search($search)
209
    {
210
        // If input parameter is a string add it to search string collection
211
        if (isset($search{0})) {
212
            $this->search[] = $search;
213
        }
214
215
        // Chaining
216
        return $this;
217
    }
218
219
    /**
220
     * Filter collection of numeric field in range from min to max values
221
     * @param string|integer|Field $field Additional field identifier or name
222
     * @param integer $minValue Min value for range filter
223
     * @param integer $maxValue Max value for range filter
224
     * @return self Chaining
225
     */
226
    public function ranged($field, $minValue, $maxValue)
227
    {
228
        // Check input parameters and try to find field
229
        if (($minValue <= $maxValue) && $this->isFieldObject($field)) {
230
            // TODO: Remove integers from code, handle else
231
            // Only numeric fields are supported
232
            if (in_array($field->Type, array(3, 7, 10))) {
233
                /** @var Condition $condition Ranged condition */
234
                $condition = new Condition('AND');
235
236
                // Add min value for ranged condition
237
                $condition->add('numeric_value', $minValue, Relation::GREATER_EQ);
238
239
                // Add max value for ranged condition
240
                $condition->add('numeric_value', $maxValue, Relation::LOWER_EQ);
241
242
                // Store created condition
243
                $this->field[] = array($field, $condition);
244
            }
245
        }
246
247
        // Chaining
248
        return $this;
249
    }
250
251
    /**
252
     * Try to find additional field record
253
     * @param string|integer $field Additional field identifier or name
254
     * @return bool True if field record has been found
255
     */
256
    protected function isFieldObject(&$field)
257
    {
258
        // Do not allow empty strings
259
        if (!empty($field)) {
260
            // Create id or URL condition
261
            $idOrUrl = new Condition('OR');
262
            $idOrUrl->add('FieldID', $field)->add('Name', $field);
263
264
            // Perform query
265
            return $this->query->className('field')->cond($idOrUrl)->first($field);
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface samsonframework\orm\QueryInterface as the method className() does only exist in the following implementations of said interface: samson\activerecord\dbQuery.

Let’s take a look at an example:

interface User
{
    /** @return string */
    public function getPassword();
}

class MyUser implements 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 implementation 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 interface:

    interface User
    {
        /** @return string */
        public function getPassword();
    
        /** @return string */
        public function getDisplayName();
    }
    
Loading history...
266
        }
267
268
        // Field not found
269
        return false;
270
    }
271
272
    /**
273
     * Try to get all material identifiers filtered by navigation
274
     * if no navigation filtering is set - nothing will happen.
275
     *
276
     * @param array $filteredIds Collection of filtered material identifiers
277
     * @return bool True if ALL navigation filtering succeeded or there was no filtering at all otherwise false
278
     */
279 View Code Duplication
    protected function applyNavigationFilter(& $filteredIds = array())
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...
280
    {
281
        // Iterate all applied navigation filters
282
        foreach ($this->navigation as $navigation) {
283
            // Create navigation-material query
284
            $this->query->className('structurematerial')
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface samsonframework\orm\QueryInterface as the method className() does only exist in the following implementations of said interface: samson\activerecord\dbQuery.

Let’s take a look at an example:

interface User
{
    /** @return string */
    public function getPassword();
}

class MyUser implements 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 implementation 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 interface:

    interface User
    {
        /** @return string */
        public function getPassword();
    
        /** @return string */
        public function getDisplayName();
    }
    
Loading history...
285
286
                ->cond('StructureID', $navigation)
287
                ->cond('Active', 1)
288
                ->group_by('MaterialID')
289
            ;
290
291
            if (isset($filteredIds)) {
292
                $this->query->cond('MaterialID', $filteredIds);
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface samsonframework\orm\QueryInterface as the method cond() does only exist in the following implementations of said interface: samson\activerecord\dbQuery.

Let’s take a look at an example:

interface User
{
    /** @return string */
    public function getPassword();
}

class MyUser implements 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 implementation 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 interface:

    interface User
    {
        /** @return string */
        public function getPassword();
    
        /** @return string */
        public function getDisplayName();
    }
    
Loading history...
293
            }
294
295
            // Perform request to get next portion of filtered material identifiers
296
            if (!$this->query->fields('MaterialID', $filteredIds)) {
0 ignored issues
show
Bug introduced by
It seems like $filteredIds defined by parameter $filteredIds on line 279 can also be of type array; however, samsonframework\orm\QueryInterface::fields() does only seem to accept null|array<integer,objec...k\orm\RecordInterface>>, maybe add an additional type check?

This check looks at variables that have been passed in as parameters and are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
297
                // This filter applying failed
298
                return false;
299
            }
300
        }
301
302
        // We have no navigation collection filters
303
        return true;
304
    }
305
306
    /**
307
     * Try to get all material identifiers filtered by additional field
308
     * if no field filtering is set - nothing will happen.
309
     *
310
     * @param array $filteredIds Collection of filtered material identifiers
311
     * @return bool True if ALL field filtering succeeded or there was no filtering at all otherwise false
312
     */
313 View Code Duplication
    protected function applyFieldFilter(& $filteredIds = array())
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...
314
    {
315
        // Iterate all applied field filters
316
        foreach ($this->field as $field) {
317
            // Create material-field query
318
            $this->query->className('materialfield')
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface samsonframework\orm\QueryInterface as the method className() does only exist in the following implementations of said interface: samson\activerecord\dbQuery.

Let’s take a look at an example:

interface User
{
    /** @return string */
    public function getPassword();
}

class MyUser implements 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 implementation 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 interface:

    interface User
    {
        /** @return string */
        public function getPassword();
    
        /** @return string */
        public function getDisplayName();
    }
    
Loading history...
319
                ->cond('FieldID', $field[0]->id)
320
                ->cond($field[1])
321
                ->group_by('MaterialID')
322
            ;
323
324
            if (isset($filteredIds)) {
325
                $this->query->cond('MaterialID', $filteredIds);
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface samsonframework\orm\QueryInterface as the method cond() does only exist in the following implementations of said interface: samson\activerecord\dbQuery.

Let’s take a look at an example:

interface User
{
    /** @return string */
    public function getPassword();
}

class MyUser implements 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 implementation 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 interface:

    interface User
    {
        /** @return string */
        public function getPassword();
    
        /** @return string */
        public function getDisplayName();
    }
    
Loading history...
326
            }
327
328
            // Perform request to get next portion of filtered material identifiers
329
            if (!$this->query->fields('MaterialID', $filteredIds)) {
0 ignored issues
show
Bug introduced by
It seems like $filteredIds defined by parameter $filteredIds on line 313 can also be of type array; however, samsonframework\orm\QueryInterface::fields() does only seem to accept null|array<integer,objec...k\orm\RecordInterface>>, maybe add an additional type check?

This check looks at variables that have been passed in as parameters and are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
330
                // This filter applying failed
331
                return false;
332
            }
333
        }
334
335
        // We have no field collection filters
336
        return true;
337
    }
338
339
    /**
340
     * Try to find all materials which have fields similar to search strings
341
     *
342
     * @param array $filteredIds Collection of filtered material identifiers
343
     * @return bool True if ALL field filtering succeeded or there was no filtering at all otherwise false
344
     */
345
    protected function applySearchFilter(& $filteredIds = array())
346
    {
347
        /** @var array $fields Variable to store all fields related to set navigation */
348
        $fields = array();
349
        /** @var array $navigationArray Array of set navigation identifiers */
350
        $navigationArray = array();
351
        /** @var array $fieldFilter Array of filtered material identifiers via materialfield table */
352
        $fieldFilter = array();
353
        /** @var array $materialFilter Array of filtered material identifiers via material table */
354
        $materialFilter = array();
0 ignored issues
show
Unused Code introduced by
$materialFilter 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...
355
356
        // If there are at least one search string
357
        if (!empty($this->search)) {
358
            // Create array containing all navigation identifiers
359
            foreach ($this->navigation as $navigation) {
360
                // Navigation hook for searching action
361
                $navigation = is_array($navigation) ? $navigation : array($navigation);
362
                $navigationArray = array_merge($navigationArray, $navigation);
363
            }
364
365
            // Get all related fields
366
            $this->query->className('structurefield')
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface samsonframework\orm\QueryInterface as the method className() does only exist in the following implementations of said interface: samson\activerecord\dbQuery.

Let’s take a look at an example:

interface User
{
    /** @return string */
    public function getPassword();
}

class MyUser implements 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 implementation 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 interface:

    interface User
    {
        /** @return string */
        public function getPassword();
    
        /** @return string */
        public function getDisplayName();
    }
    
Loading history...
367
                ->cond('StructureID', $navigationArray)
368
                ->group_by('FieldID')
369
                ->fields('FieldID', $fields);
370
371
            // Iterate over search strings
372
            foreach ($this->search as $searchString) {
373
                // Try to find search value in materialfield table
374
                $this->query->className('materialfield')
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface samsonframework\orm\QueryInterface as the method className() does only exist in the following implementations of said interface: samson\activerecord\dbQuery.

Let’s take a look at an example:

interface User
{
    /** @return string */
    public function getPassword();
}

class MyUser implements 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 implementation 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 interface:

    interface User
    {
        /** @return string */
        public function getPassword();
    
        /** @return string */
        public function getDisplayName();
    }
    
Loading history...
375
                    ->cond('FieldID', $fields)
376
                    ->cond('MaterialID', $filteredIds)
377
                    ->cond('Value', '%' . $searchString . '%', Relation::LIKE)
378
                    ->cond('Active', 1)
379
                    ->group_by('MaterialID')
380
                    ->fields('MaterialID', $fieldFilter);
381
382
                // TODO: Add generic support for all native fields or their configuration
383
                // Condition to search in material table by Name and URL
384
                $materialCondition = new Condition('OR');
385
                $materialCondition->add('Name', '%' . $searchString . '%', Relation::LIKE)
386
                    ->add('Url', '%' . $searchString . '%', Relation::LIKE);
387
388
389
                // Try to find search value in material table
390
                $this->query->className('material')
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface samsonframework\orm\QueryInterface as the method className() does only exist in the following implementations of said interface: samson\activerecord\dbQuery.

Let’s take a look at an example:

interface User
{
    /** @return string */
    public function getPassword();
}

class MyUser implements 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 implementation 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 interface:

    interface User
    {
        /** @return string */
        public function getPassword();
    
        /** @return string */
        public function getDisplayName();
    }
    
Loading history...
391
                    ->cond($materialCondition)
392
                    ->cond('Active', 1);
393
394
                // If we have not empty collection of filtering identifiers
395
                if (sizeof($filteredIds)) {
396
                    $this->query->cond('MaterialID', $filteredIds);
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface samsonframework\orm\QueryInterface as the method cond() does only exist in the following implementations of said interface: samson\activerecord\dbQuery.

Let’s take a look at an example:

interface User
{
    /** @return string */
    public function getPassword();
}

class MyUser implements 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 implementation 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 interface:

    interface User
    {
        /** @return string */
        public function getPassword();
    
        /** @return string */
        public function getDisplayName();
    }
    
Loading history...
397
                }
398
399
                $materialFilter = $this->query->fields('MaterialID');
400
401
                // If there are no materials with specified conditions
402
                if (empty($materialFilter) && empty($fieldFilter)) {
403
                    // Filter applying failed
404
                    return false;
405
                } else {// Otherwise set filtered material identifiers
406
                    $filteredIds = array_unique(array_merge($materialFilter, $fieldFilter));
407
                }
408
            }
409
        }
410
411
        // We have no search collection filters
412
        return true;
413
    }
414
415
    /**
416
     * Apply all possible material filters
417
     * @param array $filteredIds Collection of material identifiers
418
     * @return bool True if ALL filtering succeeded or there was no filtering at all otherwise false
419
     */
420
    protected function applyFilter(& $filteredIds = array())
421
    {
422
        return $this->applyNavigationFilter($filteredIds)
423
            && $this->applyFieldFilter($filteredIds)
424
            && $this->applySearchFilter($filteredIds);
425
    }
426
427
    /**
428
     * Perform material identifiers collection sorting
429
     * @param array $materialIDs Variable to return sorted collection
430
     */
431
    protected function applyFieldSorter(&$materialIDs = array())
432
    {
433
        // Check if sorter is configured
434
        if (sizeof($this->sorter)) {
435
            // If we need to sort by entity additional field(column)
436
            if (!in_array($this->sorter['field'], \samson\activerecord\material::$_attributes)) {
437
                // Sort material identifiers by its additional fields
438
                $this->query->className('materialfield')
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface samsonframework\orm\QueryInterface as the method className() does only exist in the following implementations of said interface: samson\activerecord\dbQuery.

Let’s take a look at an example:

interface User
{
    /** @return string */
    public function getPassword();
}

class MyUser implements 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 implementation 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 interface:

    interface User
    {
        /** @return string */
        public function getPassword();
    
        /** @return string */
        public function getDisplayName();
    }
    
Loading history...
439
                    ->cond('FieldID', $this->sorter['entity']->id)
440
                    ->order_by($this->sorter['field'], $this->sorter['destination'])
441
                    ->cond('MaterialID', $materialIDs)
442
                    ->fields('MaterialID', $materialIDs);
443
            }
444
        }
445
    }
446
447
    /**
448
     * Call handlers stack
449
     * @param array $handlers Collection of callbacks with their parameters
450
     * @param array $params External parameters to pass to callback at first
451
     * @return bool True if all handlers succeeded
452
     */
453
    protected function callHandlers(& $handlers = array(), $params = array())
454
    {
455
        // Call external handlers
456
        foreach ($handlers as $handler) {
457
            // Call external handlers chain
458
            if (call_user_func_array(
459
                $handler[0],
460
                array_merge($params, $handler[1]) // Merge params and handler params
461
            ) === false) {
462
                // Stop - if one of external handlers has failed
463
                return false;
464
            }
465
        }
466
467
        return true;
468
    }
469
470
    /**
471
     * Perform filtering on base material entity
472
     * @param array $materialIDs Variable to return sorted collection
473
     */
474
    protected function applyBaseEntityFilter(& $materialIDs = array())
475
    {
476
        // TODO: Change this to new OOP approach
477
        $class = $this->entityName;
478
479
        // Configure query to base entity
480
        $this->query->className('samson\activerecord\material');
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface samsonframework\orm\QueryInterface as the method className() does only exist in the following implementations of said interface: samson\activerecord\dbQuery.

Let’s take a look at an example:

interface User
{
    /** @return string */
    public function getPassword();
}

class MyUser implements 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 implementation 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 interface:

    interface User
    {
        /** @return string */
        public function getPassword();
    
        /** @return string */
        public function getDisplayName();
    }
    
Loading history...
481
482
        // Call base material entity handlers to prepare query
483
        $this->callHandlers($this->baseEntityHandlers, array(&$this->query));
484
485
        // Check if sorter is configured
486
        if (sizeof($this->sorter)) {
487
            // If we need to sort by entity own field(column)
488
            if (in_array($this->sorter['field'], $class::$_attributes)) {
489
                // Add material entity sorter
490
                $this->query->order_by($this->sorter['field'], $this->sorter['destination']);
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface samsonframework\orm\QueryInterface as the method order_by() does only exist in the following implementations of said interface: samson\activerecord\dbQuery.

Let’s take a look at an example:

interface User
{
    /** @return string */
    public function getPassword();
}

class MyUser implements 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 implementation 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 interface:

    interface User
    {
        /** @return string */
        public function getPassword();
    
        /** @return string */
        public function getDisplayName();
    }
    
Loading history...
491
            }
492
        }
493
494
        // Perform main entity query
495
        $this->materialIDs = $this->query
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface samsonframework\orm\QueryInterface as the method cond() does only exist in the following implementations of said interface: samson\activerecord\dbQuery.

Let’s take a look at an example:

interface User
{
    /** @return string */
    public function getPassword();
}

class MyUser implements 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 implementation 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 interface:

    interface User
    {
        /** @return string */
        public function getPassword();
    
        /** @return string */
        public function getDisplayName();
    }
    
Loading history...
496
            ->cond('Active', 1) // Remove deleted entities
497
            ->cond('system', 0) // Remove system entities
498
            ->cond($class::$_primary, $materialIDs) // Filter to current set
499
            ->fields($class::$_primary)
500
        ;
501
    }
502
503
    /**
504
     * Perform collection database retrieval using set filters
505
     *
506
     * @return self Chaining
507
     */
508
    public function fill()
509
    {
510
        // Clear current materials identifiers list
511
        $this->materialIDs = null;
0 ignored issues
show
Documentation Bug introduced by
It seems like null of type null is incompatible with the declared type array of property $materialIDs.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
512
513
        // TODO: Change this to new OOP approach
514
        $class = $this->entityName;
515
516
        // If no filters is set
517
        if (!sizeof($this->search) && !sizeof($this->navigation) && !sizeof($this->field)) {
518
            // Get all entity records identifiers
519
            $this->materialIDs = $this->query->cond('Active', 1)->cond('system', 0)->fields($class::$_primary);
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface samsonframework\orm\QueryInterface as the method cond() does only exist in the following implementations of said interface: samson\activerecord\dbQuery.

Let’s take a look at an example:

interface User
{
    /** @return string */
    public function getPassword();
}

class MyUser implements 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 implementation 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 interface:

    interface User
    {
        /** @return string */
        public function getPassword();
    
        /** @return string */
        public function getDisplayName();
    }
    
Loading history...
520
        }
521
522
        // Perform material filtering
523
        if ($this->applyFilter($this->materialIDs)) {
524
            // Now we have all possible material filters applied and final material identifiers collection
525
526
            // Store filtered collection size
527
            $this->count = sizeof($this->materialIDs);
528
529
            // Call material identifier handlers
530
            $this->callHandlers($this->idHandlers, array(&$this->materialIDs));
531
532
            // Perform base entity query for final filtering
533
            $this->applyBaseEntityFilter($this->materialIDs);
534
535
            // Perform sorting
536
            $this->applyFieldSorter($this->materialIDs);
537
538
            // Create count request to count pagination
539
            $this->pager->update(sizeof($this->materialIDs));
0 ignored issues
show
Bug introduced by
The method update() does not seem to exist on object<samsonframework\pager\PagerInterface>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
540
541
            // Cut only needed materials identifiers from array
542
            $this->materialIDs = array_slice($this->materialIDs, $this->pager->start, $this->pager->end);
0 ignored issues
show
Bug introduced by
Accessing start on the interface samsonframework\pager\PagerInterface suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
Bug introduced by
Accessing end on the interface samsonframework\pager\PagerInterface suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
543
544
            // Create final material query
545
            $this->query->className($this->entityName)->cond($class::$_primary, $this->materialIDs);
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface samsonframework\orm\QueryInterface as the method className() does only exist in the following implementations of said interface: samson\activerecord\dbQuery.

Let’s take a look at an example:

interface User
{
    /** @return string */
    public function getPassword();
}

class MyUser implements 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 implementation 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 interface:

    interface User
    {
        /** @return string */
        public function getPassword();
    
        /** @return string */
        public function getDisplayName();
    }
    
Loading history...
546
547
            // Call material query handlers
548
            $this->callHandlers($this->entityHandlers, array(&$this->query));
549
550
            // Add query sorter for showed page
551
            if (sizeof($this->sorter)) {
552
                $this->query->order_by($this->sorter['name'], $this->sorter['destination']);
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface samsonframework\orm\QueryInterface as the method order_by() does only exist in the following implementations of said interface: samson\activerecord\dbQuery.

Let’s take a look at an example:

interface User
{
    /** @return string */
    public function getPassword();
}

class MyUser implements 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 implementation 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 interface:

    interface User
    {
        /** @return string */
        public function getPassword();
    
        /** @return string */
        public function getDisplayName();
    }
    
Loading history...
553
            }
554
555
            // Return final filtered entity query result
556
            $this->collection = $this->query->exec();
0 ignored issues
show
Documentation Bug introduced by
It seems like $this->query->exec() can also be of type boolean. However, the property $collection is declared as type array. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

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

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
557
558
        } else { // Collection is empty
559
560
            // Clear current materials identifiers list
561
            $this->materialIDs = array();
562
563
            // Updated pagination
564
            $this->pager->update(sizeof($this->materialIDs));
0 ignored issues
show
Bug introduced by
The method update() does not seem to exist on object<samsonframework\pager\PagerInterface>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
565
        }
566
567
        // Chaining
568
        return $this;
569
    }
570
}
571