Completed
Push — master ( 8d12dc...1ef7f8 )
by Vitaly
04:50
created

Generic   A

Complexity

Total Complexity 24

Size/Duplication

Total Lines 220
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 6

Importance

Changes 9
Bugs 1 Features 3
Metric Value
wmc 24
c 9
b 1
f 3
lcom 1
cbo 6
dl 0
loc 220
rs 10

7 Methods

Rating   Name   Duplication   Size   Complexity  
A select() 0 14 4
A where() 0 11 2
A findByNavigationIDs() 0 4 1
A findByAdditionalFields() 0 15 3
B findAdditionalFields() 0 57 8
B find() 0 32 5
A __construct() 0 4 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 samsonframework\orm\Condition;
14
use samsonframework\orm\Query;
15
16
/**
17
 * Material with additional fields query.
18
 * @package samsoncms\api
19
 */
20
class Generic
21
{
22
    /** @var string Entity identifier */
23
    protected static $identifier;
24
25
    /** @var string Entity navigation identifiers */
26
    protected static $navigationIDs = array();
27
28
    /** @var array Collection of localized additional fields identifiers */
29
    protected static $localizedFieldIDs = array();
30
31
    /** @var array Collection of NOT localized additional fields identifiers */
32
    protected static $notLocalizedFieldIDs = array();
33
34
    /** @var array Collection of all additional fields identifiers */
35
    protected static $fieldIDs = array();
36
37
    /** @var array Collection of all additional fields names */
38
    protected static $fieldNames = array();
39
40
    /** @var  @var array Collection of additional fields value column names */
41
    protected static $fieldValueColumns = array();
42
43
44
    /** @var array Collection selected additional entity fields */
45
    protected $selectedFields = array();
46
47
    /** @var array Collection of entity field filter */
48
    protected $fieldFilter = array();
49
50
    /** @var string Query locale */
51
    protected $locale = '';
52
53
    /**
54
     * Select specified entity fields.
55
     * If this method is called then only selected entity fields
56
     * would be return in entity instances.
57
     *
58
     * @param mixed $fieldNames Entity field name or collection of names
59
     * @return self Chaining
60
     */
61
    public function select($fieldNames)
62
    {
63
        // Convert argument to array and iterate
64
        foreach ((!is_array($fieldNames) ? array($fieldNames) : $fieldNames) as $fieldName) {
65
            // Try to find entity additional field
66
            $pointer = &static::$fieldNames[$fieldName];
67
            if (isset($pointer)) {
68
                // Store selected additional field buy FieldID and Field name
69
                $this->selectedFields[$pointer] = $fieldName;
70
            }
71
        }
72
73
        return $this;
74
    }
75
76
    /**
77
     * Add condition to current query.
78
     *
79
     * @param string $fieldName Entity field name
80
     * @param string $fieldValue Value
81
     * @return self Chaining
82
     */
83
    public function where($fieldName, $fieldValue = null)
84
    {
85
        // Try to find entity additional field
86
        $pointer = &static::$fieldNames[$fieldName];
87
        if (isset($pointer)) {
88
            // Store additional field filter value
89
            $this->fieldFilter[$pointer] = $fieldValue;
90
        }
91
92
        return $this;
93
    }
94
95
    /**
96
     * Get collection of entity identifiers filtered by navigation identifiers.
97
     *
98
     * @param array $entityIDs Additional collection of entity identifiers for filtering
99
     * @return array Collection of material identifiers by navigation identifiers
100
     */
101
    protected function findByNavigationIDs($entityIDs = array())
102
    {
103
        return (new MaterialNavigation($entityIDs))->idsByRelationID(static::$navigationIDs);
104
    }
105
106
    /**
107
     * Get collection of entity identifiers filtered by additional field and its value.
108
     *
109
     * @param array $additionalFields Collection of additional field identifiers => values
110
     * @param array $entityIDs Additional collection of entity identifiers for filtering
111
     * @return array Collection of material identifiers by navigation identifiers
112
     */
113
    protected function findByAdditionalFields($additionalFields, $entityIDs = array())
114
    {
115
        // Iterate all additional fields needed for filter entity
116
        foreach ($additionalFields as $fieldID => $fieldValue) {
117
            // Get collection of entity identifiers passing already found identifiers
118
            $entityIDs = (new MaterialField($entityIDs))->idsByRelationID($fieldID, $fieldValue);
119
120
            // Stop execution if we have no entities found at this step
121
            if (!sizeof($entityIDs)) {
122
                break;
123
            }
124
        }
125
126
        return $entityIDs;
127
    }
128
129
    /**
130
     * Get entities additional field values.
131
     *
132
     * @param array $entityIDs Collection of entity identifiers
133
     * @return array Collection of entities additional fields EntityID => [Additional field name => Value]
134
     */
135
    protected function findAdditionalFields($entityIDs)
136
    {
137
        $return = array();
138
139
        // Copy fields arrays
140
        $localized = static::$localizedFieldIDs;
141
        $notLocalized = static::$notLocalizedFieldIDs;
142
143
        // If we filter additional fields that we need to receive
144
        if (sizeof($this->selectedFields)) {
145
            foreach ($this->selectedFields as $fieldID => $fieldName) {
146
                // Filter localized and not fields by selected fields
147
                if (!isset(static::$localizedFieldIDs[$fieldID])) {
148
                    unset($localized[$fieldID]);
149
                }
150
151
                if (!isset(static::$notLocalizedFieldIDs[$fieldID])) {
152
                    unset($notLocalized[$fieldID]);
153
                }
154
            }
155
        }
156
157
        // Prepare localized additional field query condition
158
        $condition = new Condition(Condition::DISJUNCTION);
159
        foreach ($localized as $fieldID => $fieldName) {
160
            $condition->addCondition(
161
                (new Condition())
162
                ->add(Field::F_PRIMARY, $fieldID)
163
                ->add(Field::F_LOCALIZED, $this->locale)
164
            );
165
        }
166
167
        // Prepare not localized fields condition
168
        foreach ($notLocalized as $fieldID => $fieldName) {
169
            $condition->add(Field::F_PRIMARY, $fieldID);
170
        }
171
172
        // Get additional fields values for current entity identifiers
173
        foreach ((new dbQuery())->entity(\samsoncms\api\MaterialField::ENTITY)
0 ignored issues
show
Coding Style introduced by
Space found before closing bracket of FOREACH loop
Loading history...
174
                     ->where(Material::F_PRIMARY, $entityIDs)
0 ignored issues
show
Documentation introduced by
$entityIDs is of type array, 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...
175
                     ->whereCondition($condition)
176
                     ->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...
177
                     ->exec() as $additionalField
178
        ) {
179
            // Get needed metadata
180
            $fieldID = $additionalField[Field::F_PRIMARY];
181
            $materialID = $additionalField[Material::F_PRIMARY];
182
            $valueField = static::$fieldValueColumns[$fieldID];
183
            $fieldName = static::$fieldIDs[$fieldID];
184
            $fieldValue = $additionalField[$valueField];
185
186
            // Gather additional fields values by entity identifiers and field name
187
            $return[$materialID][$fieldName] = $fieldValue;
188
        }
189
190
        return $return;
191
    }
192
193
    /**
194
     * Perform SamsonCMS query and get entities collection.
195
     *
196
     * @return mixed[] Collection of found entities
197
     */
198
    public function find()
199
    {
200
        //elapsed('Start SamsonCMS '.static::$identifier.' query');
201
        // TODO: Find and describe approach with maximum generic performance
202
        $entityIDs = $this->findByNavigationIDs();
203
        //elapsed('End navigation filter');
204
        $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...
205
        //elapsed('End fields filter');
206
207
        $return = array();
208
        if (sizeof($entityIDs)) {
209
            $additionalFields = $this->findAdditionalFields($entityIDs);
210
            //elapsed('End fields values');
211
            /** @var \samsoncms\api\Entity $item Find entity instances */
212
            foreach ((new \samsoncms\api\query\Material(static::$identifier))->byIDs($entityIDs, 'exec') as $item) {
213
                // Iterate all entity additional fields
214
                foreach (static::$fieldIDs as $fieldID => $variable) {
215
                    // Set only existing additional fields
216
                    $pointer = &$additionalFields[$item[Material::F_PRIMARY]][$variable];
217
                    if (isset($pointer)) {
218
                        $item->$variable = $pointer;
219
                    }
220
                }
221
                // Store entity by identifier
222
                $return[$item[Material::F_PRIMARY]] = $item;
223
            }
224
        }
225
226
        //elapsed('Finish SamsonCMS '.static::$identifier.' query');
227
228
        return $return;
229
    }
230
231
    /**
232
     * Generic constructor.
233
     * @param string $locale Query localizaation
234
     */
235
    public function __construct($locale = '')
236
    {
237
        $this->locale = $locale;
238
    }
239
}
240