Completed
Push — master ( 111c7d...cc6796 )
by Vitaly
02:51
created

Generic::findAdditionalFields()   B

Complexity

Conditions 4
Paths 8

Size

Total Lines 38
Code Lines 22

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 0 Features 1
Metric Value
c 2
b 0
f 1
dl 0
loc 38
rs 8.5806
cc 4
eloc 22
nc 8
nop 1
1
<?php
2
/**
3
 * Created by PhpStorm.
4
 * User: VITALYIEGOROV
5
 * Date: 08.12.15
6
 * Time: 23:11
7
 */
8
namespace samsoncms\api\query;
9
10
use samson\activerecord\dbQuery;
11
use samsoncms\api\Field;
12
use samsoncms\api\Material;
0 ignored issues
show
Bug introduced by
This use statement conflicts with another class in this namespace, samsoncms\api\query\Material.

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...
13
use samsoncms\api\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...
14
use samsonframework\orm\Condition;
15
use samsonframework\orm\Query;
16
17
/**
18
 * Material with additional fields query.
19
 * @package samsoncms\api
20
 */
21
class Generic
22
{
23
    /** @var string Entity identifier */
24
    protected static $identifier;
25
26
    /** @var string Entity navigation identifiers */
27
    protected static $navigationIDs = array();
28
29
    /** @var array Collection of localized additional fields identifiers */
30
    protected static $localizedFieldIDs = array();
31
32
    /** @var array Collection of NOT localized additional fields identifiers */
33
    protected static $notLocalizedFieldIDs = array();
34
35
    /** @var array Collection of all additional fields identifiers */
36
    protected static $fieldIDs = array();
37
38
    /** @var  @var array Collection of additional fields value column names */
39
    protected static $fieldValueColumns = array();
40
41
42
    /** @var array Collection of entity field filter */
43
    protected $fieldFilter = array();
44
45
    /** @var string Query locale */
46
    protected $locale = '';
47
48
    /**
49
     * Add condition to current query.
50
     *
51
     * @param string $fieldName Entity field name
52
     * @param string $fieldValue Value
53
     * @return self Chaining
54
     */
55
    public function where($fieldName, $fieldValue = null)
56
    {
57
        // Try to find entity additional field
58
        if (property_exists(static::$identifier, $fieldName)) {
59
            // Store additional field filter value
60
            $this->fieldFilter[$fieldName] = $fieldValue;
61
        }
62
63
        return $this;
64
    }
65
66
    /**
67
     * Get collection of entity identifiers filtered by navigation identifiers.
68
     *
69
     * @param array $entityIDs Additional collection of entity identifiers for filtering
70
     * @return array Collection of material identifiers by navigation identifiers
71
     */
72
    protected function findByNavigationIDs($entityIDs = array())
73
    {
74
        return (new MaterialNavigation($entityIDs))->idsByRelationID(static::$navigationIDs);
75
    }
76
77
    /**
78
     * Get collection of entity identifiers filtered by additional field and its value.
79
     *
80
     * @param array $additionalFields Collection of additional field identifiers => values
81
     * @param array $entityIDs Additional collection of entity identifiers for filtering
82
     * @return array Collection of material identifiers by navigation identifiers
83
     */
84
    protected function findByAdditionalFields($additionalFields, $entityIDs = array())
85
    {
86
        // Iterate all additional fields needed for filter entity
87
        foreach ($additionalFields as $fieldID => $fieldValue) {
88
            // Get collection of entity identifiers passing already found identifiers
89
            $entityIDs = (new MaterialField($entityIDs))->idsByRelationID($fieldID, $fieldValue);
0 ignored issues
show
Bug introduced by
The method idsByRelationID() does not seem to exist on object<samsoncms\api\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...
90
91
            // Stop execution if we have no entities found at this step
92
            if (!sizeof($entityIDs)) {
93
                break;
94
            }
95
        }
96
97
        return $entityIDs;
98
    }
99
100
    protected function findAdditionalFields($entityIDs)
101
    {
102
        $return = array();
103
104
        // Prepare localized additional field query condition
105
        $condition = new Condition(Condition::DISJUNCTION);
106
        foreach (static::$localizedFieldIDs as $fieldID => $fieldName) {
107
            $condition->addCondition(
108
                (new Condition())
109
                ->add(Field::F_PRIMARY, $fieldID)
110
                ->add(Field::F_LOCALIZED, $this->locale)
111
            );
112
        }
113
114
        // Prepare not localized fields condition
115
        foreach (static::$notLocalizedFieldIDs as $fieldID => $fieldName) {
116
            $condition->add(Field::F_PRIMARY, $fieldID);
117
        }
118
119
        // Get additional fields values for current entity identifiers
120
        foreach ((new dbQuery())->entity(MaterialField::ENTITY)
0 ignored issues
show
Coding Style introduced by
Space found before closing bracket of FOREACH loop
Loading history...
121
                     ->where(Material::F_PRIMARY, $entityIDs)
122
                     ->whereCondition($condition)
123
                     ->where(Material::F_DELETION, true)
0 ignored issues
show
Documentation introduced by
true is of type boolean, but the function expects a string|null.

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...
124
                     ->exec() as $additionalField
125
        ) {
126
            $fieldID = $additionalField[Field::F_PRIMARY];
127
            $materialID = $additionalField[Material::F_PRIMARY];
128
            $valueField = static::$fieldValueColumns[$fieldID];
129
            $fieldName = static::$fieldIDs[$fieldID];
130
            $fieldValue = $additionalField[$valueField];
131
132
            // Gather additional fields values by entity identifiers and field name
133
            $return[$materialID][$fieldName] = $fieldValue;
134
        }
135
136
        return $return;
137
    }
138
139
    /**
140
     * Perform SamsonCMS query and get entities collection.
141
     *
142
     * @return mixed[] Collection of found entities
143
     */
144
    public function find()
145
    {
146
        // TODO: Find and describe approach with maximum generic performance
147
        $entityIDs = $this->findByNavigationIDs();
148
        $entityIDs = $this->findByAdditionalFields($this->fieldFilter, $entityIDs);
0 ignored issues
show
Documentation introduced by
$entityIDs is of type boolean|object<samsonfra...rk\orm\RecordInterface>, but the function expects a array.

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

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

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

function acceptsInteger($int) { }

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

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
149
150
        $return = array();
151
        if (sizeof($entityIDs)) {
152
            $additionalFields = $this->findAdditionalFields($entityIDs);
153
            /** @var \samsoncms\api\Entity $item Find entity instances */
154
            foreach ((new \samsoncms\api\query\Material(static::$identifier))->byIDs($entityIDs, 'exec') as $item) {
155
                // Iterate all entity additional fields
156
                foreach (static::$fieldIDs as $fieldID => $variable) {
157
                    // Set only existing additional fields
158
                    $pointer = &$additionalFields[$item[Material::F_PRIMARY]][$variable];
159
                    if (isset($pointer)) {
160
                        $item->$variable = $pointer;
161
                    }
162
                }
163
                // Store entity by identifier
164
                $return[$item[Material::F_PRIMARY]] = $item;
165
            }
166
        }
167
168
        return $return;
169
    }
170
171
    /**
172
     * Generic constructor.
173
     * @param string $locale Query localizaation
174
     */
175
    public function __construct($locale = '')
176
    {
177
        $this->locale = $locale;
178
    }
179
}
180