Completed
Push — master ( 8e414f...89d22a )
by Vitaly
03:09
created

Generic::published()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 1
Metric Value
c 1
b 0
f 1
dl 0
loc 4
rs 10
cc 1
eloc 2
nc 1
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 samsonframework\orm\ArgumentInterface;
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 array Collection of all additional fields names */
39
    protected static $fieldNames = array();
40
41
    /** @var  @var array Collection of additional fields value column names */
42
    protected static $fieldValueColumns = array();
43
44
45
    /** @var array Collection selected additional entity fields */
46
    protected $selectedFields = array();
47
48
    /** @var array Collection of entity field filter */
49
    protected $fieldFilter = array();
50
51
    /** @var string Query locale */
52
    protected $locale = '';
53
54
    /**
55
     * Add identifier field query condition.
56
     *
57
     * @param string $value Field value
58
     * @return self Chaining
59
     * @see Generic::where()
60
     */
61
    public function identifier($value)
62
    {
63
        return $this->where(Material::F_IDENTIFIER, $value);
64
    }
65
66
    /**
67
     * Add entity published field query condition.
68
     *
69
     * @param string $value Field value
70
     * @return self Chaining
71
     * @see Generic::where()
72
     */
73
    public function published($value)
74
    {
75
        return $this->where(Material::F_PUBLISHED, $value);
76
    }
77
78
    /**
79
     * Add entity creation field query condition.
80
     *
81
     * @param string $value Field value
82
     * @param string $relation @see ArgumentInterface types
83
     * @return self Chaining
84
     * @see Generic::where()
85
     */
86
    public function created($value, $relation = ArgumentInterface::EQUAL)
87
    {
88
        return $this->where(Material::F_CREATED, $value, $relation);
89
    }
90
91
    /**
92
     * Add entity modification field query condition.
93
     *
94
     * @param string $value Field value
95
     * @param string $relation @see ArgumentInterface types
96
     * @return self Chaining
97
     * @see Generic::where()
98
     */
99
    public function modified($value, $relation = ArgumentInterface::EQUAL)
100
    {
101
        return $this->where(Material::F_MODIFIED, $value, $relation);
102
    }
103
104
    /**
105
     * Select specified entity fields.
106
     * If this method is called then only selected entity fields
107
     * would be return in entity instances.
108
     *
109
     * @param mixed $fieldNames Entity field name or collection of names
110
     * @return self Chaining
111
     */
112
    public function select($fieldNames)
113
    {
114
        // Convert argument to array and iterate
115
        foreach ((!is_array($fieldNames) ? array($fieldNames) : $fieldNames) as $fieldName) {
116
            // Try to find entity additional field
117
            $pointer = &static::$fieldNames[$fieldName];
118
            if (isset($pointer)) {
119
                // Store selected additional field buy FieldID and Field name
120
                $this->selectedFields[$pointer] = $fieldName;
121
            }
122
        }
123
124
        return $this;
125
    }
126
127
    /**
128
     * Add condition to current query.
129
     *
130
     * @param string $fieldName Entity field name
131
     * @param string $fieldValue Value
132
     * @return self Chaining
133
     */
134
    public function where($fieldName, $fieldValue = null, $fieldRelation = ArgumentInterface::EQUAL)
0 ignored issues
show
Unused Code introduced by
The parameter $fieldRelation is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
135
    {
136
        // Try to find entity additional field
137
        $pointer = &static::$fieldNames[$fieldName];
138
        if (isset($pointer)) {
139
            // Store additional field filter value
140
            $this->fieldFilter[$pointer] = $fieldValue;
141
        }
142
143
        return $this;
144
    }
145
146
    /**
147
     * Get collection of entity identifiers filtered by navigation identifiers.
148
     *
149
     * @param array $entityIDs Additional collection of entity identifiers for filtering
150
     * @return array Collection of material identifiers by navigation identifiers
151
     */
152
    protected function findByNavigationIDs($entityIDs = array())
153
    {
154
        return (new MaterialNavigation($entityIDs))->idsByRelationID(static::$navigationIDs);
155
    }
156
157
    /**
158
     * Get collection of entity identifiers filtered by additional field and its value.
159
     *
160
     * @param array $additionalFields Collection of additional field identifiers => values
161
     * @param array $entityIDs Additional collection of entity identifiers for filtering
162
     * @return array Collection of material identifiers by navigation identifiers
163
     */
164
    protected function findByAdditionalFields($additionalFields, $entityIDs = array())
165
    {
166
        // Iterate all additional fields needed for filter entity
167
        foreach ($additionalFields as $fieldID => $fieldValue) {
168
            // Get collection of entity identifiers passing already found identifiers
169
            $entityIDs = (new MaterialField($entityIDs))->idsByRelationID($fieldID, $fieldValue);
170
171
            // Stop execution if we have no entities found at this step
172
            if (!sizeof($entityIDs)) {
173
                break;
174
            }
175
        }
176
177
        return $entityIDs;
178
    }
179
180
    /**
181
     * Get entities additional field values.
182
     *
183
     * @param array $entityIDs Collection of entity identifiers
184
     * @return array Collection of entities additional fields EntityID => [Additional field name => Value]
185
     */
186
    protected function findAdditionalFields($entityIDs)
187
    {
188
        $return = array();
189
190
        // Copy fields arrays
191
        $localized = static::$localizedFieldIDs;
192
        $notLocalized = static::$notLocalizedFieldIDs;
193
194
        // If we filter additional fields that we need to receive
195
        if (sizeof($this->selectedFields)) {
196
            foreach ($this->selectedFields as $fieldID => $fieldName) {
197
                // Filter localized and not fields by selected fields
198
                if (!isset(static::$localizedFieldIDs[$fieldID])) {
199
                    unset($localized[$fieldID]);
200
                }
201
202
                if (!isset(static::$notLocalizedFieldIDs[$fieldID])) {
203
                    unset($notLocalized[$fieldID]);
204
                }
205
            }
206
        }
207
208
        // Prepare localized additional field query condition
209
        $condition = new Condition(Condition::DISJUNCTION);
210
        foreach ($localized as $fieldID => $fieldName) {
211
            $condition->addCondition(
212
                (new Condition())
213
                ->add(Field::F_PRIMARY, $fieldID)
214
                ->add(Field::F_LOCALIZED, $this->locale)
215
            );
216
        }
217
218
        // Prepare not localized fields condition
219
        foreach ($notLocalized as $fieldID => $fieldName) {
220
            $condition->add(Field::F_PRIMARY, $fieldID);
221
        }
222
223
        // Get additional fields values for current entity identifiers
224
        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...
225
                     ->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...
226
                     ->whereCondition($condition)
227
                     ->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...
228
                     ->exec() as $additionalField
229
        ) {
230
            // Get needed metadata
231
            $fieldID = $additionalField[Field::F_PRIMARY];
232
            $materialID = $additionalField[Material::F_PRIMARY];
233
            $valueField = static::$fieldValueColumns[$fieldID];
234
            $fieldName = static::$fieldIDs[$fieldID];
235
            $fieldValue = $additionalField[$valueField];
236
237
            // Gather additional fields values by entity identifiers and field name
238
            $return[$materialID][$fieldName] = $fieldValue;
239
        }
240
241
        return $return;
242
    }
243
244
    /**
245
     * Perform SamsonCMS query and get entities collection.
246
     *
247
     * @return mixed[] Collection of found entities
248
     */
249
    public function find()
250
    {
251
        //elapsed('Start SamsonCMS '.static::$identifier.' query');
252
        // TODO: Find and describe approach with maximum generic performance
253
        $entityIDs = $this->findByNavigationIDs();
254
        //elapsed('End navigation filter');
255
        $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...
256
        //elapsed('End fields filter');
257
258
        $return = array();
259
        if (sizeof($entityIDs)) {
260
            $additionalFields = $this->findAdditionalFields($entityIDs);
261
            //elapsed('End fields values');
262
            /** @var \samsoncms\api\Entity $item Find entity instances */
263
            foreach ((new \samsoncms\api\query\Material(static::$identifier))->byIDs($entityIDs, 'exec') as $item) {
264
                // If we have list of additional fields that we need
265
                $fieldIDs = sizeof($this->selectedFields) ? $this->selectedFields : static::$fieldIDs;
266
267
                // Iterate all entity additional fields
268
                foreach ($fieldIDs as $variable) {
269
                    // Set only existing additional fields
270
                    $pointer = &$additionalFields[$item[Material::F_PRIMARY]][$variable];
271
                    if (isset($pointer)) {
272
                        $item->$variable = $pointer;
273
                    }
274
                }
275
                // Store entity by identifier
276
                $return[$item[Material::F_PRIMARY]] = $item;
277
            }
278
        }
279
280
        //elapsed('Finish SamsonCMS '.static::$identifier.' query');
281
282
        return $return;
283
    }
284
285
    /**
286
     * Generic constructor.
287
     * @param string $locale Query localizaation
288
     */
289
    public function __construct($locale = '')
290
    {
291
        $this->locale = $locale;
292
    }
293
}
294