Completed
Push — master ( af05a7...eda6ec )
by Nekrasov
02:11
created

ElementQuery::groupBy()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 6
Code Lines 3

Duplication

Lines 0
Ratio 0 %
Metric Value
dl 0
loc 6
rs 9.4286
cc 1
eloc 3
nc 1
nop 1
1
<?php
2
3
namespace Arrilot\BitrixModels\Queries;
4
5
use Arrilot\BitrixModels\Collection;
6
use Arrilot\BitrixModels\Models\ElementModel;
7
use CIBlock;
8
use Exception;
9
10
/**
11
 * @method ElementQuery sortByDate(string $sort = 'desc')
12
 */
13
class ElementQuery extends BaseQuery
14
{
15
    /**
16
     * CIblock object or test double.
17
     *
18
     * @var object.
19
     */
20
    public static $cIblockObject;
21
22
    /**
23
     * Query sort.
24
     *
25
     * @var array
26
     */
27
    public $sort = ['SORT' => 'ASC'];
28
29
    /**
30
     * Query group by.
31
     *
32
     * @var array
33
     */
34
    public $groupBy = false;
35
36
    /**
37
     * Iblock id.
38
     *
39
     * @var int
40
     */
41
    protected $iblockId;
42
43
    /**
44
     * List of standard entity fields.
45
     *
46
     * @var array
47
     */
48
    protected $standardFields = [
49
        'ID',
50
        'TIMESTAMP_X',
51
        'TIMESTAMP_X_UNIX',
52
        'MODIFIED_BY',
53
        'DATE_CREATE',
54
        'DATE_CREATE_UNIX',
55
        'CREATED_BY',
56
        'IBLOCK_ID',
57
        'IBLOCK_SECTION_ID',
58
        'ACTIVE',
59
        'ACTIVE_FROM',
60
        'ACTIVE_TO',
61
        'SORT',
62
        'NAME',
63
        'PREVIEW_PICTURE',
64
        'PREVIEW_TEXT',
65
        'PREVIEW_TEXT_TYPE',
66
        'DETAIL_PICTURE',
67
        'DETAIL_TEXT',
68
        'DETAIL_TEXT_TYPE',
69
        'SEARCHABLE_CONTENT',
70
        'IN_SECTIONS',
71
        'SHOW_COUNTER',
72
        'SHOW_COUNTER_START',
73
        'CODE',
74
        'TAGS',
75
        'XML_ID',
76
        'EXTERNAL_ID',
77
        'TMP_ID',
78
        'CREATED_USER_NAME',
79
        'DETAIL_PAGE_URL',
80
        'LIST_PAGE_URL',
81
        'CREATED_DATE',
82
    ];
83
84
    /**
85
     * Method that is used to fetch getList results.
86
     * Available values: 'getNext' or 'getNextElement'.
87
     *
88
     * @var string
89
     */
90
    protected $fetchUsing = 'getNextElement';
91
92
    /**
93
     * Constructor.
94
     *
95
     * @param object $bxObject
96
     * @param string $modelName
97
     */
98
    public function __construct($bxObject, $modelName)
99
    {
100
        static::instantiateCIblockObject();
101
102
        parent::__construct($bxObject, $modelName);
103
104
        $this->iblockId = $modelName::iblockId();
105
        $this->fetchUsing = $modelName::$fetchUsing;
106
    }
107
108
    /**
109
     * Instantiate bitrix entity object.
110
     *
111
     * @throws Exception
112
     *
113
     * @return object
114
     */
115
    public static function instantiateCIblockObject()
116
    {
117
        if (static::$cIblockObject) {
118
            return static::$cIblockObject;
119
        }
120
121
        if (class_exists('CIblock')) {
122
            return static::$cIblockObject = new CIblock();
123
        }
124
125
        throw new Exception('CIblock object initialization failed');
126
    }
127
128
    /**
129
     * Setter for groupBy.
130
     *
131
     * @param $value
132
     *
133
     * @return $this
134
     */
135
    public function groupBy($value)
136
    {
137
        $this->groupBy = $value;
138
139
        return $this;
140
    }
141
142
    /**
143
     * Setter for fetchUsing.
144
     *
145
     * @param string $fetchUsing
146
     *
147
     * @return $this
148
     */
149
    public function fetchUsing($fetchUsing)
150
    {
151
        $this->fetchUsing = $fetchUsing;
152
153
        return $this;
154
    }
155
156
    /**
157
     * Get list of items.
158
     *
159
     * @return Collection
160
     */
161
    public function getList()
162
    {
163
        if ($this->queryShouldBeStopped) {
164
            return new Collection();
165
        }
166
167
        $items = [];
168
169
        $rsItems = $this->bxObject->getList(
170
            $this->sort,
171
            $this->normalizeFilter(),
172
            $this->groupBy,
173
            $this->navigation,
174
            $this->normalizeSelect()
175
        );
176
177
        if ($this->shouldBeFetchedUsingGetNext()) {
178
            while ($arItem = $rsItems->getNext()) {
179
                $this->addItemToResultsUsingKeyBy($items, new $this->modelName($arItem['ID'], $arItem));
180
            }
181
        } else {
182
            while ($obItem = $rsItems->getNextElement()) {
183
                $arItem = $obItem->getFields();
184
                if ($this->propsMustBeSelected()) {
185
                    $arItem['PROPERTIES'] = $obItem->getProperties();
186
                    $this->normalizePropertyResultFormat($arItem);
187
                }
188
189
                $this->addItemToResultsUsingKeyBy($items, new $this->modelName($arItem['ID'], $arItem));
190
            }
191
        }
192
193
        return new Collection($items);
194
    }
195
196
    /**
197
     * Get the first element with a given code.
198
     *
199
     * @param string $code
200
     *
201
     * @return ElementModel
202
     */
203
    public function getByCode($code)
204
    {
205
        $this->filter['CODE'] = $code;
206
207
        return $this->first();
208
    }
209
210
    /**
211
     * Get the first element with a given external id.
212
     *
213
     * @param string $id
214
     *
215
     * @return ElementModel
216
     */
217
    public function getByExternalId($id)
218
    {
219
        $this->filter['EXTERNAL_ID'] = $id;
220
221
        return $this->first();
222
    }
223
224
    /**
225
     * Get count of elements that match $filter.
226
     *
227
     * @return int
228
     */
229
    public function count()
230
    {
231
        if ($this->queryShouldBeStopped) {
232
            return 0;
233
        }
234
235
        return (int) $this->bxObject->getList(false, $this->normalizeFilter(), []);
236
    }
237
238
    /**
239
     * Normalize properties's format converting it to 'PROPERTY_"CODE"_VALUE'.
240
     *
241
     * @param array $fields
242
     *
243
     * @return null
244
     */
245
    protected function normalizePropertyResultFormat(&$fields)
246
    {
247
        if (empty($fields['PROPERTIES'])) {
248
            return;
249
        }
250
251
        foreach ($fields['PROPERTIES'] as $code => $prop) {
252
            $fields['PROPERTY_'.$code.'_VALUE'] = $prop['VALUE'];
253
            $fields['~PROPERTY_'.$code.'_VALUE'] = $prop['~VALUE'];
254
            $fields['PROPERTY_'.$code.'_DESCRIPTION'] = $prop['DESCRIPTION'];
255
            $fields['~PROPERTY_'.$code.'_DESCRIPTION'] = $prop['~DESCRIPTION'];
256
            $fields['PROPERTY_'.$code.'_VALUE_ID'] = $prop['PROPERTY_VALUE_ID'];
257
            if (isset($prop['VALUE_ENUM_ID'])) {
258
                $fields['PROPERTY_'.$code.'_ENUM_ID'] = $prop['VALUE_ENUM_ID'];
259
            }
260
        }
261
    }
262
263
    /**
264
     * Normalize filter before sending it to getList.
265
     * This prevents some inconsistency.
266
     *
267
     * @return array
268
     */
269
    protected function normalizeFilter()
270
    {
271
        $this->filter['IBLOCK_ID'] = $this->iblockId;
272
273
        return $this->filter;
274
    }
275
276
    /**
277
     * Normalize select before sending it to getList.
278
     * This prevents some inconsistency.
279
     *
280
     * @return array
281
     */
282 View Code Duplication
    protected function normalizeSelect()
0 ignored issues
show
Duplication introduced by
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...
283
    {
284
        if ($this->fieldsMustBeSelected()) {
285
            $this->select = array_merge($this->standardFields, $this->select);
286
        }
287
288
        if ($this->propsMustBeSelected() && $this->shouldBeFetchedUsingGetNext()) {
289
            $this->addAllPropsToSelect();
290
        }
291
292
        $this->select[] = 'ID';
293
        $this->select[] = 'IBLOCK_ID';
294
295
        return $this->clearSelectArray();
296
    }
297
298
    /**
299
     * Add all iblock property codes to select.
300
     *
301
     * return null
302
     */
303
    protected function addAllPropsToSelect()
304
    {
305
        $this->select[] = 'ID';
306
        $this->select[] = 'IBLOCK_ID';
307
308
        $rsProps = static::$cIblockObject->getProperties($this->iblockId);
309
        while ($prop = $rsProps->fetch()) {
310
            $this->select[] = 'PROPERTY_'.$prop['CODE'];
311
        }
312
    }
313
314
    /**
315
     * Determine if we should fetch using GetNext() method.
316
     *
317
     * @return bool
318
     */
319
    protected function shouldBeFetchedUsingGetNext()
320
    {
321
        return $this->fetchUsing === 'getNext' || $this->fetchUsing === 'GetNext';
322
    }
323
}
324