Products   F
last analyzed

Complexity

Total Complexity 154

Size/Duplication

Total Lines 1084
Duplicated Lines 2.4 %

Coupling/Cohesion

Components 1
Dependencies 11

Importance

Changes 0
Metric Value
dl 26
loc 1084
rs 1.264
c 0
b 0
f 0
wmc 154
lcom 1
cbo 11

24 Methods

Rating   Name   Duplication   Size   Complexity  
A addProductsToUpperCategories() 0 23 4
A getUrls() 0 10 3
A import_() 0 29 2
A rememberOriginAdditionalParentsCats() 0 16 3
B getCompareData() 0 19 10
F processProducts1() 14 170 26
C pass1Helper_getProductData() 0 54 11
A pass1Helper_getVariantData() 0 41 4
A pass1Helper_getCategoryData() 0 15 3
C pass1Helper_getImagesData() 12 45 12
C pass1Helper_getPropertiesData() 0 60 12
B insert1() 0 24 6
B insertProducts() 0 46 5
F processProducts23_Insert23() 0 81 15
A isProductCategoriesRowNew() 0 13 4
A update() 0 38 5
A updateFromCollector() 0 4 1
B rebuildAdditionalParentsCats() 0 50 9
A runResize() 0 8 2
B rebuildProductProperties() 0 42 11
A setResize() 0 5 1
A setTempDir() 0 5 1
A getPropertyValueIdOrCreate() 0 20 2
A prepareProductPropertiesData() 0 16 2

How to fix   Duplicated Code    Complexity   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

Complex Class

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

Complex classes like Products often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use Products, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
namespace exchange\classes;
4
5
use CI;
6
use CMSFactory\ModuleSettings;
7
use core\models\Route;
8
use core\models\RouteQuery;
9
use Exception;
10
use MediaManager\Image;
11
use MY_Controller;
12
use Propel\Runtime\ActiveQuery\Criteria;
13
use SimpleXMLElement;
14
15
/**
16
 *
17
 * @author kolia
18
 */
19
class Products extends ExchangeBase
20
{
21
22
    /**
23
     *
24
     * @var array
25
     */
26
    private $additionalParentsCategories = [];
27
28
    /**
29
     *
30
     * @var array
31
     */
32
    protected $compare_exIds = [];
33
34
    /**
35
     *
36
     * @var array
37
     */
38
    protected $compare_properties = [];
39
40
    /**
41
     *
42
     * @var array
43
     */
44
    protected $compare_urls = [];
45
46
    /**
47
     *
48
     * @var array
49
     */
50
    private $existingProductsIds = [];
51
52
    /**
53
     *
54
     * @var array
55
     */
56
    protected $i18nExisting = [];
57
58
    /**
59
     *
60
     * @var boolean
61
     */
62
    private $ignoreExistingDescriptions = false;
63
64
    /**
65
     *
66
     * @var
67
     */
68
    private $ignoreExistingProducts = false;
69
70
    /**
71
     * If product have images, then all
72
     * his old images need to be deleted
73
     * @var array
74
     */
75
    protected $imagesToDelete = [];
76
77
    /**
78
     * @var array
79
     */
80
    protected $imagesToResize = [];
81
82
    /**
83
     * @var array
84
     */
85
    protected $imagesToResizeAdditional = [];
86
87
    /**
88
     *
89
     * @var DataCollector
90
     */
91
    protected $insertCollector;
92
93
    /**
94
     * Array of products main categories
95
     * @var array
96
     */
97
    private $parentCat = [];
98
99
    /**
100
     *
101
     * @var array
102
     */
103
    protected $productProCats = [];
104
105
    /**
106
     * In the xml there can be two different products with same names, this array
107
     * gathers just created product urls to prevent equal addresses
108
     * @var array
109
     */
110
    protected $productsNewUrls = [];
111
112
    /**
113
     *
114
     * @var array
115
     */
116
    protected $productss;
117
118
    /**
119
     *
120
     * @var boolean
121
     */
122
    protected $runResize = FALSE;
123
124
    /**
125
     * If products have 'ХарактеристикиТовара' run fix
126
     * @var bool
127
     */
128
    protected $runVariantsFix = false;
129
130
    /**
131
     * Path of folder where xml and images stored
132
     * @var string
133
     */
134
    protected $tempDir;
135
136
    /**
137
     *
138
     * @var DataCollector
139
     */
140
    protected $updateCollector;
141
142
    /**
143
     *
144
     * @var VariantCharacteristics
145
     */
146
    private $variantCharacteristics;
147
148
    private $categoryUrls = [];
149
150
    protected function addProductsToUpperCategories() {
151
152
        $products = $this->db->select('shop_products.id, shop_category.full_path_ids')
153
            ->join('shop_category', 'shop_category.id = shop_products.category_id')
154
            ->get('shop_products')
155
            ->result();
156
157
        $insertData = [];
158
        foreach ($products as $product) {
159
            $path = unserialize($product->full_path_ids);
160
            foreach ($path as $fpi) {
161
                $newData = [
162
                            'category_id' => $fpi,
163
                            'product_id'  => $product->id,
164
                           ];
165
                if ($this->isProductCategoriesRowNew($newData) == FALSE) {
166
                    continue;
167
                }
168
                $insertData[] = $newData;
169
            }
170
        }
171
        $this->insertBatch('shop_product_categories', $insertData);
172
    }
173
174
    protected function getUrls() {
175
176
        $productExIds = [];
177
        foreach ($this->products as $product) {
0 ignored issues
show
Bug introduced by
The property products does not seem to exist. Did you mean existingProductsIds?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
178
            if (!empty($product['external_id'])) {
179
                $productExIds[$product['external_id']] = $product['id'];
180
            }
181
        }
182
        return $productExIds;
183
    }
184
185
    /**
186
     *
187
     */
188
    protected function import_() {
189
190
        $ignoreExisting = ModuleSettings::ofModule('exchange')->get('ignore_existing');
191
        $this->ignoreExistingProducts = isset($ignoreExisting['products']);
192
        $this->ignoreExistingDescriptions = isset($ignoreExisting['description']);
193
194
        $this->insertCollector = new DataCollector();
195
        $this->updateCollector = new DataCollector();
196
197
        $storageFilePath = CI::$APP->config->item('characteristicsStorageFilePath');
198
        $this->variantCharacteristics = new VariantCharacteristics($storageFilePath);
199
200
        $this->rememberOriginAdditionalParentsCats();
201
202
        $this->getCompareData();
203
204
        $this->processProducts1();
205
        $this->insert1();
206
        $this->processProducts23_Insert23();
207
208
        if (!$this->ignoreExistingProducts) {
209
            $this->update();
210
        }
211
        $this->rememberOriginAdditionalParentsCats();
212
213
        $this->rebuildAdditionalParentsCats();
214
        $this->runResize();
215
        //        $this->rebuildProductProperties();
216
    }
217
218
    /**
219
     *
220
     */
221
    protected function rememberOriginAdditionalParentsCats() {
222
223
        $result = $this->db
224
            ->select(['shop_products.id', 'shop_category.full_path_ids'])
225
            ->join('shop_category', 'shop_category.id=shop_products.category_id')
226
            ->get('shop_products');
227
228
        if (!$result) {
229
            return;
230
        }
231
232
        $result = $result->result_array();
233
        foreach ($result as $row) {
234
            $this->additionalParentsCategories[$row['id']] = unserialize($row['full_path_ids']);
235
        }
236
    }
237
238
    /**
239
     * Getting from base data of product for fast compare (external_ids, urls...)
240
     * @param integer $type if empty = all,
241
     *  1 - only external_ids,
242
     *  2 - only urls,
243
     *  3 - only properties
244
     */
245
    protected function getCompareData($type = NULL) {
246
247
        foreach ($this->products as $product) {
0 ignored issues
show
Bug introduced by
The property products does not seem to exist. Did you mean existingProductsIds?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
248
            // external ids of products
249
            if (!empty($product['external_id']) & ($type == NULL || (int) $type == 1)) {
250
                $this->compare_exIds[$product['external_id']] = $product['id'];
251
            }
252
            if ($type == NULL || (int) $type == 2) {
253
                $this->compare_urls[$product['url']] = $product['external_id'];
254
            }
255
        }
256
        if ($type == NULL || (int) $type == 3) {
257
            foreach ($this->properties as $property) {
0 ignored issues
show
Bug introduced by
The property properties does not seem to exist. Did you mean compare_properties?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
258
                if (!empty($property['external_id'])) {
259
                    $this->compare_properties[$property['external_id']] = $property;
260
                }
261
            }
262
        }
263
    }
264
265
    /**
266
     * Gather data for tables:
267
     *  - `shop_products` (data will be ready)
268
     *  - `shop_products_i18n` (after `shop_products`)
269
     *  - `shop_product_variants` (after `shop_products`)
270
     *  - `shop_product_variants_i18n` (after `shop_product_variants`)
271
     *  - `shop_products_categories` (after `shop_products`)
272
     *  - `shop_product_images` (after `shop_products`)
273
     *
274
     *  P.S. For updating all data will be ready immediately, inserting need depends on the order
275
     *
276
     */
277
    protected function processProducts1() {
278
279
        $propertiesDataUpdate = [];
280
        $productPropDTDel = [];
281
282
        // for variants
283
        $productsUniqueExIds = [];
284
285
        // passing each product
286
        foreach ($this->importData as $product) {
287
288
            if (FALSE !== strpos((string) $product->Ид, '#')) { // this is variant of product
289
                $exId = array_shift(explode('#', (string) $product->Ид)); // getting product id
0 ignored issues
show
Bug introduced by
explode('#', (string) $product->Ид) cannot be passed to array_shift() as the parameter $array expects a reference.
Loading history...
290
                $variantExId = (string) $product->Ид;
291
            } else {
292
                $exId = (string) $product->Ид;
293
                $variantExId = NULL;
294
            }
295
296
            // GETTING ALL DATA
297
            list($products, $i18n) = $this->pass1Helper_getProductData($product, $exId);
298
299
            $isNewProduct = !isset($this->compare_exIds[$products['external_id']]);
300
            $isNewVariant = $variantExId == null ? false : !isset($this->variantsIds[$variantExId]);
0 ignored issues
show
Documentation introduced by
The property variantsIds does not exist on object<exchange\classes\Products>. Since you implemented __get, maybe consider adding a @property annotation.

Since your code implements the magic getter _get, this function will be called for any read access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

If the property has read access only, you can use the @property-read annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
301
302
            list($variant, $variantI18n) = $this->pass1Helper_getVariantData($product, $isNewProduct);
303
304
            try {
305
                $categoryId = $this->pass1Helper_getCategoryData($product);
306
                $products['category_id'] = $categoryId;
307
            } catch (Exception $e) {
308
                continue;
309
            }
310
311
            list($additionalImages, $mainImage) = $this->pass1Helper_getImagesData($product, $exId);
312
313
            $this->imagesToResize[] = $mainImage;
314
            foreach ($additionalImages as $addImg) {
315
                $this->imagesToResizeAdditional[] = $addImg['image_name'];
316
            }
317
318
            if ($mainImage != NULL) {
319
                $variant['mainImage'] = $mainImage;
320
            } else {
321
                $variant['mainImage'] = '';
322
            }
323
324
            list($shopProductPropertiesData, $brandId) = $this->pass1Helper_getPropertiesData($product, $categoryId);
325
326
            if ($brandId) {
327
                $products['brand_id'] = $brandId;
328
            }
329
330
            $url = translit_url((string) $product->Наименование);
331
332
            // splitting on new & existing products (by external_id)
333
            if ($isNewProduct) { // NEW
334
                // default variants values (without `product_id`)
335
                if (!$variantExId == NULL) { // this is variant of product
336
                    $this->insertCollector->addData('shop_product_variants', $variant, $variantExId);
337
                    $this->insertCollector->addData('shop_product_variants_i18n', $variantI18n, $variantExId);
338 View Code Duplication
                    if (!isset($productsUniqueExIds[$exId])) {
339
                        $productsUniqueExIds[$exId] = 0;
340
                    } else {
341
                        $this->insertCollector->newPass();
342
                        $this->updateCollector->newPass();
343
                        continue;
344
                    }
345
                } else {
346
                    $this->insertCollector->addData('shop_product_variants', $variant, $exId);
347
                    $this->insertCollector->addData('shop_product_variants_i18n', $variantI18n, $exId);
348
                }
349
350
                if (isset($this->compare_urls[$url])) {
351
                    if ($this->compare_urls[$url] != $exId) { // add some number to url
352
                        $i = 1;
353
                        $url_ = $url;
354
                        while (array_key_exists($url, $this->compare_urls)) {
355
                            $url = $url_ . ++$i;
356
                        }
357
                    }
358
                }
359
360
                $products['url'] = $url;
361
362
                $this->compare_urls[$url] = $exId;
363
364
                $this->insertCollector->addData('shop_products', $products, $exId);
365
                $this->insertCollector->addData('shop_products_i18n', $i18n, $exId);
366
367
                $this->insertCollector->addData('shop_product_categories', ['category_id' => $products['category_id']], $exId);
368
                foreach ($shopProductPropertiesData as $propertyData) {
369
                    $this->insertCollector->updateData('shop_product_properties_data', $propertyData, $exId);
370
                }
371
                if ($additionalImages != NULL) {
372
                    $this->insertCollector->addData('shop_product_images', $additionalImages, $exId);
373
                }
374
            } else { // EXISTING
375
                $productId = $this->compare_exIds[$exId];
376
                $this->existingProductsIds[] = $productId;
377
                $variant = array_merge($variant, ['product_id' => $productId]);
378
379
                if (isset($this->variantImages[$exId]) & empty($variant['mainImage'])) {
0 ignored issues
show
Documentation introduced by
The property variantImages does not exist on object<exchange\classes\Products>. Since you implemented __get, maybe consider adding a @property annotation.

Since your code implements the magic getter _get, this function will be called for any read access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

If the property has read access only, you can use the @property-read annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
380
                    $variant['mainImage'] = $this->variantImages[$exId];
0 ignored issues
show
Documentation introduced by
The property variantImages does not exist on object<exchange\classes\Products>. Since you implemented __get, maybe consider adding a @property annotation.

Since your code implements the magic getter _get, this function will be called for any read access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

If the property has read access only, you can use the @property-read annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
381
                }
382
383
                // to not drop prices on update
384
                unset($variant['price_in_main']);
385
                unset($variant['price']);
386
387
                if (!$variantExId == NULL) { // this is variant of product
388
                    if ($isNewVariant) {
389
                        $this->insertCollector->addData('shop_product_variants', $variant, $variantExId);
390
                        $this->insertCollector->addData('shop_product_variants_i18n', $variantI18n, $variantExId);
391
                    } else {
392
                        $this->updateCollector->addData('shop_product_variants', $variant, $variantExId);
393
                        $this->updateCollector->addData('shop_product_variants_i18n', $variantI18n, $variantExId);
394
                    }
395
396 View Code Duplication
                    if (!isset($productsUniqueExIds[$exId])) {
397
                        $productsUniqueExIds[$exId] = 0;
398
                    } else {
399
                        $this->insertCollector->newPass();
400
                        $this->updateCollector->newPass();
401
                        continue;
402
                    }
403
                } else {
404
                    $this->updateCollector->addData('shop_product_variants', array_merge($variant, ['product_id' => $productId]));
405
                    $this->updateCollector->addData('shop_product_variants_i18n', $variantI18n, $exId);
406
                }
407
408
                if (isset($products['category_id'])) { // will be updated by product_id
409
                    $this->updateCollector->addData(
410
                        'shop_product_categories',
411
                        [
412
                         'product_id'  => $productId,
413
                         'category_id' => $products['category_id'],
414
                        ]
415
                    );
416
                }
417
                $this->updateCollector->addData('shop_products', array_merge($products, ['id' => $productId, 'url' => $url]));
418
                $this->updateCollector->addData('shop_products_i18n', array_merge($i18n, ['id' => $productId]));
419
420
                foreach ($shopProductPropertiesData as $propertyData) {
421
                    $propertiesDataUpdate[] = array_merge($propertyData, ['product_id' => $productId]);
422
                }
423
                $productPropDTDel[] = $productId;
424
                if ($additionalImages != NULL) {
425
                    $countAddImg = count($additionalImages);
426
                    for ($i = 0; $i < $countAddImg; $i++) {
427
                        $additionalImages[$i]['product_id'] = $productId;
428
                    }
429
                    $this->updateCollector->addData('shop_product_images', $additionalImages);
430
                }
431
            }
432
433
            $this->insertCollector->newPass();
434
            $this->updateCollector->newPass();
435
        }
436
437
        if (!$this->ignoreExistingProducts and $productPropDTDel) {
438
            $this->db
439
                ->where_in('product_id', $productPropDTDel)
440
                ->delete('shop_product_properties_data');
441
442
            $this->insertPropertiesData('shop_product_properties_data', $propertiesDataUpdate);
443
        }
444
445
        $this->variantCharacteristics->saveCharacteristics();
446
    }
447
448
    /**
449
     * Method-helper for simplify processProducts1 method
450
     * @param SimpleXMLElement $product
451
     * @param string $exId
452
     * @return array
0 ignored issues
show
Documentation introduced by
Consider making the return type a bit more specific; maybe use array<string,string|integer>[].

This check looks for the generic type array as a return type and suggests a more specific type. This type is inferred from the actual code.

Loading history...
453
     */
454
    protected function pass1Helper_getProductData(SimpleXMLElement $product, $exId) {
455
456
        $products = [
457
                     'external_id' => $exId,
458
                     'active'      => (string) $product->Статус == 'Удален' ? 0 : 1,
459
                    ];
460
        $i18n = [
461
                 'locale' => $this->locale,
462
                 'name'   => (string) $product->Наименование,
463
                ];
464
465
        $hasDescription = false;
466
467
        if (isset($product->Описание)) {
468
            $hasDescription = true;
469
            $description = (string) $product->Описание;
470
        } elseif (isset($product->ЗначенияРеквизитов->ЗначениеРеквизита->Наименование)) {
471
            foreach ($product->ЗначенияРеквизитов->ЗначениеРеквизита as $recVal) {
472
                if ((string) $recVal->Наименование == 'Полное наименование') {
473
                    $hasDescription = true;
474
                    $description = (string) $recVal->Значение;
475
                }
476
            }
477
        }
478
479
        if ($hasDescription) {
480
            $locale = MY_Controller::defaultLocale();
481
            $res = $this->db
482
                ->select('shop_products_i18n.short_description, shop_products_i18n.full_description')
483
                ->from('shop_products')
484
                ->where('external_id', $exId)
485
                ->where('shop_products_i18n.locale', $locale)
486
                ->join('shop_products_i18n', 'shop_products_i18n.id = shop_products.id')
487
                ->get();
488
489
            if ($res->num_rows() > 0) {
490
                $desc = $res->row_array();
491
                $shortDescIsEmpty = ('' == $desc['short_description']);
492
                $FullDescIsEmpty = ('' == $desc['full_description']);
493
            }
494
            if ($this->ignoreExistingDescriptions) {
495
                $shortDescIsEmpty && $i18n['short_description'] = $description;
496
                $FullDescIsEmpty && $i18n['full_description'] = $description;
497
            } else {
498
                $i18n['short_description'] = $description;
499
                $i18n['full_description'] = $description;
500
            }
501
        }
502
503
        return [
504
                $products,
505
                $i18n,
506
               ];
507
    }
508
509
    /**
510
     * Method-helper for simplify processProducts1 method
511
     * @param SimpleXMLElement $product
512
     * @param bool $isNew
513
     * @return array
0 ignored issues
show
Documentation introduced by
Consider making the return type a bit more specific; maybe use array[].

This check looks for the generic type array as a return type and suggests a more specific type. This type is inferred from the actual code.

Loading history...
514
     */
515
    protected function pass1Helper_getVariantData(SimpleXMLElement $product, $isNew = true) {
516
517
        $variant = [
518
                    'external_id' => (string) $product->Ид,
519
                    'number'      => (string) $product->Артикул,
520
                    'currency'    => $this->mainCurrencyId,
0 ignored issues
show
Documentation introduced by
The property mainCurrencyId does not exist on object<exchange\classes\Products>. Since you implemented __get, maybe consider adding a @property annotation.

Since your code implements the magic getter _get, this function will be called for any read access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

If the property has read access only, you can use the @property-read annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
521
                   ];
522
523
        //$name = (string) $product->Наименование;
524
        $name = '';
525
        if (isset($product->ХарактеристикиТовара)) {
526
            foreach ($product->ХарактеристикиТовара->ХарактеристикаТовара as $value) {
527
                $chName = (string) $value->Наименование;
528
                $chValue = (string) $value->Значение;
529
530
                $name .= ' ' . $chValue;
531
                $this->variantCharacteristics->addCharacteristic($chName, $chValue);
532
            }
533
        }
534
535
        $variantI18n = [
536
                        'locale' => $this->locale,
537
                        'name'   => trim($name),
538
                       ];
539
540
        if ($isNew) {
541
            $defaultVariantsValues = [
542
                                      'price'         => '0.00000',
543
                                      'stock'         => 0,
544
                                      'position'      => 0,
545
                                      'price_in_main' => '0.00000',
546
                                     ];
547
        } else {
548
            $defaultVariantsValues = [];
549
        }
550
551
        return [
552
                array_merge($variant, $defaultVariantsValues),
553
                $variantI18n,
554
               ];
555
    }
556
557
    /**
558
     * Method-helper for simplify processProducts1 method
559
     * @param SimpleXMLElement $product
560
     * @return int
561
     * @throws Exception
562
     */
563
    protected function pass1Helper_getCategoryData(SimpleXMLElement $product) {
564
565
        $categoryId = NULL;
0 ignored issues
show
Unused Code introduced by
$categoryId is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
566
        if (isset($product->Группы)) {
567
            $categoryExId = (string) $product->Группы->Ид;
568
            $categoryId = Categories::getInstance()->categoryExists2($categoryExId, TRUE);
569
            if (!$categoryId) {
570
                throw new Exception(sprintf('Error! Product category with id [%s] not found in file', $categoryExId));
571
            }
572
        } else {
573
            throw new Exception(sprintf('Error! Product "%s" category not found in file', $product->Наименование));
574
        }
575
576
        return $categoryId;
577
    }
578
579
    /**
580
     * Method-helper for simplify processProducts1 method
581
     * @param SimpleXMLElement $product
582
     * @param string $exId
583
     * @return array
584
     */
585
    protected function pass1Helper_getImagesData(SimpleXMLElement $product, $exId) {
586
587
        $additionalImages = NULL;
588
        $mainImage = NULL;
589
590
        if (count($product->Картинка) > 1) {
591
            $this->imagesToDelete[$exId] = NULL;
592
        }
593
        $i = 0;
594
        foreach ((array) $product->Картинка as $image) {
595
            $path = (string) $image;
596
            $fileName = pathinfo($path, PATHINFO_BASENAME);
597
            if ($i == 0) { // main image
598
                if (file_exists($this->tempDir . $path) and !file_exists('./uploads/shop/products/origin/' . $fileName)) {
599
                    $copied = copy($this->tempDir . $path, './uploads/shop/products/origin/' . $fileName);
600
                    if ($copied != FALSE) {
601
                        $mainImage = $fileName;
602
                    }
603
                } elseif (file_exists('./uploads/shop/products/origin/' . $fileName)) {
604
                    $mainImage = $fileName;
605
                }
606
            } else { // rest of images will be an additional
607
                if (file_exists($this->tempDir . $path) and !file_exists('./uploads/shop/products/origin/additional/' . $fileName)) {
608
                    $copied = copy($this->tempDir . $path, './uploads/shop/products/origin/additional/' . $fileName);
609 View Code Duplication
                    if ($copied != FALSE) {
610
                        $additionalImages[] = [
611
                                               'position'   => $i - 1,
612
                                               'image_name' => $fileName,
613
                                              ];
614
                    }
615 View Code Duplication
                } elseif (file_exists('./uploads/shop/products/origin/additional/' . $fileName)) {
616
                    $additionalImages[] = [
617
                                           'position'   => $i - 1,
618
                                           'image_name' => $fileName,
619
                                          ];
620
                }
621
            }
622
            $i++;
623
        }
624
625
        return [
626
                $additionalImages,
627
                $mainImage,
628
               ];
629
    }
630
631
    /**
632
     * Method-helper for simplify processProducts1 method
633
     * @param SimpleXMLElement $product
634
     * @param int $categoryId
635
     * @return array
636
     */
637
    protected function pass1Helper_getPropertiesData(SimpleXMLElement $product, $categoryId) {
638
639
        $brandIdentif = Properties::getInstance()->getBrandIdentif();
0 ignored issues
show
Bug introduced by
The method getBrandIdentif does only exist in exchange\classes\Properties, but not in exchange\classes\Products.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
640
        $brandId = '';
641
642
        $shopProductPropertiesData = [];
643
        // processing properties of product
644
        if (isset($product->ЗначенияСвойств)) {
645
            foreach ($product->ЗначенияСвойств->ЗначенияСвойства as $property) {
646
                $propertyValue = (string) $property->Значение;
647
                if (empty($propertyValue)) {
648
                    continue;
649
                }
650
                // check for "brand"
651
                $propertyExId = (string) $property->Ид;
652
                if ($propertyExId == $brandIdentif) {
653
                    $brandId = Properties::getInstance()->getBrandIdByExId($propertyValue) ?: Properties::getInstance()->getBrandIdByName($propertyValue);
0 ignored issues
show
Bug introduced by
The method getBrandIdByExId does only exist in exchange\classes\Properties, but not in exchange\classes\Products.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
Bug introduced by
The method getBrandIdByName does only exist in exchange\classes\Properties, but not in exchange\classes\Products.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
654
                    continue;
655
                }
656
657
                if (!isset($this->compare_properties[$propertyExId])) {
658
                    continue;
659
                }
660
661
                $propertyId = $this->compare_properties[$propertyExId]['id'];
662
663
                // if property is multiple, then correting value
664
                if (Properties::getInstance()->dictionaryProperties[$propertyExId]) {
665
                    $propertyValue = Properties::getInstance()->dictionaryProperties[$propertyExId][$propertyValue];
666
                }
667
668
                $shopProductPropertiesData[] = [
669
                                                'property_id' => $propertyId,
670
                                                'value'       => $propertyValue,
671
                                                'locale'      => $this->locale,
672
                                               ];
673
674
                if ($categoryId != NULL) {
675
                    $newRow = TRUE;
676
                    foreach ($this->productProCats as $row) {
677
                        if ($row['property_id'] == $propertyId & $row['category_id'] == $categoryId) {
0 ignored issues
show
Comprehensibility introduced by
Consider adding parentheses for clarity. Current Interpretation: ($row['property_id'] == ...ory_id'] == $categoryId, Probably Intended Meaning: $row['property_id'] == (...ry_id'] == $categoryId)

When comparing the result of a bit operation, we suggest to add explicit parenthesis and not to rely on PHP’s built-in operator precedence to ensure the code behaves as intended and to make it more readable.

Let’s take a look at these examples:

// Returns always int(0).
return 0 === $foo & 4;
return (0 === $foo) & 4;

// More likely intended return: true/false
return 0 === ($foo & 4);
Loading history...
678
                            $newRow = FALSE;
679
                            break;
680
                        }
681
                    }
682
                    if ($newRow == TRUE) {
683
                        $this->productProCats[] = [
684
                                                   'property_id' => $propertyId,
685
                                                   'category_id' => $categoryId,
686
                                                  ]; // TODO: то тоже тре бде потім розібрати
687
                    }
688
                }
689
            }
690
        }
691
692
        return [
693
                $shopProductPropertiesData,
694
                $brandId,
695
               ];
696
    }
697
698
    // ------------------------------ HELPERS ------------------------------
699
700
    /**
701
     * Inserting data into `shop_products`
702
     */
703
    protected function insert1() {
704
705
        $this->insertProducts($this->insertCollector->getData('shop_products'));
706
        $this->dataLoad->getNewData('products');
707
708
        // properties-categories relations
709
        if (count($this->productProCats) > 0) {
710
            $epc = $this->db->get('shop_product_properties_categories')->result_array();
711
            foreach ($this->productProCats as $key => $newRowData) {
712
                $newRowIsReallyNew = TRUE;
713
                foreach ($epc as $rowData) {
714
                    if ($newRowData['property_id'] == $rowData['property_id'] & $newRowData['category_id'] == $rowData['category_id']) {
0 ignored issues
show
Comprehensibility introduced by
Consider adding parentheses for clarity. Current Interpretation: ($newRowData['property_i...$rowData['category_id'], Probably Intended Meaning: $newRowData['property_id...rowData['category_id'])

When comparing the result of a bit operation, we suggest to add explicit parenthesis and not to rely on PHP’s built-in operator precedence to ensure the code behaves as intended and to make it more readable.

Let’s take a look at these examples:

// Returns always int(0).
return 0 === $foo & 4;
return (0 === $foo) & 4;

// More likely intended return: true/false
return 0 === ($foo & 4);
Loading history...
715
                        unset($this->productProCats[$key]);
716
                        $newRowIsReallyNew = FALSE;
717
                        break;
718
                    }
719
                }
720
                if ($newRowIsReallyNew == FALSE) {
721
                    continue;
722
                }
723
            }
724
            $this->insertBatch('shop_product_properties_categories', $this->productProCats);
725
        }
726
    }
727
728
    private function insertProducts($data) {
729
        if (FALSE == (count($data) > 0)) {
730
            return;
731
        }
732
733
        foreach ($data as $value) {
734
            $routeUrl = $value['url'];
735
            unset($value['url']);
736
            $value['created'] = time();
737
            $value['updated'] = time();
738
            $this->db->set($value)->insert('shop_products');
739
740
            $id = $this->db->insert_id();
741
742
            $category_id = $value['category_id'];
743
            if (!array_key_exists($category_id, $this->categoryUrls)) {
744
                $parentRoute = RouteQuery::create()->filterByType(Route::TYPE_SHOP_CATEGORY)
745
                    ->findOneByEntityId($category_id);
746
                $this->categoryUrls[$category_id] = $parentRoute->getFullUrl();
747
            }
748
749
            $parentUrl = $this->categoryUrls[$category_id];
750
751
            $route = new Route();
752
            $route->setType(Route::TYPE_PRODUCT)
753
                ->setParentUrl($parentUrl)
754
                ->setUrl($routeUrl)
755
                ->setEntityId($id)
756
                ->save();
757
758
            $this->db->update('shop_products', ['route_id' => $route->getId()], ['id' => $id]);
759
760
        }
761
762
        $error = $this->db->_error_message();
763
764
        if (!empty($error)) {
765
            throw new Exception('Error on inserting into `shop_products`: ' . $error);
766
        }
767
        // gathering statistics
768
        ExchangeBase::$stats[] = [
769
                                  'query type'    => 'insert',
770
                                  'table name'    => 'shop_products',
771
                                  'affected rows' => count($data),
772
                                 ];
773
    }
774
775
    /**
776
     * Filling with product_id tables that need it, and inserting into other tables
777
     * @throws \Exception
778
     */
779
    protected function processProducts23_Insert23() {
780
781
        // process 2 (adding product_id to tables data)
782
        $products = &$this->insertCollector->getData('shop_products');
783
        $productsI18n = &$this->insertCollector->getData('shop_products_i18n');
784
        $variants = &$this->insertCollector->getData('shop_product_variants');
785
        $propertiesData = &$this->insertCollector->getData('shop_product_properties_data');
786
        $images = &$this->insertCollector->getData('shop_product_images');
787
        $productCategories = &$this->insertCollector->getData('shop_product_categories');
788
        $imagesToDelete = [];
789
        $propertiesData_ = [];
790
        $imagesForInsert = [];
791
792
        foreach ($this->productIds as $externalId => $productId) {
0 ignored issues
show
Documentation introduced by
The property productIds does not exist on object<exchange\classes\Products>. Since you implemented __get, maybe consider adding a @property annotation.

Since your code implements the magic getter _get, this function will be called for any read access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

If the property has read access only, you can use the @property-read annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
793
            if (FALSE == isset($products[$externalId])) {
794
                continue;
795
            }
796
            $productsI18n[$externalId]['id'] = $productId;
797
            if (isset($propertiesData[$externalId])) {
798
                foreach ($propertiesData[$externalId] as $oneProductPropData) {
799
                    $propertiesData_[] = array_merge($oneProductPropData, ['product_id' => $productId]);
800
                }
801
            }
802
            if (isset($images[$externalId])) {
803
                $countImgs = count($images[$externalId]);
804
                for ($i = 0; $i < $countImgs; $i++) {
805
                    $images[$externalId][$i]['product_id'] = $productId;
806
                    $imagesForInsert[] = $images[$externalId][$i];
807
                }
808
            }
809
            if (isset($this->imagesToDelete[$externalId])) {
810
                $imagesToDelete[] = $productId;
811
            }
812
            if (isset($productCategories[$externalId])) {
813
                $productCategories[$externalId]['product_id'] = $productId;
814
                if (FALSE == $this->isProductCategoriesRowNew($productCategories[$externalId])) {
815
                    unset($productCategories[$externalId]);
816
                }
817
            }
818
        }
819
        $this->insertCollector->unsetData('shop_product_properties_data');
820
        // insert 2 (inserting those which where needed product_id)
821
        $this->insertBatch('shop_products_i18n', $productsI18n);
822
823
        foreach ($variants as $variantExId => $variantData) {
824
            $productExId = array_shift(explode('#', $variantExId));
0 ignored issues
show
Bug introduced by
explode('#', $variantExId) cannot be passed to array_shift() as the parameter $array expects a reference.
Loading history...
825
            $variants[$variantExId]['product_id'] = $this->productIds[$productExId];
0 ignored issues
show
Documentation introduced by
The property productIds does not exist on object<exchange\classes\Products>. Since you implemented __get, maybe consider adding a @property annotation.

Since your code implements the magic getter _get, this function will be called for any read access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

If the property has read access only, you can use the @property-read annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
826
        }
827
828
        $this->insertBatch('shop_product_variants', $variants);
829
830
        // adding shop_product_properties_data and shop_product_properties_data_i18n is not so ordinary...
831
        if (count($propertiesData_) > 0) {
832
833
            $data = $this->prepareProductPropertiesData($propertiesData_);
834
            $this->insertBatch('shop_product_properties_data', $data);
835
        }
836
837
        // inserting shop_product_categories
838
        $this->insertBatch('shop_product_categories', $productCategories);
839
840
        //process3 (variants)
841
        $variantsI18n = &$this->insertCollector->getData('shop_product_variants_i18n');
842
843
        $variantsIds = $this->dataLoad->getNewData('variantsIds');
844
        foreach ($variantsIds as $externalId => $variantId) {
845
            if (FALSE == isset($variantsI18n[$externalId])) {
846
                continue;
847
            }
848
            $variantsI18n[$externalId]['id'] = $variantId;
849
        }
850
851
        // insert 3
852
        $this->insertBatch('shop_product_variants_i18n', $variantsI18n);
853
854
        // deleting additional images, inserting new
855
        if ($imagesToDelete) {
856
            $this->db->where_in('product_id', $imagesToDelete)->delete('shop_product_images');
857
        }
858
        $this->insertBatch('shop_product_images', $imagesForInsert);
859
    }
860
861
    /**
862
     *
863
     * @param array $newRowData
864
     * @return boolean
865
     */
866
    protected function isProductCategoriesRowNew(array $newRowData) {
867
868
        if (!isset($this->existingRows)) {
869
            $this->existingRows = $this->db->get('shop_product_categories')->result_array();
0 ignored issues
show
Bug introduced by
The property existingRows does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
870
        }
871
872
        foreach ($this->existingRows as $existingRowData) {
873
            if ($existingRowData['product_id'] == $newRowData['product_id'] & $existingRowData['category_id'] == $newRowData['category_id']) {
0 ignored issues
show
Comprehensibility introduced by
Consider adding parentheses for clarity. Current Interpretation: ($existingRowData['produ...wRowData['category_id'], Probably Intended Meaning: $existingRowData['produc...RowData['category_id'])

When comparing the result of a bit operation, we suggest to add explicit parenthesis and not to rely on PHP’s built-in operator precedence to ensure the code behaves as intended and to make it more readable.

Let’s take a look at these examples:

// Returns always int(0).
return 0 === $foo & 4;
return (0 === $foo) & 4;

// More likely intended return: true/false
return 0 === ($foo & 4);
Loading history...
874
                return FALSE;
875
            }
876
        }
877
        return TRUE;
878
    }
879
880
    /**
881
     * Update all
882
     * @throws \Exception
883
     */
884
    protected function update() {
885
886
        // update has only two "passes" - as we already got product_id
887
        $this->updateFromCollector('shop_products', 'id');
888
        $this->updateFromCollector('shop_product_categories', 'product_id');
889
        $this->updateFromCollector('shop_products_i18n', 'id');
890
        //$this->updateFromCollector('shop_product_properties_data', 'product_id');
891
        //        $this->updateFromCollector('shop_product_images', 'product_id');
892
        $this->updateFromCollector('shop_product_variants', 'external_id');
893
894
        // get variants ids, and update variants_18n
895
        $variantsI18n = &$this->updateCollector->getData('shop_product_variants_i18n');
896
897
        $this->dataLoad->getNewData('variantsIds');
898
        foreach ($variantsI18n as $exId => $variantI18n) {
899
            $variantsI18n[$exId]['id'] = $this->variantsIds[$exId];
0 ignored issues
show
Documentation introduced by
The property variantsIds does not exist on object<exchange\classes\Products>. Since you implemented __get, maybe consider adding a @property annotation.

Since your code implements the magic getter _get, this function will be called for any read access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

If the property has read access only, you can use the @property-read annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
900
        }
901
902
        $this->updateBatch('shop_product_variants_i18n', $variantsI18n, 'id');
903
904
        $productsIdsWithImages = [];
905
        $additionalImages = [];
906
        $additionalImages_ = &$this->updateCollector->getData('shop_product_images');
907
        $countAddImgs = count($additionalImages_);
908
        for ($i = 0; $i < $countAddImgs; $i++) {
909
            foreach ($additionalImages_[$i] as $addImgData) {
910
                $productsIdsWithImages[] = $addImgData['product_id'];
911
            }
912
            $additionalImages = array_merge($additionalImages, $additionalImages_[$i]);
913
        }
914
        if ($productsIdsWithImages) {
915
            $this->db
916
                ->where_in('product_id', array_unique($productsIdsWithImages))
917
                ->delete('shop_product_images');
918
        }
919
920
        $this->insertBatch('shop_product_images', $additionalImages);
921
    }
922
923
    /**
924
     * Helper-method for updating
925
     * @param string $tableName
926
     * @param string $compareField
927
     * @throws \Exception
928
     */
929
    protected function updateFromCollector($tableName, $compareField) {
930
931
        $this->updateBatch($tableName, $this->updateCollector->getData($tableName), $compareField);
932
    }
933
934
    // ----------------------- end of HELPERS ------------------------------
935
936
    /**
937
     * Set shop categories for products
938
     * @throws Exception
939
     */
940
    public function rebuildAdditionalParentsCats() {
941
942
        $ids = [];
943
944
        foreach ($this->products as $products) {
0 ignored issues
show
Bug introduced by
The property products does not seem to exist. Did you mean existingProductsIds?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
945
            $ids[] = $products['id'];
946
        }
947
948
        $products = $this->db
949
            ->select('shop_products.category_id, shop_products.id, shop_category.full_path_ids, shop_category.parent_id, shop_category.id as cat_id')
950
            ->join('shop_category', 'shop_category.id = shop_products.category_id')
951
            ->where_in('shop_products.id', $ids)
952
            ->get('shop_products')
953
            ->result();
954
955
        foreach ($products as $p) {
956
            $this->parentCat[$p->id] = $p->category_id;
957
        }
958
959
        if ($this->ignoreExistingProducts) {
960
            // deleting only "path categories" data (parents)
961
            foreach ($this->additionalParentsCategories as $productId => $parentCategoriesIds) {
962
963
                array_push($parentCategoriesIds, $this->parentCat[$productId]);
964
                if ($parentCategoriesIds and in_array($productId, $ids)) {
965
                    $this->db
966
                        ->where('product_id', $productId)
967
                        ->where_in('category_id', $parentCategoriesIds)
968
                        ->delete('shop_product_categories');
969
                }
970
            }
971
        } else {
972
            $this->db->where_in('product_id', $ids)->delete('shop_product_categories');
973
        }
974
975
        foreach ($products as $product) {
976
            $pathIds = unserialize($product->full_path_ids);
977
978
            array_push($pathIds, $product->cat_id);
979
            foreach ($pathIds as $categoryId) {
980
                $this->db->insert(
981
                    'shop_product_categories',
982
                    [
983
                     'category_id' => $categoryId,
984
                     'product_id'  => $product->id,
985
                    ]
986
                );
987
            }
988
        }
989
    }
990
991
    private function runResize() {
992
993
        if ($this->runResize) {
994
            Image::create()
995
                ->resizeByName($this->imagesToResize)
996
                ->resizeByNameAdditional(array_unique($this->imagesToResizeAdditional));
997
        }
998
    }
999
1000
    protected function rebuildProductProperties() {
1001
1002
        $productTableProperties = $this->db->select('shop_product_properties_data.property_id, shop_product_property_value_i18n.value, shop_product_property_value_i18n.locale')
1003
            ->from('shop_product_properties_data')
1004
            ->join('shop_product_property_value', 'shop_product_properties_data.value_id = shop_product_property_value.id')
1005
            ->join('shop_product_property_value_i18n', 'shop_product_property_value.id = shop_product_property_value_i18n.id')
1006
            ->get()->result_array();
1007
1008
        $propertiesTableValues = $this->db->select('id, data, locale')->get('shop_product_properties_i18n')->result_array();
1009
1010
        //  array:
1011
        //      [property_id][array property_locales][array property_values]
1012
1013
        $productPropertiesOrdered = [];
1014
1015
        foreach ($productTableProperties as $one) {
1016
            if (!isset($productPropertiesOrdered[$one['property_id']])) {
1017
                $productPropertiesOrdered[$one['property_id']] = [];
1018
            }
1019
            if (!isset($productPropertiesOrdered[$one['property_id']][$one['locale']])) {
1020
                $productPropertiesOrdered[$one['property_id']][$one['locale']] = [];
1021
            }
1022
            if (!in_array($one['value'], $productPropertiesOrdered[$one['property_id']][$one['locale']], true)) {
1023
                array_push($productPropertiesOrdered[$one['property_id']][$one['locale']], $one['value']);
1024
            }
1025
        }
1026
1027
        foreach ($propertiesTableValues as $one) {
1028
            $id = $one['id'];
1029
            $locale = $one['locale'];
1030
            $insertData = [];
1031
            $res = true;
1032
            $error = false;
1033
1034
            if (array_key_exists($id, $productPropertiesOrdered) && array_key_exists($locale, $productPropertiesOrdered[$id])) {
1035
                $onePropertyValues = unserialize($one['data']) ?: [];
1036
                $insertData['data'] = serialize(array_unique(array_merge($onePropertyValues, $productPropertiesOrdered[$id][$locale])));
1037
                $res = $res && $this->db->where('id', $id)->update('shop_product_properties_i18n', $insertData);
0 ignored issues
show
Unused Code introduced by
$res is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
1038
                $error = $this->db->_error_message() ?: $error;
0 ignored issues
show
Unused Code introduced by
$error is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
1039
            }
1040
        }
1041
    }
1042
1043
    /**
1044
     * @param bool $run_resize
1045
     * @return $this
1046
     */
1047
    public function setResize($run_resize = FALSE) {
1048
1049
        $this->runResize = $run_resize;
1050
        return $this;
1051
    }
1052
1053
    /**
1054
     * Setting temporary folder with import data. Mantadory!
1055
     * @param string $tempDir
1056
     * @return $this
1057
     */
1058
    public function setTempDir($tempDir) {
1059
1060
        $this->tempDir = $tempDir;
1061
        return $this;
1062
    }
1063
1064
    private function getPropertyValueIdOrCreate($propertyId, $value, $locale) {
1065
        $valueModel = \SPropertyValueQuery::create()
1066
            ->joinWithI18n($locale, Criteria::INNER_JOIN)
1067
            ->useI18nQuery($locale)
1068
            ->filterByValue($value)
1069
            ->endUse()
1070
            ->filterByPropertyId($propertyId)
1071
            ->findOne();
1072
1073
        if (!$valueModel) {
1074
            $valueModel = new \SPropertyValue();
1075
            $valueModel->setPropertyId($propertyId)
1076
                ->setValue($value)
1077
                ->setLocale($locale)
1078
                ->save();
1079
1080
        }
1081
1082
        return $valueModel->getId();
1083
    }
1084
1085
    private function prepareProductPropertiesData($propertiesData) {
1086
1087
        $data = [];
1088
        foreach ($propertiesData as $key => $item) {
1089
1090
            $dataItem = [
1091
                         'property_id' => $item['property_id'],
1092
                         'product_id'  => $item['product_id'],
1093
                         'value_id'    => $this->getPropertyValueIdOrCreate($item['property_id'], $item['value'], $item['locale']),
1094
1095
                        ];
1096
            $data[] = $dataItem;
1097
        }
1098
1099
        return $data;
1100
    }
1101
1102
}