Completed
Push — master ( 262d71...f4720a )
by Nekrasov
02:40
created

ElementModel::scopeFromSectionWithId()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 6
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 6
rs 9.4286
cc 1
eloc 3
nc 1
nop 2
1
<?php
2
3
namespace Arrilot\BitrixModels\Models;
4
5
use Arrilot\BitrixModels\Queries\ElementQuery;
6
use Exception;
7
8
class ElementModel extends BaseModel
9
{
10
    /**
11
     * Bitrix entity object.
12
     *
13
     * @var object
14
     */
15
    public static $bxObject;
16
17
    /**
18
     * Corresponding object class name.
19
     *
20
     * @var string
21
     */
22
    protected static $objectClass = 'CIBlockElement';
23
24
    /**
25
     * List of additional params that can modify query.
26
     *
27
     * @var array
28
     */
29
    protected static $additionalQueryModifiers = [
30
        'groupBy',
31
        'fetchUsing',
32
    ];
33
34
    /**
35
     * Have sections been already fetched from DB?
36
     *
37
     * @var bool
38
     */
39
    protected $sectionsAreFetched = false;
40
41
    /**
42
     * Method that is used to fetch getList results.
43
     * Available values: 'getNext' or 'getNextElement'.
44
     *
45
     * @var string
46
     */
47
    public static $fetchUsing = 'getNextElement';
48
49
    /**
50
     * Corresponding iblock id.
51
     * MUST be overridden.
52
     *
53
     * @throws Exception
54
     *
55
     * @return int
56
     */
57
    public static function iblockId()
58
    {
59
        throw new Exception('public static function iblockId() MUST be overridden');
60
    }
61
62
    /**
63
     * Corresponding section model full qualified class name.
64
     * MUST be overridden if you are going to use section model for this iblock.
65
     *
66
     * @throws Exception
67
     *
68
     * @return string
69
     */
70
    public static function sectionModel()
71
    {
72
        throw new Exception('public static function sectionModel() MUST be overridden');
73
    }
74
75
    /**
76
     * Instantiate a query object for the model.
77
     *
78
     * @return ElementQuery
79
     */
80
    public static function query()
81
    {
82
        return new ElementQuery(static::instantiateObject(), get_called_class());
83
    }
84
85
    /**
86
     * Scope to sort by date.
87
     *
88
     * @param ElementQuery $query
89
     * @param string       $sort
90
     *
91
     * @return ElementQuery
92
     */
93
    public function scopeSortByDate($query, $sort = 'DESC')
94
    {
95
        return $query->sort(['ACTIVE_FROM' => $sort]);
96
    }
97
98
99
    /**
100
     * Scope to get only items from a given section.
101
     *
102
     * @param ElementQuery $query
103
     * @param mixed        $id
104
     *
105
     * @return ElementQuery
106
     */
107
    public function scopeFromSectionWithId($query, $id)
108
    {
109
        $query->filter['SECTION_ID'] = $id;
110
111
        return $query;
112
    }
113
114
    /**
115
     * Scope to get only items from a given section.
116
     *
117
     * @param ElementQuery $query
118
     * @param string       $code
119
     *
120
     * @return ElementQuery
121
     */
122
    public function scopeFromSectionWithCode($query, $code)
123
    {
124
        $query->filter['SECTION_CODE'] = $code;
125
126
        return $query;
127
    }
128
129
    /**
130
     * Fill extra fields when $this->field is called.
131
     *
132
     * @return null
133
     */
134
    protected function afterFill()
135
    {
136
        $this->normalizePropertyFormat();
137
    }
138
139
    /**
140
     * Get all model attributes from cache or database.
141
     *
142
     * @return array
143
     */
144
    public function get()
145
    {
146
        $this->getFields();
147
148
        return $this->fields;
149
    }
150
151
    /**
152
     * Get element's sections from cache or database.
153
     *
154
     * @return array
155
     */
156
    public function getSections()
157
    {
158
        if ($this->sectionsAreFetched) {
159
            return $this->fields['IBLOCK_SECTION'];
160
        }
161
162
        return $this->refreshSections();
163
    }
164
165
    /**
166
     * Refresh model from database and place data to $this->fields.
167
     *
168
     * @return array
169
     */
170
    public function refresh()
171
    {
172
        return $this->refreshFields();
173
    }
174
175
    /**
176
     * Refresh element's fields and save them to a class field.
177
     *
178
     * @return array
179
     */
180 View Code Duplication
    public function refreshFields()
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...
181
    {
182
        if ($this->id === null) {
183
            return  $this->fields = [];
184
        }
185
186
        $sectionsBackup = isset($this->fields['IBLOCK_SECTION']) ? $this->fields['IBLOCK_SECTION'] : null;
187
188
        $this->fields = static::query()->getById($this->id)->fields;
189
190
        if (!empty($sectionsBackup)) {
191
            $this->fields['IBLOCK_SECTION'] = $sectionsBackup;
192
        }
193
194
        $this->fieldsAreFetched = true;
195
196
        return $this->fields;
197
    }
198
199
    /**
200
     * Refresh element's sections and save them to a class field.
201
     *
202
     * @return array
203
     */
204
    public function refreshSections()
205
    {
206
        if ($this->id === null) {
207
            return [];
208
        }
209
210
        $this->fields['IBLOCK_SECTION'] = static::$bxObject->getElementGroups($this->id, true);
211
        $this->sectionsAreFetched = true;
212
213
        return $this->fields['IBLOCK_SECTION'];
214
    }
215
216
    /**
217
     * Get element direct section as ID or array of fields.
218
     *
219
     * @param bool $withProps
220
     *
221
     * @return false|int|array
222
     */
223
    public function getSection($withProps = false)
224
    {
225
        $fields = $this->getFields();
226
        if (!$withProps) {
227
            return $fields['IBLOCK_SECTION_ID'];
228
        }
229
230
        /** @var SectionModel $sectionModel */
231
        $sectionModel = static::sectionModel();
232
        if (!$fields['IBLOCK_SECTION_ID']) {
233
            return false;
234
        }
235
236
        return $sectionModel::getById($fields['IBLOCK_SECTION_ID'])->toArray();
237
    }
238
239
    /**
240
     * Get element direct section as model object.
241
     *
242
     * @param bool $withProps
243
     *
244
     * @return false|SectionModel
245
     */
246
    public function section($withProps = false)
247
    {
248
        $fields = $this->getFields();
249
250
        /** @var SectionModel $sectionModel */
251
        $sectionModel = static::sectionModel();
252
253
        return $withProps
254
            ? $sectionModel::getById($fields['IBLOCK_SECTION_ID'])
255
            : new $sectionModel($fields['IBLOCK_SECTION_ID']);
256
    }
257
258
    /**
259
     * Save props to database.
260
     * If selected is not empty then only props from it are saved.
261
     *
262
     * @param array $selected
263
     *
264
     * @return bool
265
     */
266
    public function saveProps($selected = [])
267
    {
268
        $propertyValues = $this->constructPropertyValuesForSave($selected);
269
        if (empty($propertyValues)) {
270
            return false;
271
        }
272
273
        $bxMethod = empty($selected) ? 'setPropertyValues' : 'setPropertyValuesEx';
274
        static::$bxObject->$bxMethod(
275
            $this->id,
276
            static::iblockId(),
277
            $propertyValues
278
        );
279
280
        return true;
281
    }
282
283
    /**
284
     * Normalize properties's format converting it to 'PROPERTY_"CODE"_VALUE'.
285
     *
286
     * @return null
287
     */
288
    protected function normalizePropertyFormat()
289
    {
290
        if (empty($this->fields['PROPERTIES'])) {
291
            return;
292
        }
293
294
        foreach ($this->fields['PROPERTIES'] as $code => $prop) {
295
            $this->fields['PROPERTY_'.$code.'_VALUE'] = $prop['VALUE'];
296
            $this->fields['~PROPERTY_'.$code.'_VALUE'] = $prop['~VALUE'];
297
            $this->fields['PROPERTY_'.$code.'_DESCRIPTION'] = $prop['DESCRIPTION'];
298
            $this->fields['~PROPERTY_'.$code.'_DESCRIPTION'] = $prop['~DESCRIPTION'];
299
            $this->fields['PROPERTY_'.$code.'_VALUE_ID'] = $prop['PROPERTY_VALUE_ID'];
300
        }
301
    }
302
303
    /**
304
     * Construct 'PROPERTY_VALUES' => [...] from flat fields array.
305
     * This is used in save.
306
     * If $selectedFields are specified only those are saved.
307
     *
308
     * @param $selectedFields
309
     *
310
     * @return array
311
     */
312
    protected function constructPropertyValuesForSave($selectedFields = [])
313
    {
314
        $propertyValues = [];
315
        $saveOnlySelected = !empty($selectedFields);
316
        foreach ($this->fields as $code => $value) {
0 ignored issues
show
Bug introduced by
The expression $this->fields of type null|array 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...
317
            if ($saveOnlySelected && !in_array($code, $selectedFields)) {
318
                continue;
319
            }
320
321
            if (preg_match('/^PROPERTY_(.*)_VALUE$/', $code, $matches) && !empty($matches[1])) {
322
                $propertyValues[$matches[1]] = $value;
323
            }
324
        }
325
326
        return $propertyValues;
327
    }
328
}
329