Completed
Push — master ( 9c62a1...5487fd )
by Vitaly
02:46
created

Collection::applyBaseEntityFilter()   B

Complexity

Conditions 3
Paths 3

Size

Total Lines 28
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 1
Metric Value
c 1
b 0
f 1
dl 0
loc 28
rs 8.8571
cc 3
eloc 12
nc 3
nop 1
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 samson\activerecord\Condition;
11
use samson\activerecord\dbRelation;
12
use samsonframework\collection\Paged;
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
 */
22
class Collection extends Paged
23
{
24
    /** @var string Entity manager instance */
25
    protected $managerEntity = '\samsoncms\api\query\Generic';
26
27
    /** @var array Collection for current filtered material identifiers */
28
    protected $materialIDs = array();
29
30
    /** @var array Collection of navigation filters */
31
    protected $navigation = array();
32
33
    /** @var array Collection of field filters */
34
    protected $field = array();
35
36
    /** @var array Search string collection */
37
    protected $search = array();
38
39
    /** @var array Collection of query handlers */
40
    protected $idHandlers = array();
41
42
    /** @var array External material handler and params array */
43
    protected $entityHandlers = array();
44
45
    /** @var array Base material entity handler callbacks array */
46
    protected $baseEntityHandlers = array();
47
48
    /** @var string Collection entities class name */
49
    protected $entityName = 'samson\cms\CMSMaterial';
50
51
    /** @var array Sorter parameters collection */
52
    protected $sorter = array();
53
54
    /**
55
     * Generic collection constructor
56
     * @param RenderInterface $renderer View render object
57
     * @param QueryInterface $query Query object
58
     */
59
    public function __construct(RenderInterface $renderer, QueryInterface $query, PagerInterface $pager)
60
    {
61
        // Call parent initialization
62
        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...
63
    }
64
65
    /**
66
     * Render products collection block
67
     * @param string $prefix Prefix for view variables
68
     * @param array $restricted Collection of ignored keys
69
     * @return array Collection key => value
70
     */
71
    public function toView($prefix = null, array $restricted = array())
72
    {
73
        // Render pager and collection
74
        return array(
75
            $prefix.'html' => $this->render(),
76
            $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...
77
        );
78
    }
79
80
    /**
81
     * Add external identifier filter handler
82
     * @param callback $handler
83
     * @param array $params
84
     * @return self Chaining
85
     */
86
    public function handler($handler, array $params = array())
87
    {
88
        // Add callback with parameters to array
89
        $this->idHandlers[] = array($handler, $params);
90
91
        return $this;
92
    }
93
94
    /**
95
     * Set external entity handler
96
     * @param callback $handler
97
     * @param array $params
98
     * @return self Chaining
99
     */
100
    public function baseEntityHandler($handler, array $params = array())
101
    {
102
        // Add callback with parameters to array
103
        $this->baseEntityHandlers[] = array($handler, $params);
104
105
        return $this;
106
    }
107
108
    /**
109
     * Set external entity handler
110
     * @param callback $handler
111
     * @param array $params
112
     * @return self Chaining
113
     */
114
    public function entityHandler($handler, array $params = array())
115
    {
116
        // Add callback with parameters to array
117
        $this->entityHandlers[] = array($handler, $params);
118
119
        return $this;
120
    }
121
122
    /**
123
     * Set collection sorter parameters
124
     * @param string|integer $field Field identifier or name
125
     * @param string $destination ASC|DESC
126
     * @return void
127
     */
128
    public function sorter($field, $destination = 'ASC')
129
    {
130
        /**@var \samson\activerecord\field $field */
131
        // TODO: Add ability to sort with entity fields
132
        if (in_array($field, \samson\activerecord\material::$_attributes)) {
133
            $this->sorter = array(
134
                'field' => $field,
135
                'name' => $field,
136
                'destination' => $destination
137
            );
138
        } else if ($this->isFieldObject($field)) {
139
            $this->sorter = array(
140
                'entity' => $field,
141
                'name' => $field->Name,
142
                'field' => in_array($field->Type, array(3, 7, 10)) ? 'numeric_value' : 'value',
143
                'destination' => $destination
144
            );
145
        }
146
    }
147
148
    /**
149
     * Filter collection using navigation entity or collection of them.
150
     * If collection of navigation Url or Ids is passed then this group will be
151
     * applied as single navigation filter to retrieve materials.
152
     *
153
     * @param string|integer|array $navigation Navigation URL or identifier for filtering
154
     * @return self Chaining
155
     */
156
    public function navigation($navigation)
157
    {
158
        // Do not allow empty strings
159
        if (!empty($navigation)) {
160
            // Create id or URL condition
161
            $idOrUrl = new Condition('OR');
0 ignored issues
show
Deprecated Code introduced by
The class samson\activerecord\Condition has been deprecated with message: use \samsonframework\orm\Condition

This class, trait or interface has been deprecated. The supplier of the file has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the type will be removed from the class and what other constant to use instead.

Loading history...
162
            $idOrUrl->add('StructureID', $navigation)->add('Url', $navigation);
163
164
            /** @var array $navigationIds  */
165
            $navigationIds = null;
166
            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...
167
                // Store all retrieved navigation elements as navigation collection filter
168
                $this->navigation[] = $navigationIds;
169
            }
170
        }
171
172
        // Chaining
173
        return $this;
174
    }
175
176
    /**
177
     * Filter collection using additional field entity.
178
     *
179
     * @param string|integer|Field $field Additional field identifier or name
180
     * @param mixed $value Additional field value for filtering
181
     * @param string $relation Additional field relation for filtering
182
     * @return self Chaining
183
     */
184
    public function field($field, $value, $relation = dbRelation::EQUAL)
185
    {
186
        // Do not allow empty strings
187
        if ($this->isFieldObject($field)) {
188
            // Get field value column
189
            $valueField = in_array($field->Type, array(3, 7, 10)) ? 'numeric_value' : 'value';
190
			$valueField = $field->Type == 6 ? 'key_value' : $valueField;
191
			
192
            /** @var Condition $condition Ranged condition */
193
            $condition = new Condition('AND');
0 ignored issues
show
Deprecated Code introduced by
The class samson\activerecord\Condition has been deprecated with message: use \samsonframework\orm\Condition

This class, trait or interface has been deprecated. The supplier of the file has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the type will be removed from the class and what other constant to use instead.

Loading history...
194
195
            // Add min value for ranged condition
196
            $condition->add($valueField, $value, $relation);
197
198
            // Store retrieved field element and its value as field collection filter
199
            $this->field[] = array($field, $condition);
200
        }
201
202
        // Chaining
203
        return $this;
204
    }
205
206
    /**
207
     * Filter collection using additional field entity values and LIKE relation.
208
     * If this method is called more then once, it will use materials, previously filtered by this method.
209
     *
210
     * @param string $search Search string
211
     * @return self Chaining
212
     */
213
    public function search($search)
214
    {
215
        // If input parameter is a string add it to search string collection
216
        if (isset($search{0})) {
217
            $this->search[] = $search;
218
        }
219
220
        // Chaining
221
        return $this;
222
    }
223
224
    /**
225
     * Filter collection of numeric field in range from min to max values
226
     * @param string|integer|Field $field Additional field identifier or name
227
     * @param integer $minValue Min value for range filter
228
     * @param integer $maxValue Max value for range filter
229
     * @return self Chaining
230
     */
231
    public function ranged($field, $minValue, $maxValue)
232
    {
233
        // Check input parameters and try to find field
234
        if (($minValue <= $maxValue) && $this->isFieldObject($field)) {
235
            // TODO: Remove integers from code, handle else
236
            // Only numeric fields are supported
237
            if (in_array($field->Type, array(3, 7, 10))) {
238
                /** @var Condition $condition Ranged condition */
239
                $condition = new Condition('AND');
0 ignored issues
show
Deprecated Code introduced by
The class samson\activerecord\Condition has been deprecated with message: use \samsonframework\orm\Condition

This class, trait or interface has been deprecated. The supplier of the file has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the type will be removed from the class and what other constant to use instead.

Loading history...
240
241
                // Add min value for ranged condition
242
                $condition->add('numeric_value', $minValue, dbRelation::GREATER_EQ);
243
244
                // Add max value for ranged condition
245
                $condition->add('numeric_value', $maxValue, dbRelation::LOWER_EQ);
246
247
                // Store created condition
248
                $this->field[] = array($field, $condition);
249
            }
250
        }
251
252
        // Chaining
253
        return $this;
254
    }
255
256
    /**
257
     * Try to find additional field record
258
     * @param string|integer $field Additional field identifier or name
259
     * @return bool True if field record has been found
260
     */
261
    protected function isFieldObject(&$field)
262
    {
263
        // Do not allow empty strings
264
        if (!empty($field)) {
265
            // Create id or URL condition
266
            $idOrUrl = new Condition('OR');
0 ignored issues
show
Deprecated Code introduced by
The class samson\activerecord\Condition has been deprecated with message: use \samsonframework\orm\Condition

This class, trait or interface has been deprecated. The supplier of the file has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the type will be removed from the class and what other constant to use instead.

Loading history...
267
            $idOrUrl->add('FieldID', $field)->add('Name', $field);
268
269
            // Perform query
270
            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...
271
        }
272
273
        // Field not found
274
        return false;
275
    }
276
277
    /**
278
     * Try to get all material identifiers filtered by navigation
279
     * if no navigation filtering is set - nothing will happen.
280
     *
281
     * @param array $filteredIds Collection of filtered material identifiers
282
     * @return bool True if ALL navigation filtering succeeded or there was no filtering at all otherwise false
283
     */
284 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...
285
    {
286
        // Iterate all applied navigation filters
287
        foreach ($this->navigation as $navigation) {
288
            // Create navigation-material query
289
            $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...
290
291
                ->cond('StructureID', $navigation)
292
                ->cond('Active', 1)
293
                ->group_by('MaterialID')
294
            ;
295
296
            if (isset($filteredIds)) {
297
                $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...
298
            }
299
300
            // Perform request to get next portion of filtered material identifiers
301
            if (!$this->query->fields('MaterialID', $filteredIds)) {
0 ignored issues
show
Bug introduced by
It seems like $filteredIds defined by parameter $filteredIds on line 284 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...
302
                // This filter applying failed
303
                return false;
304
            }
305
        }
306
307
        // We have no navigation collection filters
308
        return true;
309
    }
310
311
    /**
312
     * Try to get all material identifiers filtered by additional field
313
     * if no field filtering is set - nothing will happen.
314
     *
315
     * @param array $filteredIds Collection of filtered material identifiers
316
     * @return bool True if ALL field filtering succeeded or there was no filtering at all otherwise false
317
     */
318 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...
319
    {
320
        // Iterate all applied field filters
321
        foreach ($this->field as $field) {
322
            // Create material-field query
323
            $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...
324
                ->cond('FieldID', $field[0]->id)
325
                ->cond($field[1])
326
                ->group_by('MaterialID')
327
            ;
328
329
            if (isset($filteredIds)) {
330
                $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...
331
            }
332
333
            // Perform request to get next portion of filtered material identifiers
334
            if (!$this->query->fields('MaterialID', $filteredIds)) {
0 ignored issues
show
Bug introduced by
It seems like $filteredIds defined by parameter $filteredIds on line 318 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...
335
                // This filter applying failed
336
                return false;
337
            }
338
        }
339
340
        // We have no field collection filters
341
        return true;
342
    }
343
344
    /**
345
     * Try to find all materials which have fields similar to search strings
346
     *
347
     * @param array $filteredIds Collection of filtered material identifiers
348
     * @return bool True if ALL field filtering succeeded or there was no filtering at all otherwise false
349
     */
350
    protected function applySearchFilter(& $filteredIds = array())
351
    {
352
        /** @var array $fields Variable to store all fields related to set navigation */
353
        $fields = array();
354
        /** @var array $navigationArray Array of set navigation identifiers */
355
        $navigationArray = array();
356
        /** @var array $fieldFilter Array of filtered material identifiers via materialfield table */
357
        $fieldFilter = array();
358
        /** @var array $materialFilter Array of filtered material identifiers via material table */
359
        $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...
360
361
        // If there are at least one search string
362
        if (!empty($this->search)) {
363
            // Create array containing all navigation identifiers
364
            foreach ($this->navigation as $navigation) {
365
                // Navigation hook for searching action
366
                $navigation = is_array($navigation) ? $navigation : array($navigation);
367
                $navigationArray = array_merge($navigationArray, $navigation);
368
            }
369
370
            // Get all related fields
371
            $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...
372
                ->cond('StructureID', $navigationArray)
373
                ->group_by('FieldID')
374
                ->fields('FieldID', $fields);
375
376
            // Iterate over search strings
377
            foreach ($this->search as $searchString) {
378
                // Try to find search value in materialfield table
379
                $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...
380
                    ->cond('FieldID', $fields)
381
                    ->cond('MaterialID', $filteredIds)
382
                    ->cond('Value', '%' . $searchString . '%', dbRelation::LIKE)
383
                    ->cond('Active', 1)
384
                    ->group_by('MaterialID')
385
                    ->fields('MaterialID', $fieldFilter);
386
387
                // TODO: Add generic support for all native fields or their configuration
388
                // Condition to search in material table by Name and URL
389
                $materialCondition = new Condition('OR');
0 ignored issues
show
Deprecated Code introduced by
The class samson\activerecord\Condition has been deprecated with message: use \samsonframework\orm\Condition

This class, trait or interface has been deprecated. The supplier of the file has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the type will be removed from the class and what other constant to use instead.

Loading history...
390
                $materialCondition->add('Name', '%' . $searchString . '%', dbRelation::LIKE)
391
                    ->add('Url', '%' . $searchString . '%', dbRelation::LIKE);
392
393
394
                // Try to find search value in material table
395
                $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...
396
                    ->cond($materialCondition)
397
                    ->cond('Active', 1);
398
399
                // If we have not empty collection of filtering identifiers
400
                if (sizeof($filteredIds)) {
401
                    $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...
402
                }
403
404
                $materialFilter = $this->query->fields('MaterialID');
405
406
                // If there are no materials with specified conditions
407
                if (empty($materialFilter) && empty($fieldFilter)) {
408
                    // Filter applying failed
409
                    return false;
410
                } else {// Otherwise set filtered material identifiers
411
                    $filteredIds = array_unique(array_merge($materialFilter, $fieldFilter));
412
                }
413
            }
414
        }
415
416
        // We have no search collection filters
417
        return true;
418
    }
419
420
    /**
421
     * Apply all possible material filters
422
     * @param array $filteredIds Collection of material identifiers
423
     * @return bool True if ALL filtering succeeded or there was no filtering at all otherwise false
424
     */
425
    protected function applyFilter(& $filteredIds = array())
426
    {
427
        return $this->applyNavigationFilter($filteredIds)
428
            && $this->applyFieldFilter($filteredIds)
429
            && $this->applySearchFilter($filteredIds);
430
    }
431
432
    /**
433
     * Perform material identifiers collection sorting
434
     * @param array $materialIDs Variable to return sorted collection
435
     */
436
    protected function applyFieldSorter(&$materialIDs = array())
437
    {
438
        // Check if sorter is configured
439
        if (sizeof($this->sorter)) {
440
            // If we need to sort by entity additional field(column)
441
            if (!in_array($this->sorter['field'], \samson\activerecord\material::$_attributes)) {
442
                // Sort material identifiers by its additional fields
443
                $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...
444
                    ->cond('FieldID', $this->sorter['entity']->id)
445
                    ->order_by($this->sorter['field'], $this->sorter['destination'])
446
                    ->cond('MaterialID', $materialIDs)
447
                    ->fields('MaterialID', $materialIDs);
448
            }
449
        }
450
    }
451
452
    /**
453
     * Call handlers stack
454
     * @param array $handlers Collection of callbacks with their parameters
455
     * @param array $params External parameters to pass to callback at first
456
     * @return bool True if all handlers succeeded
457
     */
458
    protected function callHandlers(& $handlers = array(), $params = array())
459
    {
460
        // Call external handlers
461
        foreach ($handlers as $handler) {
462
            // Call external handlers chain
463
            if (call_user_func_array(
464
                $handler[0],
465
                array_merge($params, $handler[1]) // Merge params and handler params
466
            ) === false) {
467
                // Stop - if one of external handlers has failed
468
                return false;
469
            }
470
        }
471
472
        return true;
473
    }
474
475
    /**
476
     * Perform filtering on base material entity
477
     * @param array $materialIDs Variable to return sorted collection
478
     */
479
    protected function applyBaseEntityFilter(& $materialIDs = array())
480
    {
481
        // TODO: Change this to new OOP approach
482
        $class = $this->entityName;
483
484
        // Configure query to base entity
485
        $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...
486
487
        // Call base material entity handlers to prepare query
488
        $this->callHandlers($this->baseEntityHandlers, array(&$this->query));
489
490
        // Check if sorter is configured
491
        if (sizeof($this->sorter)) {
492
            // If we need to sort by entity own field(column)
493
            if (in_array($this->sorter['field'], $class::$_attributes)) {
494
                // Add material entity sorter
495
                $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...
496
            }
497
        }
498
499
        // Perform main entity query
500
        $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...
501
            ->cond('Active', 1) // Remove deleted entities
502
            ->cond('system', 0) // Remove system entities
503
            ->cond($class::$_primary, $materialIDs) // Filter to current set
504
            ->fields($class::$_primary)
505
        ;
506
    }
507
508
    /**
509
     * Perform collection database retrieval using set filters
510
     *
511
     * @return self Chaining
512
     */
513
    public function fill()
514
    {
515
        // Clear current materials identifiers list
516
        $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...
517
518
        // TODO: Change this to new OOP approach
519
        $class = $this->entityName;
520
521
        // If no filters is set
522
        if (!sizeof($this->search) && !sizeof($this->navigation) && !sizeof($this->field)) {
523
            // Get all entity records identifiers
524
            $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...
525
        }
526
527
        // Perform material filtering
528
        if ($this->applyFilter($this->materialIDs)) {
529
            // Now we have all possible material filters applied and final material identifiers collection
530
531
            // Store filtered collection size
532
            $this->count = sizeof($this->materialIDs);
533
534
            // Call material identifier handlers
535
            $this->callHandlers($this->idHandlers, array(&$this->materialIDs));
536
537
            // Perform base entity query for final filtering
538
            $this->applyBaseEntityFilter($this->materialIDs);
539
540
            // Perform sorting
541
            $this->applyFieldSorter($this->materialIDs);
542
543
            // Create count request to count pagination
544
            $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...
545
546
            // Cut only needed materials identifiers from array
547
            $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...
548
549
            // Create final material query
550
            $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...
551
552
            // Call material query handlers
553
            $this->callHandlers($this->entityHandlers, array(&$this->query));
554
555
            // Add query sorter for showed page
556
            if (sizeof($this->sorter)) {
557
                $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...
558
            }
559
560
            // Return final filtered entity query result
561
            $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...
562
563
        } else { // Collection is empty
564
565
            // Clear current materials identifiers list
566
            $this->materialIDs = array();
567
568
            // Updated pagination
569
            $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...
570
        }
571
572
        // Chaining
573
        return $this;
574
    }
575
}
576