Completed
Push — master ( a58b1e...21d850 )
by Nekrasov
02:05
created

ElementModel::setResizePictures()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 4
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 1
1
<?php
2
3
namespace Arrilot\BitrixModels\Models;
4
5
use Arrilot\BitrixModels\Exceptions\ExceptionFromBitrix;
6
use Arrilot\BitrixModels\Queries\ElementQuery;
7
use CIBlock;
8
use Illuminate\Support\Collection;
9
use LogicException;
10
11
/**
12
 * ElementQuery methods
13
 * @method static ElementQuery groupBy($value)
14
 * @method static static getByCode(string $code)
15
 * @method static static getByExternalId(string $id)
16
 *
17
 * Base Query methods
18
 * @method static Collection|static[] getList()
19
 * @method static static first()
20
 * @method static static getById(int $id)
21
 * @method static ElementQuery sort(string|array $by, string $order='ASC')
22
 * @method static ElementQuery order(string|array $by, string $order='ASC') // same as sort()
23
 * @method static ElementQuery filter(array $filter)
24
 * @method static ElementQuery addFilter(array $filters)
25
 * @method static ElementQuery resetFilter()
26
 * @method static ElementQuery navigation(array $filter)
27
 * @method static ElementQuery select($value)
28
 * @method static ElementQuery keyBy(string $value)
29
 * @method static ElementQuery limit(int $value)
30
 * @method static ElementQuery offset(int $value)
31
 * @method static ElementQuery page(int $num)
32
 * @method static ElementQuery take(int $value) // same as limit()
33
 * @method static ElementQuery forPage(int $page, int $perPage=15)
34
 * @method static \Illuminate\Pagination\LengthAwarePaginator paginate(int $perPage = 15, string $pageName = 'page')
35
 * @method static \Illuminate\Pagination\Paginator simplePaginate(int $perPage = 15, string $pageName = 'page')
36
 * @method static ElementQuery stopQuery()
37
 * @method static ElementQuery cache(float|int $minutes)
38
 *
39
 * Scopes
40
 * @method static ElementQuery active()
41
 * @method static ElementQuery sortByDate(string $sort = 'DESC')
42
 * @method static ElementQuery fromSectionWithId(int $id)
43
 * @method static ElementQuery fromSectionWithCode(string $code)
44
 */
45
class ElementModel extends BitrixModel
46
{
47
    /**
48
     * Corresponding IBLOCK_ID
49
     *
50
     * @var int
51
     */
52
    const IBLOCK_ID = null;
53
54
    /**
55
     * IBLOCK version (1 or 2)
56
     *
57
     * @var int
58
     */
59
    const IBLOCK_VERSION = 2;
60
61
    /**
62
     * Bitrix entity object.
63
     *
64
     * @var object
65
     */
66
    public static $bxObject;
67
68
    /**
69
     * Corresponding object class name.
70
     *
71
     * @var string
72
     */
73
    protected static $objectClass = 'CIBlockElement';
74
75
    /**
76
     * Have sections been already fetched from DB?
77
     *
78
     * @var bool
79
     */
80
    protected $sectionsAreFetched = false;
81
82
    /**
83
     * Log in Bitrix workflow ($bWorkFlow for CIBlockElement::Add/Update).
84
     *
85
     * @var bool
86
     */
87
    protected static $workFlow = false;
88
89
    /**
90
     * Update search after each create or update (bUpdateSearch for CIBlockElement::Add/Update).
91
     *
92
     * @var bool
93
     */
94
    protected static $updateSearch = true;
95
96
    /**
97
     * Resize pictures during add/update (bResizePictures for CIBlockElement::Add/Update).
98
     *
99
     * @var bool
100
     */
101
    protected static $resizePictures = false;
102
103
    /**
104
     * Getter for corresponding iblock id.
105
     *
106
     * @throws LogicException
107
     *
108
     * @return int
109
     */
110
    public static function iblockId()
111
    {
112
        $id = static::IBLOCK_ID;
113
        if (!$id) {
114
            throw new LogicException('You must set IBLOCK_ID constant inside a model or override iblockId() method');
115
        }
116
        
117
        return $id;
118
    }
119
    
120
    /**
121
     * Create new item in database.
122
     *
123
     * @param $fields
124
     *
125
     * @throws LogicException
126
     *
127
     * @return static|bool
128
     * @throws ExceptionFromBitrix
129
     */
130
    public static function create($fields)
131
    {
132
        if (!isset($fields['IBLOCK_ID'])) {
133
            $fields['IBLOCK_ID'] = static::iblockId();
134
        }
135
136
        return static::internalCreate($fields);
137
    }
138
139
    public static function internalDirectCreate($bxObject, $fields)
140
    {
141
        return $bxObject->add($fields, static::$workFlow, static::$updateSearch, static::$resizePictures);
142
    }
143
144
    /**
145
     * Corresponding section model full qualified class name.
146
     * MUST be overridden if you are going to use section model for this iblock.
147
     *
148
     * @throws LogicException
149
     *
150
     * @return string
151
     */
152
    public static function sectionModel()
153
    {
154
        throw new LogicException('public static function sectionModel() MUST be overridden');
155
    }
156
157
    /**
158
     * Instantiate a query object for the model.
159
     *
160
     * @return ElementQuery
161
     */
162
    public static function query()
163
    {
164
        return new ElementQuery(static::instantiateObject(), get_called_class());
165
    }
166
167
    /**
168
     * Scope to sort by date.
169
     *
170
     * @param ElementQuery $query
171
     * @param string       $sort
172
     *
173
     * @return ElementQuery
174
     */
175
    public function scopeSortByDate($query, $sort = 'DESC')
176
    {
177
        return $query->sort(['ACTIVE_FROM' => $sort]);
178
    }
179
180
    /**
181
     * Scope to get only items from a given section.
182
     *
183
     * @param ElementQuery $query
184
     * @param mixed        $id
185
     *
186
     * @return ElementQuery
187
     */
188
    public function scopeFromSectionWithId($query, $id)
189
    {
190
        $query->filter['SECTION_ID'] = $id;
191
192
        return $query;
193
    }
194
195
    /**
196
     * Scope to get only items from a given section.
197
     *
198
     * @param ElementQuery $query
199
     * @param string       $code
200
     *
201
     * @return ElementQuery
202
     */
203
    public function scopeFromSectionWithCode($query, $code)
204
    {
205
        $query->filter['SECTION_CODE'] = $code;
206
207
        return $query;
208
    }
209
210
    /**
211
     * Fill extra fields when $this->field is called.
212
     *
213
     * @return null
214
     */
215
    protected function afterFill()
216
    {
217
        $this->normalizePropertyFormat();
218
    }
219
220
    /**
221
     * Load all model attributes from cache or database.
222
     *
223
     * @return $this
224
     */
225
    public function load()
226
    {
227
        $this->getFields();
228
229
        return $this;
230
    }
231
232
    /**
233
     * Get element's sections from cache or database.
234
     *
235
     * @return array
236
     */
237
    public function getSections()
238
    {
239
        if ($this->sectionsAreFetched) {
240
            return $this->fields['IBLOCK_SECTION'];
241
        }
242
243
        return $this->refreshSections();
244
    }
245
246
    /**
247
     * Refresh model from database and place data to $this->fields.
248
     *
249
     * @return array
250
     */
251
    public function refresh()
252
    {
253
        return $this->refreshFields();
254
    }
255
256
    /**
257
     * Refresh element's fields and save them to a class field.
258
     *
259
     * @return array
260
     */
261 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...
262
    {
263
        if ($this->id === null) {
264
            $this->original = [];
265
            return $this->fields = [];
266
        }
267
268
        $sectionsBackup = isset($this->fields['IBLOCK_SECTION']) ? $this->fields['IBLOCK_SECTION'] : null;
269
270
        $this->fields = static::query()->getById($this->id)->fields;
271
272
        if (!empty($sectionsBackup)) {
273
            $this->fields['IBLOCK_SECTION'] = $sectionsBackup;
274
        }
275
276
        $this->fieldsAreFetched = true;
277
278
        $this->original = $this->fields;
279
280
        return $this->fields;
281
    }
282
283
    /**
284
     * Refresh element's sections and save them to a class field.
285
     *
286
     * @return array
287
     */
288
    public function refreshSections()
289
    {
290
        if ($this->id === null) {
291
            return [];
292
        }
293
294
        $this->fields['IBLOCK_SECTION'] = [];
295
        $dbSections = static::$bxObject->getElementGroups($this->id, true);
296
        while ($section = $dbSections->Fetch()) {
297
            $this->fields['IBLOCK_SECTION'][] = $section;
298
        }
299
300
        $this->sectionsAreFetched = true;
301
302
        return $this->fields['IBLOCK_SECTION'];
303
    }
304
305
    /**
306
     * @deprecated in favour of `->section()`
307
     * Get element direct section as ID or array of fields.
308
     *
309
     * @param bool $load
310
     *
311
     * @return false|int|array
312
     */
313
    public function getSection($load = false)
314
    {
315
        $fields = $this->getFields();
316
        if (!$load) {
317
            return $fields['IBLOCK_SECTION_ID'];
318
        }
319
320
        /** @var SectionModel $sectionModel */
321
        $sectionModel = static::sectionModel();
322
        if (!$fields['IBLOCK_SECTION_ID']) {
323
            return false;
324
        }
325
326
        return $sectionModel::query()->getById($fields['IBLOCK_SECTION_ID'])->toArray();
327
    }
328
329
    /**
330
     * Get element direct section as model object.
331
     *
332
     * @param bool $load
333
     *
334
     * @return false|SectionModel
335
     */
336
    public function section($load = false)
337
    {
338
        $fields = $this->getFields();
339
340
        /** @var SectionModel $sectionModel */
341
        $sectionModel = static::sectionModel();
342
343
        return $load
344
            ? $sectionModel::query()->getById($fields['IBLOCK_SECTION_ID'])
345
            : new $sectionModel($fields['IBLOCK_SECTION_ID']);
346
    }
347
348
    /**
349
     * Proxy for GetPanelButtons
350
     *
351
     * @param array $options
352
     * @return array
353
     */
354
    public function getPanelButtons($options = [])
355
    {
356
        return CIBlock::GetPanelButtons(
357
            static::iblockId(),
358
            $this->id,
359
            0,
360
            $options
361
        );
362
    }
363
364
    /**
365
     * Save props to database.
366
     * If selected is not empty then only props from it are saved.
367
     *
368
     * @param array $selected
369
     *
370
     * @return bool
371
     */
372
    public function saveProps($selected = [])
373
    {
374
        $propertyValues = $this->constructPropertyValuesForSave($selected);
375
        if (empty($propertyValues)) {
376
            return false;
377
        }
378
379
        $bxMethod = empty($selected) ? 'setPropertyValues' : 'setPropertyValuesEx';
380
        static::$bxObject->$bxMethod(
381
            $this->id,
382
            static::iblockId(),
383
            $propertyValues
384
        );
385
386
        return true;
387
    }
388
389
    /**
390
     * Normalize properties's format converting it to 'PROPERTY_"CODE"_VALUE'.
391
     *
392
     * @return null
393
     */
394
    protected function normalizePropertyFormat()
395
    {
396
        if (empty($this->fields['PROPERTIES'])) {
397
            return;
398
        }
399
400
        foreach ($this->fields['PROPERTIES'] as $code => $prop) {
401
            $this->fields['PROPERTY_'.$code.'_VALUE'] = $prop['VALUE'];
402
            $this->fields['~PROPERTY_'.$code.'_VALUE'] = $prop['~VALUE'];
403
            $this->fields['PROPERTY_'.$code.'_DESCRIPTION'] = $prop['DESCRIPTION'];
404
            $this->fields['~PROPERTY_'.$code.'_DESCRIPTION'] = $prop['~DESCRIPTION'];
405
            $this->fields['PROPERTY_'.$code.'_VALUE_ID'] = $prop['PROPERTY_VALUE_ID'];
406
        }
407
    }
408
409
    /**
410
     * Construct 'PROPERTY_VALUES' => [...] from flat fields array.
411
     * This is used in save.
412
     * If $selectedFields are specified only those are saved.
413
     *
414
     * @param $selectedFields
415
     *
416
     * @return array
417
     */
418
    protected function constructPropertyValuesForSave($selectedFields = [])
419
    {
420
        $propertyValues = [];
421
        $saveOnlySelected = !empty($selectedFields);
422
        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...
423
            if ($saveOnlySelected && !in_array($code, $selectedFields)) {
424
                continue;
425
            }
426
427
            if (preg_match('/^PROPERTY_(.*)_VALUE$/', $code, $matches) && !empty($matches[1])) {
428
                $propertyValues[$matches[1]] = $value;
429
            }
430
        }
431
432
        return $propertyValues;
433
    }
434
435
    /**
436
     * Determine whether the field should be stopped from passing to "update".
437
     *
438
     * @param string $field
439
     * @param mixed  $value
440
     * @param array  $selectedFields
441
     *
442
     * @return bool
443
     */
444
    protected function fieldShouldNotBeSaved($field, $value, $selectedFields)
445
    {
446
        $blacklistedFields = [
447
            'ID',
448
            'IBLOCK_ID',
449
            'PROPERTIES',
450
            'PROPERTY_VALUES',
451
        ];
452
453
        return (!empty($selectedFields) && !in_array($field, $selectedFields))
454
            || in_array($field, $blacklistedFields)
455
            || ($field[0] === '~');
456
            //|| (substr($field, 0, 9) === 'PROPERTY_');
457
    }
458
459
    /**
460
     * @param $fields
461
     * @param $fieldsSelectedForSave
462
     * @return bool
463
     */
464
    protected function internalUpdate($fields, $fieldsSelectedForSave)
465
    {
466
        $fields = $fields ?: [];
467
        foreach ($fields as $key => $value) {
468
            if (substr($key, 0, 9) === 'PROPERTY_') {
469
                unset($fields[$key]);
470
            }
471
        }
472
473
        $result = !empty($fields) ? static::$bxObject->update($this->id, $fields, static::$workFlow, static::$updateSearch, static::$resizePictures) : false;
474
        $savePropsResult = $this->saveProps($fieldsSelectedForSave);
475
        $result = $result || $savePropsResult;
476
477
        return $result;
478
    }
479
480
    /**
481
     * @param $value
482
     */
483
    public static function setWorkflow($value)
484
    {
485
        static::$workFlow = $value;
486
    }
487
488
    /**
489
     * @param $value
490
     */
491
    public static function setUpdateSearch($value)
492
    {
493
        static::$updateSearch = $value;
494
    }
495
496
    /**
497
     * @param $value
498
     */
499
    public static function setResizePictures($value)
500
    {
501
        static::$resizePictures = $value;
502
    }
503
}
504