Passed
Push — master ( be20b1...a18a63 )
by Vitaly
32s
created

Entity::applySearch()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 18
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 18
rs 9.4285
cc 3
eloc 12
nc 3
nop 1
1
<?php
2
/**
3
 * Created by PhpStorm.
4
 * User: VITALYIEGOROV
5
 * Date: 11.12.15
6
 * Time: 17:35
7
 */
8
namespace samsoncms\api\query;
9
10
use samson\activerecord\dbQuery;
11
use samson\activerecord\materialfield;
0 ignored issues
show
Bug introduced by
This use statement conflicts with another class in this namespace, samsoncms\api\query\materialfield.

Let’s assume that you have a directory layout like this:

.
|-- OtherDir
|   |-- Bar.php
|   `-- Foo.php
`-- SomeDir
    `-- Foo.php

and let’s assume the following content of Bar.php:

// Bar.php
namespace OtherDir;

use SomeDir\Foo; // This now conflicts the class OtherDir\Foo

If both files OtherDir/Foo.php and SomeDir/Foo.php are loaded in the same runtime, you will see a PHP error such as the following:

PHP Fatal error:  Cannot use SomeDir\Foo as Foo because the name is already in use in OtherDir/Foo.php

However, as OtherDir/Foo.php does not necessarily have to be loaded and the error is only triggered if it is loaded before OtherDir/Bar.php, this problem might go unnoticed for a while. In order to prevent this error from surfacing, you must import the namespace with a different alias:

// Bar.php
namespace OtherDir;

use SomeDir\Foo as SomeDirFoo; // There is no conflict anymore.
Loading history...
12
use samsonframework\orm\Argument;
13
use samsonframework\orm\ArgumentInterface;
14
use samsoncms\api\CMS;
15
use samsoncms\api\exception\EntityFieldNotFound;
16
use samsoncms\api\Field;
17
use samsoncms\api\Material;
18
use samsonframework\orm\Condition;
19
use samsonframework\orm\ConditionInterface;
20
use samsonframework\orm\QueryInterface;
21
22
/**
23
 * Generic SamsonCMS Entity query.
24
 * @package samsoncms\api\query
25
 */
26
class Entity extends Generic
27
{
28
    /** @var array Collection of all additional fields names */
29
    public static $fieldNames = array();
30
31
    /** @var array Collection of localized additional fields identifiers */
32
    protected static $localizedFieldIDs = array();
33
34
    /** @var array Collection of NOT localized additional fields identifiers */
35
    protected static $notLocalizedFieldIDs = array();
36
37
    /** @var array Collection of all additional fields identifiers */
38
    protected static $fieldIDs = array();
39
40
    /** @var  @var array Collection of additional fields value column names */
41
    protected static $fieldValueColumns = array();
42
43
    /** @var Condition Collection of entity field filter */
44
    protected $fieldFilter = array();
45
46
    /** @var string Query locale */
47
    protected $locale = '';
48
49
    /** @var array Collection of additional fields for ordering */
50
    protected $entityOrderBy = array();
51
52
    /** @var array Collection of search fields for query */
53
    protected $searchFilter = array();
54
55
    /**
56
     * Select specified entity fields.
57
     * If this method is called then only selected entity fields
58
     * would be return in entity instances.
59
     *
60
     * @param mixed $fieldNames Entity field name or collection of names
61
     * @return $this Chaining
62
     */
63
    public function select($fieldNames)
64
    {
65
        // Convert argument to array and iterate
66
        foreach ((!is_array($fieldNames) ? array($fieldNames) : $fieldNames) as $fieldName) {
67
            // Try to find entity additional field
68
            $pointer = &static::$fieldNames[$fieldName];
69
            if (null !== $pointer) {
70
                // Store selected additional field buy FieldID and Field name
71
                $this->selectedFields[$pointer] = $fieldName;
72
            }
73
        }
74
75
        return $this;
76
    }
77
78
    /**
79
     * Set additional field for sorting.
80
     *
81
     * @param string $fieldName Additional field name
82
     * @param string $order Sorting order
83
     * @return $this Chaining
84
     */
85
    public function orderBy($fieldName, $order = 'ASC')
86
    {
87
        if (array_key_exists($fieldName, static::$fieldNames)) {
88
            $this->entityOrderBy = array($fieldName, $order);
89
        } else {
90
            parent::orderBy($fieldName, $order);
91
        }
92
93
        return $this;
94
    }
95
96
    /**
97
     * Search entity fields by text.
98
     *
99
     * @param string $text Searching text
100
     * @return $this
101
     */
102
    public function search($text)
103
    {
104
        $this->searchFilter[] = $text;
105
106
        return $this;
107
    }
108
109
    /**
110
     * Set resulting query limits.
111
     *
112
     * @param integer $offset Starting index
113
     * @param integer|null $count Entities count
114
     * @return $this Chaining
115
     */
116
    public function limit($offset, $count = null)
117
    {
118
        $this->limit = array($offset, $count);
119
120
        return $this;
121
    }
122
123
    /**
124
     * Add condition to current query.
125
     *
126
     * @param string $fieldName Entity field name
127
     * @param string $fieldValue Value
128
     * @param string $fieldRelation Entity field to value relation
129
     * @return $this Chaining
130
     */
131
    public function where($fieldName, $fieldValue = null, $fieldRelation = ArgumentInterface::EQUAL)
132
    {
133
        // Try to find entity additional field
134
        $pointer = &static::$fieldNames[$fieldName];
135
        if (isset($pointer)) {
136
            // Store additional field filter value
137
            $this->fieldFilter[$pointer] = (new Condition())->add(static::$fieldValueColumns[$pointer], $fieldValue, $fieldRelation);
138
        } else {
139
            parent::where($fieldName, $fieldValue, $fieldRelation);
140
        }
141
142
        return $this;
143
    }
144
145
    /** @return array Collection of entity identifiers */
146
    protected function findEntityIDs()
147
    {
148
        $entityIDs = array();
149
        if ($this->conditions) {
150
            $entityIDs = $this->query
151
                ->entity(Material::ENTITY)
152
                ->whereCondition($this->conditions)
153
                ->fields(Material::F_PRIMARY);
154
        }
155
156
        // TODO: Find and describe approach with maximum generic performance
157
        $entityIDs = $this->findByAdditionalFields(
158
            $this->fieldFilter,
0 ignored issues
show
Documentation introduced by
$this->fieldFilter is of type object<samsonframework\orm\Condition>, but the function expects a array<integer,object<sam...amework\orm\Condition>>.

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...
159
            $this->findByNavigationIDs($entityIDs)
160
        );
161
162
        // Perform sorting if necessary
163
        if (count($this->entityOrderBy) === 2) {
164
            $entityIDs = $this->applySorting($entityIDs, $this->entityOrderBy[0], $this->entityOrderBy[1]);
165
        }
166
167
        // Perform limits if necessary
168
        if (count($this->limit)) {
169
            $entityIDs = array_slice($entityIDs, $this->limit[0], $this->limit[1]);
170
        }
171
172
        return $entityIDs;
173
    }
174
175
    /**
176
     * Get collection of entity identifiers filtered by navigation identifiers.
177
     *
178
     * @param array $entityIDs Additional collection of entity identifiers for filtering
179
     * @return array Collection of material identifiers by navigation identifiers
180
     */
181
    protected function findByNavigationIDs($entityIDs = array())
182
    {
183
        return (new MaterialNavigation($entityIDs))->idsByRelationID(static::$navigationIDs);
184
    }
185
186
    /**
187
     * Get collection of entity identifiers filtered by additional field and its value.
188
     *
189
     * @param Condition[] $additionalFields Collection of additional field identifiers => values
190
     * @param array $entityIDs Additional collection of entity identifiers for filtering
191
     * @return array Collection of material identifiers by navigation identifiers
192
     */
193
    protected function findByAdditionalFields($additionalFields, $entityIDs = array())
194
    {
195
        /**
196
         * TODO: We have separate request to materialfield for each field, maybe faster to
197
         * make one single query with all fields conditions. Performance tests are needed.
198
         */
199
200
        /** @var Condition $fieldCondition Iterate all additional fields needed for filter condition */
201
        foreach ($additionalFields as $fieldID => $fieldCondition) {
202
            // Get collection of entity identifiers passing already found identifiers
203
            $entityIDs = (new MaterialField($entityIDs))->idsByRelationID($fieldID, $fieldCondition, array());
0 ignored issues
show
Bug introduced by
The method idsByRelationID() does not seem to exist on object<samson\activerecord\MaterialField>.

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...
204
205
            // Stop execution if we have no entities found at this step
206
            if (!count($entityIDs)) {
207
                break;
208
            }
209
        }
210
211
        return $entityIDs;
212
    }
213
214
    /**
215
     * @param array $entityIDs
216
     * @return array
217
     */
218
    protected function applySearch(array $entityIDs)
219
    {
220
        $condition = new Condition(ConditionInterface::DISJUNCTION);
221
222
        foreach ($this->searchFilter as $searchText) {
223
            foreach (static::$fieldValueColumns as $fieldId => $fieldColumn) {
224
                $condition->addCondition((new Condition())
225
                    ->addArgument(new Argument($fieldColumn, '%' . $searchText . '%', ArgumentInterface::LIKE))
226
                    ->addArgument(new Argument(\samsoncms\api\MaterialField::F_FIELDID, $fieldId)));
227
            }
228
        }
229
230
        return $this->query
231
            ->entity(\samsoncms\api\MaterialField::class)
232
            ->whereCondition($condition)
233
            ->where(Material::F_PRIMARY, $entityIDs)
234
            ->fields(Material::F_PRIMARY);
235
    }
236
237
    /**
238
     * Add sorting to entity identifiers.
239
     *
240
     * @param array $entityIDs
241
     * @param string $fieldName Additional field name for sorting
242
     * @param string $order Sorting order(ASC|DESC)
243
     * @return array Collection of entity identifiers ordered by additional field value
244
     */
245
    protected function applySorting(array $entityIDs, $fieldName, $order = 'ASC')
246
    {
247
        // Get additional field metadata
248
        $fieldID = &static::$fieldNames[$fieldName];
249
        $valueColumn = &static::$fieldValueColumns[$fieldID];
250
251
        // If this is additional field
252
        if (null !== $fieldID && null !== $valueColumn) {
253
            return $this->query
254
                ->entity(CMS::MATERIAL_FIELD_RELATION_ENTITY)
255
                ->where(Field::F_PRIMARY, $fieldID)
256
                ->where(Material::F_PRIMARY, $entityIDs)
257
                ->orderBy($valueColumn, $order)
258
                ->fields(Material::F_PRIMARY);
259
        } else { // Nothing is changed
260
            return $entityIDs;
261
        }
262
    }
263
264
    /**
265
     * Get entities additional field values.
266
     *
267
     * @param array $entityIDs Collection of entity identifiers
268
     * @return array Collection of entities additional fields EntityID => [Additional field name => Value]
269
     */
270
    protected function findAdditionalFields($entityIDs)
271
    {
272
        $return = array();
273
274
        // Copy fields arrays
275
        $localized = static::$localizedFieldIDs;
276
        $notLocalized = static::$notLocalizedFieldIDs;
277
278
        // If we filter additional fields that we need to receive
279
        if (count($this->selectedFields)) {
280
            foreach ($this->selectedFields as $fieldID => $fieldName) {
281
                // Filter localized and not fields by selected fields
282
                if (!isset(static::$localizedFieldIDs[$fieldID])) {
283
                    unset($localized[$fieldID]);
284
                }
285
286
                if (!isset(static::$notLocalizedFieldIDs[$fieldID])) {
287
                    unset($notLocalized[$fieldID]);
288
                }
289
            }
290
        }
291
292
        // Prepare localized additional field query condition
293
        $condition = new Condition(Condition::DISJUNCTION);
294
        foreach ($localized as $fieldID => $fieldName) {
295
            $condition->addCondition(
296
                (new Condition())
297
                    ->add(Field::F_PRIMARY, $fieldID)
298
                    ->add(\samsoncms\api\MaterialField::F_LOCALE, $this->locale)
299
            );
300
        }
301
302
        // Prepare not localized fields condition
303
        foreach ($notLocalized as $fieldID => $fieldName) {
304
            $condition->add(Field::F_PRIMARY, $fieldID);
305
        }
306
307
        // Get additional fields values for current entity identifiers
308
        foreach ($this->query->entity(CMS::MATERIAL_FIELD_RELATION_ENTITY)
0 ignored issues
show
Bug introduced by
The expression $this->query->entity(\sa...DELETION, true)->exec() of type boolean|array<integer,ob...k\orm\RecordInterface>> is not guaranteed to be traversable. How about adding an additional type check?

There are different options of fixing this problem.

  1. If you want to be on the safe side, you can add an additional type-check:

    $collection = json_decode($data, true);
    if ( ! is_array($collection)) {
        throw new \RuntimeException('$collection must be an array.');
    }
    
    foreach ($collection as $item) { /** ... */ }
    
  2. If you are sure that the expression is traversable, you might want to add a doc comment cast to improve IDE auto-completion and static analysis:

    /** @var array $collection */
    $collection = json_decode($data, true);
    
    foreach ($collection as $item) { /** .. */ }
    
  3. Mark the issue as a false-positive: Just hover the remove button, in the top-right corner of this issue for more options.

Loading history...
Coding Style introduced by
Space found before closing bracket of FOREACH loop
Loading history...
309
                     ->where(Material::F_PRIMARY, $entityIDs)
310
                     ->whereCondition($condition)
311
                     ->where(Material::F_DELETION, true)
312
                     ->exec() as $additionalField
313
        ) {
314
            // Get needed metadata
315
            $fieldID = $additionalField[Field::F_PRIMARY];
316
            $materialID = $additionalField[Material::F_PRIMARY];
317
            $valueField = &static::$fieldValueColumns[$fieldID];
318
            $fieldName = &static::$fieldIDs[$fieldID];
319
320
            // Check if we have this additional field in this entity query
321
            if (null === $valueField || null === $fieldName) {
322
                throw new EntityFieldNotFound($fieldID);
323
            } else { // Add field value to result
324
                $fieldValue = $additionalField[$valueField];
325
                // Gather additional fields values by entity identifiers and field name
326
                $return[$materialID][$fieldName] = $fieldValue;
327
            }
328
        }
329
330
        return $return;
331
    }
332
333
    /**
334
     * Fill entity additional fields.
335
     *
336
     * @param Entity $entity Entity instance for filling
337
     * @param array $additionalFields Collection of additional field values
338
     * @return Entity With filled additional field values
339
     */
340
    protected function fillEntityFields($entity, array $additionalFields)
341
    {
342
        // If we have list of additional fields that we need
343
        $fieldIDs = count($this->selectedFields) ? $this->selectedFields : static::$fieldIDs;
344
345
        // Iterate all entity additional fields
346
        foreach ($fieldIDs as $variable) {
347
            // Set only existing additional fields
348
            $pointer = &$additionalFields[$entity[Material::F_PRIMARY]][$variable];
349
            if (isset($pointer)) {
350
                $entity->$variable = $pointer;
351
            }
352
        }
353
354
        return $entity;
355
    }
356
357
    /**
358
     * Perform SamsonCMS query and get collection of entities.
359
     *
360
     * @param int $page Page number
361
     * @param int $size Page size
362
     *
363
     * @return \samsoncms\api\Entity[] Collection of entity fields
364
     */
365
    public function find($page = null, $size = null)
366
    {
367
        $return = array();
368
        if (count($entityIDs = $this->findEntityIDs())) {
369
            $additionalFields = $this->findAdditionalFields($entityIDs);
370
371
            if (count($this->searchFilter)) {
372
                $entityIDs = $this->applySearch($entityIDs);
373
374
                // Return result if not ids
375
                if (count($entityIDs) === 0) {
376
                    return $return;
0 ignored issues
show
Bug Best Practice introduced by
The return type of return $return; (array) is incompatible with the return type of the parent method samsoncms\api\query\Generic::find of type boolean|samsonframework\orm\RecordInterface[].

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

Let’s take a look at an example:

class Author {
    private $name;

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

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

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

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

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

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

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

Loading history...
377
                }
378
            }
379
380
            // Slice identifier array to match pagination
381
            if (null !== $page && null !== $size) {
382
                $entityIDs = array_slice($entityIDs, ($page - 1) * $size, $size);
383
            }
384
385
            // Set entity primary keys
386
            $this->primary($entityIDs);
0 ignored issues
show
Documentation introduced by
$entityIDs is of type array, but the function expects a string.

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

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

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

function acceptsInteger($int) { }

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

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
387
388
            //elapsed('End fields values');
389
            /** @var \samsoncms\api\Entity $item Find entity instances */
390
            foreach (parent::find() as $item) {
0 ignored issues
show
Bug introduced by
The expression parent::find() of type boolean|array<integer,ob...k\orm\RecordInterface>> is not guaranteed to be traversable. How about adding an additional type check?

There are different options of fixing this problem.

  1. If you want to be on the safe side, you can add an additional type-check:

    $collection = json_decode($data, true);
    if ( ! is_array($collection)) {
        throw new \RuntimeException('$collection must be an array.');
    }
    
    foreach ($collection as $item) { /** ... */ }
    
  2. If you are sure that the expression is traversable, you might want to add a doc comment cast to improve IDE auto-completion and static analysis:

    /** @var array $collection */
    $collection = json_decode($data, true);
    
    foreach ($collection as $item) { /** .. */ }
    
  3. Mark the issue as a false-positive: Just hover the remove button, in the top-right corner of this issue for more options.

Loading history...
391
                $item = $this->fillEntityFields($item, $additionalFields);
392
393
                // Store entity by identifier
394
                $return[$item[Material::F_PRIMARY]] = $item;
395
            }
396
        }
397
398
        //elapsed('Finish SamsonCMS '.static::$identifier.' query');
399
400
        return $return;
0 ignored issues
show
Bug Best Practice introduced by
The return type of return $return; (array) is incompatible with the return type of the parent method samsoncms\api\query\Generic::find of type boolean|samsonframework\orm\RecordInterface[].

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

Let’s take a look at an example:

class Author {
    private $name;

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

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

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

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

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

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

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

Loading history...
401
    }
402
403
    /**
404
     * Perform SamsonCMS query and get first matching entity.
405
     *
406
     * @return \samsoncms\api\Entity Firt matching entity
407
     */
408
    public function first()
409
    {
410
        $return = array();
411
        if (count($entityIDs = $this->findEntityIDs())) {
412
            $this->primary($entityIDs);
0 ignored issues
show
Documentation introduced by
$entityIDs is of type array, but the function expects a string.

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

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

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

function acceptsInteger($int) { }

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

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
413
            $additionalFields = $this->findAdditionalFields($entityIDs);
414
            $return = $this->fillEntityFields(parent::first(), $additionalFields);
0 ignored issues
show
Documentation introduced by
parent::first() is of type object<samsoncms\api\Entity>|null, but the function expects a object<samsoncms\api\query\Entity>.

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...
415
        }
416
417
        return $return;
0 ignored issues
show
Bug Best Practice introduced by
The return type of return $return; (samsoncms\api\query\Entity|array) is incompatible with the return type of the parent method samsoncms\api\query\Generic::first of type samsoncms\api\Entity|null.

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

Let’s take a look at an example:

class Author {
    private $name;

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

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

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

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

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

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

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

Loading history...
418
    }
419
420
    /**
421
     * Perform SamsonCMS query and get collection of entities fields.
422
     *
423
     * @param string $fieldName Entity field name
424
     * @return array Collection of entity fields
425
     * @throws EntityFieldNotFound
426
     */
427
    public function fields($fieldName)
428
    {
429
        $return = array();
430
        if (count($entityIDs = $this->findEntityIDs())) {
431
            // Check if our entity has this field
432
            $fieldID = &static::$fieldNames[$fieldName];
433
            if (isset($fieldID)) {
434
                $return = $this->query
435
                    ->entity(\samsoncms\api\MaterialField::ENTITY)
436
                    ->where(Material::F_PRIMARY, $entityIDs)
437
                    ->where(Field::F_PRIMARY, $fieldID)
438
                    ->where(\samsoncms\api\MaterialField::F_DELETION, true)
439
                    ->fields(static::$fieldValueColumns[$fieldID]);
440
            } elseif (array_key_exists($fieldName, static::$parentFields)) {
441
                // TODO: Generalize real and virtual entity fields and manipulations with them
442
                // If this is parent field
443
                return parent::fields($fieldName);
444
            } else {
445
                throw new EntityFieldNotFound($fieldName);
446
            }
447
        }
448
449
        //elapsed('Finish SamsonCMS '.static::$identifier.' query');
450
451
        return $return;
452
    }
453
454
    /**
455
     * Perform SamsonCMS query and get amount resulting entities.
456
     *
457
     * @return int Amount of resulting entities
458
     */
459
    public function count()
460
    {
461
        $return = 0;
0 ignored issues
show
Bug Compatibility introduced by
The expression 0; of type integer adds the type integer to the return on line 467 which is incompatible with the return type of the parent method samsoncms\api\query\Generic::count of type boolean|samsonframework\orm\RecordInterface.
Loading history...
462
        if (count($entityIDs = $this->findEntityIDs())) {
463
            $this->primary($entityIDs);
0 ignored issues
show
Documentation introduced by
$entityIDs is of type array, but the function expects a string.

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

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

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

function acceptsInteger($int) { }

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

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
464
            $return = parent::count();
465
        }
466
467
        return $return;
468
    }
469
470
    /**
471
     * Generic constructor.
472
     *
473
     * @param QueryInterface $query Database query instance
474
     * @param string $locale Query localization
475
     */
476
    public function __construct(QueryInterface $query = null, $locale = null)
477
    {
478
        $this->locale = $locale;
479
480
        parent::__construct(null === $query ? new dbQuery() : $query);
481
482
        // Work only with active entities
483
        $this->active(true);
484
    }
485
}
486