Issues (168)

Security Analysis    no request data  

This project does not seem to handle request data directly as such no vulnerable execution paths were found.

  Cross-Site Scripting
Cross-Site Scripting enables an attacker to inject code into the response of a web-request that is viewed by other users. It can for example be used to bypass access controls, or even to take over other users' accounts.
  File Exposure
File Exposure allows an attacker to gain access to local files that he should not be able to access. These files can for example include database credentials, or other configuration files.
  File Manipulation
File Manipulation enables an attacker to write custom data to files. This potentially leads to injection of arbitrary code on the server.
  Object Injection
Object Injection enables an attacker to inject an object into PHP code, and can lead to arbitrary code execution, file exposure, or file manipulation attacks.
  Code Injection
Code Injection enables an attacker to execute arbitrary code on the server.
  Response Splitting
Response Splitting can be used to send arbitrary responses.
  File Inclusion
File Inclusion enables an attacker to inject custom files into PHP's file loading mechanism, either explicitly passed to include, or for example via PHP's auto-loading mechanism.
  Command Injection
Command Injection enables an attacker to inject a shell command that is execute with the privileges of the web-server. This can be used to expose sensitive data, or gain access of your server.
  SQL Injection
SQL Injection enables an attacker to execute arbitrary SQL code on your database server gaining access to user data, or manipulating user data.
  XPath Injection
XPath Injection enables an attacker to modify the parts of XML document that are read. If that XML document is for example used for authentication, this can lead to further vulnerabilities similar to SQL Injection.
  LDAP Injection
LDAP Injection enables an attacker to inject LDAP statements potentially granting permission to run unauthorized queries, or modify content inside the LDAP tree.
  Header Injection
  Other Vulnerability
This category comprises other attack vectors such as manipulating the PHP runtime, loading custom extensions, freezing the runtime, or similar.
  Regex Injection
Regex Injection enables an attacker to execute arbitrary code in your PHP process.
  XML Injection
XML Injection enables an attacker to read files on your local filesystem including configuration files, or can be abused to freeze your web-server process.
  Variable Injection
Variable Injection enables an attacker to overwrite program variables with custom data, and can lead to further vulnerabilities.
Unfortunately, the security analysis is currently not available for your project. If you are a non-commercial open-source project, please contact support to gain access.

src/Collection.php (19 issues)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

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 samsoncms\api\query\Generic;
11
use samsonframework\orm\Condition;
12
use samsonframework\collection\Paged;
13
use samsonframework\orm\Relation;
14
use samsonframework\pager\PagerInterface;
15
use samsonframework\core\RenderInterface;
16
use samsonframework\orm\QueryInterface;
17
18
/**
19
 * Collection query builder for filtering
20
 * @package    samsonos\cms\collection
21
 * @author     Egorov Vitaly <[email protected]>
22
 * @deprecated Use generated Entities and EntityQueries classes.
23
 */
24
class Collection extends Paged
25
{
26
    /** @var string Entity manager instance */
27
    protected $managerEntity = Generic::class;
28
29
    /** @var array Collection for current filtered material identifiers */
30
    protected $materialIDs = array();
31
32
    /** @var array Collection of navigation filters */
33
    protected $navigation = array();
34
35
    /** @var array Collection of field filters */
36
    protected $field = array();
37
38
    /** @var array Collection of query handlers */
39
    protected $idHandlers = array();
40
41
    /** @var array External material handler and params array */
42
    protected $entityHandlers = array();
43
44
    /** @var array Base material entity handler callbacks array */
45
    protected $baseEntityHandlers = array();
46
47
    /** @var string Collection entities class name */
48
    protected $entityName = Material::class;
49
50
    /**
51
     * Generic collection constructor
52
     *
53
     * @param RenderInterface $renderer View render object
54
     * @param QueryInterface  $query    Query object
55
     */
56
    public function __construct(RenderInterface $renderer, QueryInterface $query, PagerInterface $pager)
57
    {
58
        // Call parent initialization
59
        parent::__construct($renderer, $query->entity('\samson\activerecord\material'), $pager);
60
    }
61
62
    /**
63
     * Render products collection block
64
     *
65
     * @param string $prefix     Prefix for view variables
66
     * @param array  $restricted Collection of ignored keys
67
     *
68
     * @return array Collection key => value
69
     */
70
    public function toView($prefix = null, array $restricted = array())
71
    {
72
        // Render pager and collection
73
        return array_diff(array(
74
            $prefix . 'html' => $this->render(),
75
            $prefix . 'pager' => $this->pager->total > 1 ? $this->pager->toHTML() : ''
0 ignored issues
show
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...
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...
76
        ), $restricted);
77
    }
78
79
    /**
80
     * Add external identifier filter handler
81
     *
82
     * @param callback $handler
83
     * @param array    $params
84
     *
85
     * @return $this Chaining
86
     */
87
    public function handler($handler, array $params = array())
88
    {
89
        // Add callback with parameters to array
90
        $this->idHandlers[] = array($handler, $params);
91
92
        return $this;
93
    }
94
95
    /**
96
     * Set external entity handler
97
     *
98
     * @param callback $handler
99
     * @param array    $params
100
     *
101
     * @return $this Chaining
102
     */
103
    public function baseEntityHandler($handler, array $params = array())
104
    {
105
        // Add callback with parameters to array
106
        $this->baseEntityHandlers[] = array($handler, $params);
107
108
        return $this;
109
    }
110
111
    /**
112
     * Set external entity handler
113
     *
114
     * @param callback $handler
115
     * @param array    $params
116
     *
117
     * @return $this Chaining
118
     */
119
    public function entityHandler($handler, array $params = array())
120
    {
121
        // Add callback with parameters to array
122
        $this->entityHandlers[] = array($handler, $params);
123
124
        return $this;
125
    }
126
127
    /**
128
     * Set collection sorter parameters
129
     *
130
     * @param string|integer $field       Field identifier or name
131
     * @param string         $destination ASC|DESC
132
     *
133
     * @return void
134
     */
135
    public function sorter($field, $destination = 'ASC')
136
    {
137
        /**@var \samson\activerecord\field $field */
138
        // TODO: Add ability to sort with entity fields
139
        if (in_array($field, \samson\activerecord\material::$_attributes)) {
140
            $this->sorter = array(
141
                'field' => $field,
142
                'name' => $field,
143
                'destination' => $destination
144
            );
145
        } elseif ($this->isFieldObject($field)) {
146
            $this->sorter = array(
147
                'entity' => $field,
148
                'name' => $field->Name,
149
                'field' => in_array($field->Type, array(3, 7, 10)) ? 'numeric_value' : 'value',
150
                'destination' => $destination
151
            );
152
        }
153
    }
154
155
    /**
156
     * Filter collection using navigation entity or collection of them.
157
     * If collection of navigation Url or Ids is passed then this group will be
158
     * applied as single navigation filter to retrieve materials.
159
     *
160
     * @param string|integer|array $navigation Navigation URL or identifier for filtering
161
     *
162
     * @return $this Chaining
163
     */
164
    public function navigation($navigation)
165
    {
166
        // Do not allow empty strings
167
        if (!empty($navigation)) {
168
            // Create id or URL condition
169
            $idOrUrl = new Condition('OR');
170
            $idOrUrl->add('StructureID', $navigation)->add('Url', $navigation);
171
172
            /** @var array $navigationIds */
173
            $navigationIds = null;
174
            if ($this->query->entity('\samson\activerecord\structure')->whereCondition($idOrUrl)->fields('StructureID', $navigationIds)) {
175
                // Store all retrieved navigation elements as navigation collection filter
176
                $this->navigation[] = $navigationIds;
177
            }
178
        }
179
180
        // Chaining
181
        return $this;
182
    }
183
184
    /**
185
     * Filter collection using additional field entity.
186
     *
187
     * @param string|integer|Field $field    Additional field identifier or name
188
     * @param mixed                $value    Additional field value for filtering
189
     * @param string               $relation Additional field relation for filtering
190
     *
191
     * @return $this Chaining
192
     */
193
    public function field($field, $value, $relation = Relation::EQUAL)
194
    {
195
        // Do not allow empty strings
196
        if ($this->isFieldObject($field)) {
197
            // Get field value column
198
            $valueField = in_array($field->Type, array(3, 7, 10)) ? 'numeric_value' : 'value';
199
            $valueField = $field->Type == 6 ? 'key_value' : $valueField;
200
201
            /** @var Condition $condition Ranged condition */
202
            $condition = new Condition('AND');
203
204
            // Add min value for ranged condition
205
            $condition->add($valueField, $value, $relation);
206
207
            // Store retrieved field element and its value as field collection filter
208
            $this->field[] = array($field, $condition);
209
        }
210
211
        // Chaining
212
        return $this;
213
    }
214
215
    /**
216
     * Filter collection using additional field entity values and LIKE relation.
217
     * If this method is called more then once, it will use materials, previously filtered by this method.
218
     *
219
     * @param string $search Search string
220
     *
221
     * @return $this Chaining
222
     */
223
    public function search($search)
224
    {
225
        // If input parameter is a string add it to search string collection
226
        if (isset($search{0})) {
227
            $this->search[] = $search;
228
        }
229
230
        // Chaining
231
        return $this;
232
    }
233
234
    /**
235
     * Filter collection of numeric field in range from min to max values
236
     *
237
     * @param string|integer|Field $field    Additional field identifier or name
238
     * @param integer              $minValue Min value for range filter
239
     * @param integer              $maxValue Max value for range filter
240
     *
241
     * @return $this Chaining
242
     */
243
    public function ranged($field, $minValue, $maxValue)
244
    {
245
        // Check input parameters and try to find field
246
        if (($minValue <= $maxValue) && $this->isFieldObject($field)) {
247
            // TODO: Remove integers from code, handle else
248
            // Only numeric fields are supported
249
            if (in_array($field->Type, array(3, 7, 10))) {
250
                /** @var Condition $condition Ranged condition */
251
                $condition = new Condition('AND');
252
253
                // Add min value for ranged condition
254
                $condition->add('numeric_value', $minValue, Relation::GREATER_EQ);
255
256
                // Add max value for ranged condition
257
                $condition->add('numeric_value', $maxValue, Relation::LOWER_EQ);
258
259
                // Store created condition
260
                $this->field[] = array($field, $condition);
261
            }
262
        }
263
264
        // Chaining
265
        return $this;
266
    }
267
268
    /**
269
     * Try to find additional field record
270
     *
271
     * @param string|integer $field Additional field identifier or name
272
     *
273
     * @return bool True if field record has been found
274
     */
275
    protected function isFieldObject(&$field)
276
    {
277
        // Do not allow empty strings
278
        if (!empty($field)) {
279
            // Create id or URL condition
280
            $idOrUrl = new Condition('OR');
281
            $idOrUrl->add('FieldID', $field)->add('Name', $field);
282
283
            // Perform query
284
            return $this->query->entity('\samson\activerecord\field')->whereCondition($idOrUrl)->first($field);
0 ignored issues
show
$field is of type string|integer, but the function expects a null|object<samsonframework\orm\RecordInterface>.

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

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

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

function acceptsInteger($int) { }

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

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
285
        }
286
287
        // Field not found
288
        return false;
289
    }
290
291
    /**
292
     * Try to get all material identifiers filtered by navigation
293
     * if no navigation filtering is set - nothing will happen.
294
     *
295
     * @param array $filteredIds Collection of filtered material identifiers
296
     *
297
     * @return bool True if ALL navigation filtering succeeded or there was no filtering at all otherwise false
298
     */
299 View Code Duplication
    protected function applyNavigationFilter(&$filteredIds = array())
0 ignored issues
show
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...
300
    {
301
        // Iterate all applied navigation filters
302
        foreach ($this->navigation as $navigation) {
303
            // Create navigation-material query
304
            $this->query->entity('\samson\activerecord\structurematerial')
305
                ->where('StructureID', $navigation)
306
                ->where('Active', 1)
307
                ->groupBy('MaterialID');
308
309
            if (null !== $filteredIds) {
310
                $this->query->where('MaterialID', $filteredIds);
311
            }
312
313
            // Perform request to get next portion of filtered material identifiers
314
            if (!$this->query->fields('MaterialID', $filteredIds)) {
0 ignored issues
show
It seems like $filteredIds defined by parameter $filteredIds on line 299 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...
315
                // This filter applying failed
316
                return false;
317
            }
318
        }
319
320
        // We have no navigation collection filters
321
        return true;
322
    }
323
324
    /**
325
     * Try to get all material identifiers filtered by additional field
326
     * if no field filtering is set - nothing will happen.
327
     *
328
     * @param array $filteredIds Collection of filtered material identifiers
329
     *
330
     * @return bool True if ALL field filtering succeeded or there was no filtering at all otherwise false
331
     */
332 View Code Duplication
    protected function applyFieldFilter(&$filteredIds = array())
0 ignored issues
show
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...
333
    {
334
        // Iterate all applied field filters
335
        foreach ($this->field as $field) {
336
            // Create material-field query
337
            $this->query->entity('\samson\activerecord\materialfield')
338
                ->where('FieldID', $field[0]->id)
339
                ->whereCondition($field[1])
340
                ->groupBy('MaterialID');
341
342
            if (null !== $filteredIds) {
343
                $this->query->where('MaterialID', $filteredIds);
344
            }
345
346
            // Perform request to get next portion of filtered material identifiers
347
            if (!$this->query->fields('MaterialID', $filteredIds)) {
0 ignored issues
show
It seems like $filteredIds defined by parameter $filteredIds on line 332 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...
348
                // This filter applying failed
349
                return false;
350
            }
351
        }
352
353
        // We have no field collection filters
354
        return true;
355
    }
356
357
    /**
358
     * Try to find all materials which have fields similar to search strings
359
     *
360
     * @param array $filteredIds Collection of filtered material identifiers
361
     *
362
     * @return bool True if ALL field filtering succeeded or there was no filtering at all otherwise false
363
     */
364
    protected function applySearchFilter(&$filteredIds = array())
365
    {
366
        /** @var array $fields Variable to store all fields related to set navigation */
367
        $fields = array();
368
        /** @var array $navigationArray Array of set navigation identifiers */
369
        $navigationArray = array();
370
        /** @var array $fieldFilter Array of filtered material identifiers via materialfield table */
371
        $fieldFilter = array();
372
        /** @var array $materialFilter Array of filtered material identifiers via material table */
373
        $materialFilter = array();
0 ignored issues
show
$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...
374
375
        // If there are at least one search string
376
        if (!empty($this->search)) {
377
            // Create array containing all navigation identifiers
378
            foreach ($this->navigation as $navigation) {
379
                // Navigation hook for searching action
380
                $navigation = is_array($navigation) ? $navigation : array($navigation);
381
                $navigationArray = array_merge($navigationArray, $navigation);
382
            }
383
384
            // Get all related fields
385
            $this->query->entity('\samson\activerecord\structurefield')
386
                ->where('StructureID', $navigationArray)
387
                ->groupBy('FieldID')
388
                ->fields('FieldID', $fields);
389
390
            // Iterate over search strings
391
            foreach ($this->search as $searchString) {
392
                // Try to find search value in materialfield table
393
                $this->query->entity('\samson\activerecord\materialfield')
394
                    ->where('FieldID', $fields)
395
                    ->where('MaterialID', $filteredIds)
396
                    ->where('Value', '%' . $searchString . '%', Relation::LIKE)
397
                    ->where('Active', 1)
398
                    ->groupBy('MaterialID')
399
                    ->fields('MaterialID', $fieldFilter);
0 ignored issues
show
It seems like $fieldFilter defined by array() on line 371 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?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
400
401
                // TODO: Add generic support for all native fields or their configuration
402
                // Condition to search in material table by Name and URL
403
                $materialCondition = new Condition('OR');
404
                $materialCondition->add('Name', '%' . $searchString . '%', Relation::LIKE)
405
                    ->add('Url', '%' . $searchString . '%', Relation::LIKE);
406
407
408
                // Try to find search value in material table
409
                $this->query->entity('\samson\activerecord\material')
410
                    ->whereCondition($materialCondition)
411
                    ->where('Active', 1);
412
413
                // If we have not empty collection of filtering identifiers
414
                if (count($filteredIds)) {
415
                    $this->query->where('MaterialID', $filteredIds);
416
                }
417
418
                $materialFilter = $this->query->fields('MaterialID');
419
420
                // If there are no materials with specified conditions
421
                if (empty($materialFilter) && empty($fieldFilter) && count($materialFilter) != 0 && count($fieldFilter != 0)) {
422
                    // Filter applying failed
423
                    return false;
424
                } else {// Otherwise set filtered material identifiers
425
                    $filteredIds = array_unique(array_merge($materialFilter, $fieldFilter));
426
                }
427
            }
428
        }
429
430
        // We have no search collection filters
431
        return true;
432
    }
433
434
    /**
435
     * Apply all possible material filters
436
     *
437
     * @param array $filteredIds Collection of material identifiers
438
     *
439
     * @return bool True if ALL filtering succeeded or there was no filtering at all otherwise false
440
     */
441
    protected function applyFilter(& $filteredIds = array())
442
    {
443
        return $this->applyNavigationFilter($filteredIds)
444
        && $this->applyFieldFilter($filteredIds)
445
        && $this->applySearchFilter($filteredIds)
446
        && $this->applyMaterialSorter($filteredIds);
447
    }
448
449
    /**
450
     * Perform material identifiers collection sorting
451
     *
452
     * @param array $materialIDs Variable to return sorted collection
453
     */
454
    protected function applyFieldSorter(&$materialIDs = array())
455
    {
456
        // Check if sorter is configured
457
        if (count($this->sorter)) {
458
            // If we need to sort by entity additional field(column)
459
            if (!in_array($this->sorter['field'], \samson\activerecord\material::$_attributes)) {
460
                // Sort material identifiers by its additional fields
461
                $this->query->entity('\samson\activerecord\materialfield')
462
                    ->where('FieldID', $this->sorter['entity']->id)
463
                    ->orderBy($this->sorter['field'], $this->sorter['destination'])
464
                    ->where('MaterialID', $materialIDs)
465
                    ->fields('MaterialID', $materialIDs);
466
            }
467
        }
468
    }
469
470
        /**
471
     * Perform material own fields sorting
472
     *
473
     * @param array $materialIDs Variable to return sorted collection
474
     *
475
     * @return bool Always true as we are just sorting
476
     */
477
    protected function applyMaterialSorter(&$materialIDs = array())
478
    {
479
        // Check if sorter is configured
480
        if (count($this->sorter)) {
481
            // If we need to sort by entity additional field(column)
482
            if (in_array($this->sorter['field'], \samson\activerecord\material::$_attributes)) {
483
                // Sort material identifiers by its additional fields
484
                $this->query->entity('\samson\activerecord\material')
485
                    ->where('MaterialID', $materialIDs)
486
                    ->orderBy($this->sorter['field'], $this->sorter['destination'])
487
                    ->fields('MaterialID', $materialIDs);
488
            }
489
        }
490
491
        return true;
492
    }
493
494
    /**
495
     * Call handlers stack
496
     *
497
     * @param array $handlers Collection of callbacks with their parameters
498
     * @param array $params   External parameters to pass to callback at first
499
     *
500
     * @return bool True if all handlers succeeded
501
     */
502
    protected function callHandlers(&$handlers = array(), $params = array())
503
    {
504
        // Call external handlers
505
        foreach ($handlers as $handler) {
506
            // Call external handlers chain
507
            if (call_user_func_array($handler[0], array_merge($params, $handler[1])) === false) {
508
                // Stop - if one of external handlers has failed
509
                return false;
510
            }
511
        }
512
513
        return true;
514
    }
515
516
    /**
517
     * Perform filtering on base material entity
518
     *
519
     * @param array $materialIDs Variable to return sorted collection
520
     */
521
    protected function applyBaseEntityFilter(&$materialIDs = array())
522
    {
523
        // TODO: Change this to new OOP approach
524
        $class = $this->entityName;
525
526
        // Configure query to base entity
527
        $this->query->entity('samson\activerecord\material');
528
529
        // Call base material entity handlers to prepare query
530
        $this->callHandlers($this->baseEntityHandlers, array(&$this->query));
531
532
        // Check if sorter is configured
533 View Code Duplication
        if (count($this->sorter)) {
0 ignored issues
show
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
534
            // If we need to sort by entity own field(column)
535
            if (in_array($this->sorter['field'], $class::$_attributes)) {
536
                // Add material entity sorter
537
                $this->query->orderBy($this->sorter['field'], $this->sorter['destination']);
538
            }
539
        }
540
541
        // Perform main entity query
542
        $this->materialIDs = $this->query
543
            ->where('Active', 1)// Remove deleted entities
544
            ->where('system', 0)// Remove system entities
545
            ->where($class::$_primary, $materialIDs)// Filter to current set
546
            ->fields($class::$_primary);
547
    }
548
549
    /**
550
     * Perform collection database retrieval using set filters
551
     *
552
     * @return $this Chaining
553
     */
554
    public function fill()
555
    {
556
        // Clear current materials identifiers list
557
        $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...
558
559
        // TODO: Change this to new OOP approach
560
        $class = $this->entityName;
561
562
        // If no filters is set
563
        if (!count($this->search) && !count($this->navigation) && !count($this->field)) {
564
            // Add sorting if present for material table
565 View Code Duplication
            if (count($this->sorter) && !array_key_exists('enitity', $this->sorter)) {
0 ignored issues
show
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
566
                $this->query->orderBy($this->sorter['field'], $this->sorter['destination']);
567
            }
568
            // Get all entity records identifiers
569
            $this->materialIDs = $this->query->where('Active', 1)->where('system', 0)->fields($class::$_primary);
570
        }
571
572
        // Perform material filtering
573
        if ($this->applyFilter($this->materialIDs)) {
0 ignored issues
show
It seems like $this->materialIDs can also be of type null; however, samsoncms\api\Collection::applyFilter() does only seem to accept array, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
574
            // Now we have all possible material filters applied and final material identifiers collection
575
576
            // Store filtered collection size
577
            $this->count = count($this->materialIDs);
578
579
            // Call material identifier handlers
580
            $this->callHandlers($this->idHandlers, array(&$this->materialIDs));
581
582
            // Perform base entity query for final filtering
583
            $this->applyBaseEntityFilter($this->materialIDs);
584
585
            // Perform sorting
586
            $this->applyFieldSorter($this->materialIDs);
587
588
            // Create count request to count pagination
589
            $this->pager->update(count($this->materialIDs));
0 ignored issues
show
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...
590
591
            // Cut only needed materials identifiers from array
592
            $this->materialIDs = array_slice($this->materialIDs, $this->pager->start, $this->pager->end);
0 ignored issues
show
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...
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...
593
594
            // Create final material query
595
            $this->query->entity($this->entityName)->where($class::$_primary, $this->materialIDs);
596
597
            // Call material query handlers
598
            $this->callHandlers($this->entityHandlers, array(&$this->query));
599
600
            // Add query sorter for showed page
601
            if (count($this->sorter)) {
602
                $this->query->orderBy($this->sorter['name'], $this->sorter['destination']);
603
            }
604
605
            // Return final filtered entity query result
606
            $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...
607
0 ignored issues
show
Blank line found at end of control structure
Loading history...
608
        } else { // Collection is empty
609
610
            // Clear current materials identifiers list
611
            $this->materialIDs = array();
612
613
            // Updated pagination
614
            $this->pager->update(count($this->materialIDs));
0 ignored issues
show
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...
615
        }
616
617
        // Chaining
618
        return $this;
619
    }
620
}
621