Completed
Push — master ( 1a6f67...12dacc )
by Sebastian
05:32
created

Helper::createCategoryWithShopId()   B

Complexity

Conditions 2
Paths 2

Size

Total Lines 24
Code Lines 15

Duplication

Lines 8
Ratio 33.33 %

Importance

Changes 0
Metric Value
cc 2
eloc 15
nc 2
nop 3
dl 8
loc 24
rs 8.9713
c 0
b 0
f 0
1
<?php
2
/**
3
 * (c) shopware AG <[email protected]>
4
 * For the full copyright and license information, please view the LICENSE
5
 * file that was distributed with this source code.
6
 */
7
8
namespace ShopwarePlugins\Connect\Components;
9
10
use Shopware\Connect\Struct\Product;
11
use Shopware\CustomModels\Connect\AttributeRepository;
12
use Shopware\Models\Article\Article as ProductModel;
13
use Shopware\Components\Model\ModelManager;
14
use Doctrine\ORM\Query;
15
use Shopware\CustomModels\Connect\Attribute as ConnectAttribute;
16
use Shopware\CustomModels\Connect\Attribute;
17
use Shopware\Models\Article\Detail as ProductDetail;
18
use Shopware\Models\Article\Unit;
19
use Shopware\Models\Customer\Group;
20
use ShopwarePlugins\Connect\Components\Utils\UnitMapper;
21
use ShopwarePlugins\Connect\Struct\ShopProductId;
22
23
/**
24
 * @category  Shopware
25
 * @package   Shopware\Plugins\SwagConnect
26
 */
27
class Helper
28
{
29
    /**
30
     * @var ModelManager
31
     */
32
    private $manager;
33
34
    /**
35
     * @var CategoryQuery
36
     */
37
    private $connectCategoryQuery;
38
39
    /**
40
     * @var ProductQuery
41
     */
42
    private $connectProductQuery;
43
44
    /**
45
     * @param ModelManager $manager
46
     * @param CategoryQuery
47
     * @param ProductQuery
48
     */
49
    public function __construct(
50
        ModelManager $manager,
51
        CategoryQuery $connectCategoryQuery,
52
        ProductQuery $connectProductQuery
53
    ) {
54
        $this->manager = $manager;
55
        $this->connectCategoryQuery = $connectCategoryQuery;
56
        $this->connectProductQuery = $connectProductQuery;
57
    }
58
59
    /**
60
     * @return Group
61
     */
62
    public function getDefaultCustomerGroup()
63
    {
64
        $repository = $this->manager->getRepository('Shopware\Models\Customer\Group');
65
66
        return $repository->findOneBy(['key' => 'EK']);
67
    }
68
69
    /**
70
     * Returns an article model for a given (sdk) product.
71
     *
72
     * @param Product $product
73
     * @param int $mode
74
     * @return null|ProductModel
75
     */
76 View Code Duplication
    public function getArticleModelByProduct(Product $product, $mode = Query::HYDRATE_OBJECT)
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...
77
    {
78
        $builder = $this->manager->createQueryBuilder();
79
        $builder->select(['ba', 'a']);
80
        $builder->from('Shopware\CustomModels\Connect\Attribute', 'ba');
81
        $builder->join('ba.article', 'a');
82
83
        $builder->where('ba.shopId = :shopId AND ba.sourceId = :sourceId');
84
        $query = $builder->getQuery();
85
86
        $query->setParameter('shopId', $product->shopId);
87
        $query->setParameter('sourceId', (string) $product->sourceId);
88
        $result = $query->getResult(
89
            $mode
90
        );
91
92
        if (isset($result[0])) {
93
            $attribute = $result[0];
94
95
            return $attribute->getArticle();
96
        }
97
98
        return null;
99
    }
100
101
    /**
102
     * @param Product $product
103
     * @param int $mode
104
     * @return null|ProductDetail
105
     */
106 View Code Duplication
    public function getArticleDetailModelByProduct(Product $product, $mode = Query::HYDRATE_OBJECT)
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...
107
    {
108
        $builder = $this->manager->createQueryBuilder();
109
        $builder->select(['ba', 'd']);
110
        $builder->from('Shopware\CustomModels\Connect\Attribute', 'ba');
111
        $builder->join('ba.articleDetail', 'd');
112
        $builder->leftJoin('d.attribute', 'at');
113
        $builder->where('ba.shopId = :shopId AND ba.sourceId = :sourceId');
114
115
        $query = $builder->getQuery();
116
        $query->setParameter('shopId', $product->shopId);
117
        $query->setParameter('sourceId', (string) $product->sourceId);
118
119
        $result = $query->getResult(
120
            $mode
121
        );
122
123
        if (isset($result[0])) {
124
            /** @var \Shopware\CustomModels\Connect\Attribute $attribute */
125
            $attribute = $result[0];
126
127
            return $attribute->getArticleDetail();
128
        }
129
130
        return null;
131
    }
132
133
    /**
134
     * Get article detail by his number
135
     *
136
     * @param string $number
137
     * @return null|ProductDetail
138
     */
139
    public function getDetailByNumber($number)
140
    {
141
        return $this->manager->getRepository(ProductDetail::class)->findOneBy(['number' => $number]);
142
    }
143
144
    public function getConnectArticleModel($sourceId, $shopId)
145
    {
146
        $builder = $this->manager->createQueryBuilder();
147
        $builder->select(['ba', 'a']);
148
        $builder->from('Shopware\CustomModels\Connect\Attribute', 'ba');
149
        $builder->join('ba.article', 'a');
150
        $builder->join('a.mainDetail', 'd');
151
        $builder->leftJoin('d.attribute', 'at');
152
153
        $builder->where('ba.shopId = :shopId AND ba.sourceId = :sourceId');
154
        $query = $builder->getQuery();
155
156
        $query->setParameter('shopId', $shopId);
157
        $query->setParameter('sourceId', (string) $sourceId);
158
        $result = $query->getResult(
159
            $query::HYDRATE_OBJECT
160
        );
161
162
        if (isset($result[0])) {
163
            $attribute = $result[0];
164
165
            return $attribute->getArticle();
166
        }
167
168
        return null;
169
    }
170
171
    /**
172
     * @param array $orderNumbers
173
     * @return array
174
     */
175 View Code Duplication
    public function getArticleIdsByNumber(array $orderNumbers)
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...
176
    {
177
        $builder = $this->manager->getConnection()->createQueryBuilder();
178
179
        $rows = $builder->select('d.articleID as articleId')
180
            ->from('s_articles_details', 'd')
181
            ->where('d.ordernumber IN (:orderNumbers)')
182
            ->setParameter('orderNumbers', $orderNumbers, \Doctrine\DBAL\Connection::PARAM_STR_ARRAY)
183
            ->execute()
184
            ->fetchAll();
185
186
        return array_map(function ($row) {
187
            return $row['articleId'];
188
        }, $rows);
189
    }
190
191
    /**
192
     * Returns article detail model by
193
     * given sourceId and shopId
194
     *
195
     * @param string $sourceId
196
     * @param int $shopId
197
     * @return null|ProductDetail
198
     */
199
    public function getConnectArticleDetailModel($sourceId, $shopId)
200
    {
201
        $product = new Product(['sourceId' => $sourceId, 'shopId' => $shopId]);
202
203
        return $this->getArticleDetailModelByProduct($product);
204
    }
205
206
    /**
207
     * Helper to update the connect_items table
208
     */
209
    public function updateConnectProducts()
210
    {
211
        // Insert new articles
212
        $sql = "
213
        INSERT INTO `s_plugin_connect_items` (article_id, article_detail_id, source_id)
214
        SELECT a.id, ad.id, IF(ad.kind = 1, a.id, CONCAT(a.id, '-', ad.id)) as sourceID
215
216
        FROM s_articles a
217
218
        LEFT JOIN `s_articles_details` ad
219
        ON a.id = ad.articleId
220
221
        LEFT JOIN `s_plugin_connect_items` bi
222
        ON bi.article_detail_id = ad.id
223
224
225
        WHERE a.id IS NOT NULL
226
        AND ad.id IS NOT NULL
227
        AND bi.id IS NULL
228
        ";
229
230
        $this->manager->getConnection()->exec($sql);
231
232
        // Delete removed articles from s_plugin_connect_items
233
        $sql = '
234
        DELETE FROM `s_plugin_connect_items` 
235
        WHERE article_detail_id IS NULL AND NOT cron_update <=> 1
236
        ';
237
238
        $this->manager->getConnection()->exec($sql);
239
    }
240
241
    /**
242
     * Returns wether connect categories have to be recreated or not
243
     * @return bool
244
     */
245
    public function checkIfConnectCategoriesHaveToBeRecreated()
246
    {
247
        $configComponent = ConfigFactory::getConfigInstance();
248
        $result = $configComponent->getConfig('recreateConnectCategories');
0 ignored issues
show
Bug introduced by
Are you sure the assignment to $result is correct as $configComponent->getCon...eateConnectCategories') (which targets ShopwarePlugins\Connect\...nts\Config::getConfig()) seems to always return null.

This check looks for function or method calls that always return null and whose return value is assigned to a variable.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
$object = $a->getObject();

The method getObject() can return nothing but null, so it makes no sense to assign that value to a variable.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
249
250
        return $result === 0;
251
    }
252
253
    /**
254
     * Returns wether shopId has to be added to ConnectCategories
255
     * @return bool
256
     */
257
    public function checkIfShopIdHasToBeAddedToConnectCategories()
258
    {
259
        $configComponent = ConfigFactory::getConfigInstance();
260
        $result = $configComponent->getConfig('addShopIdToConnectCategories');
0 ignored issues
show
Bug introduced by
Are you sure the assignment to $result is correct as $configComponent->getCon...IdToConnectCategories') (which targets ShopwarePlugins\Connect\...nts\Config::getConfig()) seems to always return null.

This check looks for function or method calls that always return null and whose return value is assigned to a variable.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
$object = $a->getObject();

The method getObject() can return nothing but null, so it makes no sense to assign that value to a variable.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
261
262
        return $result === 0;
263
    }
264
265
    /**
266
     * Returns a remote connectProduct e.g. for checkout maniputlations
267
     *
268
     * @param array $ids
269
     * @param int $shopId
270
     * @return array
271
     */
272
    public function getRemoteProducts(array $ids, $shopId)
273
    {
274
        return $this->connectProductQuery->getRemote($ids, $shopId);
275
    }
276
277
    /**
278
     * Returns a local connectProduct for export
279
     *
280
     * @param array $sourceIds
281
     * @return Product[]
282
     */
283
    public function getLocalProduct(array $sourceIds)
284
    {
285
        return $this->connectProductQuery->getLocal($sourceIds);
286
    }
287
288
    /**
289
     * Does the current basket contain connect products?
290
     *
291
     * @param $session
292
     * @return bool
293
     */
294
    public function hasBasketConnectProducts($session, $userId = null)
295
    {
296
        $connection = $this->manager->getConnection();
297
        $sql = 'SELECT ob.articleID
298
299
            FROM s_order_basket ob
300
301
            INNER JOIN s_plugin_connect_items bi
302
            ON bi.article_id = ob.articleID
303
            AND bi.shop_id IS NOT NULL
304
305
            WHERE ob.sessionID=?
306
            ';
307
        $whereClause = [$session];
308
309
        if ($userId > 0) {
310
            $sql .= ' OR userID=?';
311
            $whereClause[] = $userId;
312
        }
313
314
        $sql .= ' LIMIT 1';
315
316
        $result = $connection->fetchArray($sql, $whereClause);
317
318
        return !empty($result);
319
    }
320
321
    /**
322
     * Will return the connectAttribute for a given model. The model can be an Article\Article or Article\Detail
323
     *
324
     * @param $model ProductModel|ProductDetail
325
     * @return ConnectAttribute
326
     */
327
    public function getConnectAttributeByModel($model)
328
    {
329
        if (!$model->getId()) {
330
            return false;
331
        }
332
        $repository = $this->manager->getRepository('Shopware\CustomModels\Connect\Attribute');
333
334
        if ($model instanceof ProductModel) {
0 ignored issues
show
Bug introduced by
The class Shopware\Models\Article\Article does not exist. Did you forget a USE statement, or did you not list all dependencies?

This error could be the result of:

1. Missing dependencies

PHP Analyzer uses your composer.json file (if available) to determine the dependencies of your project and to determine all the available classes and functions. It expects the composer.json to be in the root folder of your repository.

Are you sure this class is defined by one of your dependencies, or did you maybe not list a dependency in either the require or require-dev section?

2. Missing use statement

PHP does not complain about undefined classes in ìnstanceof checks. For example, the following PHP code will work perfectly fine:

if ($x instanceof DoesNotExist) {
    // Do something.
}

If you have not tested against this specific condition, such errors might go unnoticed.

Loading history...
335
            if (!$model->getMainDetail()) {
336
                return false;
337
            }
338
339
            return $repository->findOneBy(['articleDetailId' => $model->getMainDetail()->getId()]);
340
        } elseif ($model instanceof ProductDetail) {
0 ignored issues
show
Bug introduced by
The class Shopware\Models\Article\Detail does not exist. Did you forget a USE statement, or did you not list all dependencies?

This error could be the result of:

1. Missing dependencies

PHP Analyzer uses your composer.json file (if available) to determine the dependencies of your project and to determine all the available classes and functions. It expects the composer.json to be in the root folder of your repository.

Are you sure this class is defined by one of your dependencies, or did you maybe not list a dependency in either the require or require-dev section?

2. Missing use statement

PHP does not complain about undefined classes in ìnstanceof checks. For example, the following PHP code will work perfectly fine:

if ($x instanceof DoesNotExist) {
    // Do something.
}

If you have not tested against this specific condition, such errors might go unnoticed.

Loading history...
341
            return $repository->findOneBy(['articleDetailId' => $model->getId()]);
342
        }
343
344
        return false;
345
    }
346
347
    /**
348
     * Returns connectAttributes for all article details by given article object
349
     *
350
     * @param ProductModel $article
351
     * @return \Shopware\CustomModels\Connect\Attribute[]
352
     */
353
    public function getConnectAttributesByArticle(ProductModel $article)
354
    {
355
        $builder = $this->manager->createQueryBuilder();
356
        $builder->select(['connectAttribute', 'detail']);
357
        $builder->from('Shopware\CustomModels\Connect\Attribute', 'connectAttribute');
358
        $builder->innerJoin('connectAttribute.articleDetail', 'detail');
359
360
        $builder->where('connectAttribute.articleId = :articleId');
361
        $query = $builder->getQuery();
362
363
        $query->setParameter('articleId', $article->getId());
364
365
        return $query->getResult();
366
    }
367
368
    /**
369
     * Returns true when product is exported to Connect
370
     *
371
     * @param Attribute $connectAttribute
372
     * @return bool
373
     */
374
    public function isProductExported(Attribute $connectAttribute)
375
    {
376
        $status = $connectAttribute->getExportStatus();
377
        if ($connectAttribute->isExported()) {
378
            return true;
379
        }
380
381
        if ($status == Attribute::STATUS_INSERT) {
382
            return true;
383
        }
384
385
        if ($status == Attribute::STATUS_UPDATE) {
386
            return true;
387
        }
388
389
        if ($status == Attribute::STATUS_SYNCED) {
390
            return true;
391
        }
392
393
        return false;
394
    }
395
396
    /**
397
     * Verifies that at least one variant from
398
     * same article is exported.
399
     *
400
     * @param Attribute $connectAttribute
401
     * @return bool
402
     */
403
    public function hasExportedVariants(Attribute $connectAttribute)
404
    {
405
        $builder = $this->manager->getConnection()->createQueryBuilder();
406
        $builder->select('COUNT(spci.id)')
407
            ->from('s_plugin_connect_items', 'spci')
408
            ->where('spci.article_id = :articleId AND spci.export_status IN (:exportStatus) AND spci.shop_id IS NULL')
409
            ->setParameter('articleId', $connectAttribute->getArticleId(), \PDO::PARAM_INT)
410
            ->setParameter(
411
                ':exportStatus',
412
                [Attribute::STATUS_INSERT, Attribute::STATUS_UPDATE, Attribute::STATUS_SYNCED],
413
                \Doctrine\DBAL\Connection::PARAM_STR_ARRAY
414
            );
415
416
        return $builder->execute()->fetchColumn() > 0;
417
    }
418
419
    /**
420
     * Helper method to create a connect attribute on the fly
421
     *
422
     * @param $model
423
     * @throws \RuntimeException
424
     * @return ConnectAttribute
425
     */
426
    public function getOrCreateConnectAttributeByModel($model)
427
    {
428
        $attribute = $this->getConnectAttributeByModel($model);
429
430
        if (!$attribute) {
431
            $attribute = new ConnectAttribute();
432
            $attribute->setPurchasePriceHash('');
433
            $attribute->setOfferValidUntil('');
434
            $attribute->setStream('');
435
436
            if ($model instanceof ProductModel) {
0 ignored issues
show
Bug introduced by
The class Shopware\Models\Article\Article does not exist. Did you forget a USE statement, or did you not list all dependencies?

This error could be the result of:

1. Missing dependencies

PHP Analyzer uses your composer.json file (if available) to determine the dependencies of your project and to determine all the available classes and functions. It expects the composer.json to be in the root folder of your repository.

Are you sure this class is defined by one of your dependencies, or did you maybe not list a dependency in either the require or require-dev section?

2. Missing use statement

PHP does not complain about undefined classes in ìnstanceof checks. For example, the following PHP code will work perfectly fine:

if ($x instanceof DoesNotExist) {
    // Do something.
}

If you have not tested against this specific condition, such errors might go unnoticed.

Loading history...
437
                $attribute->setArticle($model);
438
                $attribute->setArticleDetail($model->getMainDetail());
439
                $attribute->setSourceId(
440
                    $this->generateSourceId($model->getMainDetail())
441
                );
442
            } elseif ($model instanceof ProductDetail) {
0 ignored issues
show
Bug introduced by
The class Shopware\Models\Article\Detail does not exist. Did you forget a USE statement, or did you not list all dependencies?

This error could be the result of:

1. Missing dependencies

PHP Analyzer uses your composer.json file (if available) to determine the dependencies of your project and to determine all the available classes and functions. It expects the composer.json to be in the root folder of your repository.

Are you sure this class is defined by one of your dependencies, or did you maybe not list a dependency in either the require or require-dev section?

2. Missing use statement

PHP does not complain about undefined classes in ìnstanceof checks. For example, the following PHP code will work perfectly fine:

if ($x instanceof DoesNotExist) {
    // Do something.
}

If you have not tested against this specific condition, such errors might go unnoticed.

Loading history...
443
                $attribute->setArticle($model->getArticle());
444
                $attribute->setArticleDetail($model);
445
                $attribute->setSourceId(
446
                    $this->generateSourceId($model)
447
                );
448
            } else {
449
                throw new \RuntimeException('Passed model needs to be an article or an article detail');
450
            }
451
            $this->manager->persist($attribute);
452
            $this->manager->flush($attribute);
453
        }
454
455
        return $attribute;
456
    }
457
458
    /**
459
     * Returns connect attributes for article
460
     * and all variants.
461
     * If connect attribute does not exist
462
     * it will be created.
463
     *
464
     * @param ProductModel $article
465
     * @return array
466
     */
467
    public function getOrCreateConnectAttributes(ProductModel $article)
468
    {
469
        $attributes = [];
470
        /** @var \Shopware\Models\Article\Detail $detail */
471
        foreach ($article->getDetails() as $detail) {
472
            $attributes[] = $this->getOrCreateConnectAttributeByModel($detail);
473
        }
474
475
        return $attributes;
476
    }
477
478
    /**
479
     * Generate sourceId
480
     *
481
     * @param ProductDetail $detail
482
     * @return string
483
     */
484
    public function generateSourceId(ProductDetail $detail)
485
    {
486
        if ($detail->getKind() == 1) {
487
            $sourceId = (string) $detail->getArticle()->getId();
488
        } else {
489
            $sourceId = sprintf(
490
                '%s-%s',
491
                $detail->getArticle()->getId(),
492
                $detail->getId()
493
            );
494
        }
495
496
        return $sourceId;
497
    }
498
499
    /**
500
     * @param $id
501
     * @return array
502
     */
503
    public function getConnectCategoryForProduct($id)
504
    {
505
        return $this->connectCategoryQuery->getConnectCategoryForProduct($id);
506
    }
507
508
    public function getMostRelevantConnectCategory($categories)
509
    {
510
        usort(
511
            $categories,
512
            [
513
                $this->connectCategoryQuery->getRelevanceSorter(),
514
                'sortConnectCategoriesByRelevance'
515
            ]
516
        );
517
518
        return array_pop($categories);
519
    }
520
521
    /**
522
     * Defines the update flags
523
     *
524
     * @return array
525
     */
526
    public function getUpdateFlags()
527
    {
528
        return [2 => 'shortDescription', 4 => 'longDescription', 8 => 'name', 16 => 'image', 32 => 'price', 64 => 'imageInitialImport', 128 => 'additionalDescription', 256 => 'mainImage'];
529
    }
530
531
    /**
532
     * Returns shopware unit entity
533
     *
534
     * @param $unitKey
535
     * @return \Shopware\Models\Article\Unit
536
     */
537
    public function getUnit($unitKey)
538
    {
539
        $repository = $this->manager->getRepository('Shopware\Models\Article\Unit');
540
541
        return $repository->findOneBy(['unit' => $unitKey]);
542
    }
543
544
    /**
545
     * Clear article cache
546
     */
547
    public function clearArticleCache($articleId)
548
    {
549
        Shopware()->Events()->notify(
550
            'Shopware_Plugins_HttpCache_InvalidateCacheId',
551
            ['cacheId' => 'a' . $articleId]
552
        );
553
    }
554
555
    /**
556
     * Replace unit and ref quantity
557
     * @param $products
558
     * @return mixed
559
     */
560
    public function prepareConnectUnit($products)
561
    {
562
        foreach ($products as &$p) {
563
            if ($p->attributes['unit']) {
564
                $configComponent = ConfigFactory::getConfigInstance();
565
                /** @var \ShopwarePlugins\Connect\Components\Utils\UnitMapper $unitMapper */
566
                $unitMapper = new UnitMapper(
567
                    $configComponent,
568
                    $this->manager
569
                );
570
571
                $p->attributes['unit'] = $unitMapper->getConnectUnit($p->attributes['unit']);
572
            }
573
574
            if ($p->attributes['ref_quantity']) {
575
                $intRefQuantity = (int) $p->attributes['ref_quantity'];
576
                if ($p->attributes['ref_quantity'] - $intRefQuantity <= 0.0001) {
577
                    $p->attributes['ref_quantity'] = $intRefQuantity;
578
                }
579
            }
580
        }
581
582
        return $products;
583
    }
584
585
    /**
586
     * Removes connect reservation from session
587
     */
588
    public function clearConnectReservation()
589
    {
590
        Shopware()->Session()->connectReservation = null;
591
    }
592
593
    /**
594
     * Collect sourceIds by given article ids
595
     *
596
     * @param array $articleIds
597
     * @return array
598
     */
599
    public function getArticleSourceIds(array $articleIds)
600
    {
601
        if (empty($articleIds)) {
602
            return [];
603
        }
604
605
        /** @var AttributeRepository $repo */
606
        $repo = $this->manager->getRepository(ConnectAttribute::class);
607
608
        return array_merge(
609
            $repo->findSourceIds($articleIds, 1),
610
            $repo->findSourceIds($articleIds, 2)
611
        );
612
    }
613
614
    /**
615
     * Get ShopProductId struct by given article detail id
616
     * It contains product sourceId and shopId.
617
     * If $articleDetailId is local product, $shopProductId->shopId will be null.
618
     *
619
     * @param int $articleDetailId
620
     * @return ShopProductId
621
     */
622
    public function getShopProductId($articleDetailId)
623
    {
624
        $articleDetailId = (int) $articleDetailId;
625
        $builder = $this->manager->getConnection()->createQueryBuilder();
626
        $builder->select('items.source_id as sourceId, items.shop_id as shopId')
627
            ->from('s_plugin_connect_items', 'items')
628
            ->where('items.article_detail_id = :articleDetailIds')
629
            ->setParameter(':articleDetailIds', $articleDetailId);
630
631
        $result = $builder->execute()->fetch(\PDO::FETCH_ASSOC);
632
633
        return new ShopProductId($result);
634
    }
635
636
    /**
637
     * Check if given articleDetailId is remote product
638
     *
639
     * @param int $articleDetailId
640
     * @return bool
641
     */
642
    public function isRemoteArticleDetail($articleDetailId)
643
    {
644
        $articleDetailId = (int) $articleDetailId;
645
        $articleDetailRepository = $this->manager->getRepository('Shopware\Models\Article\Detail');
646
        /** @var \Shopware\Models\Article\Detail $detail */
647
        $detail = $articleDetailRepository->find($articleDetailId);
648
        if (!$detail) {
649
            return false;
650
        }
651
652
        $connectAttribute = $this->getConnectAttributeByModel($detail);
653
        if (!$connectAttribute) {
654
            return false;
655
        }
656
657
        return ($connectAttribute->getShopId() != null);
658
    }
659
660
    /**
661
     * Check if given articleDetailId is remote product
662
     *
663
     * @param int $articleDetailId
664
     * @return bool
665
     */
666
    public function isRemoteArticleDetailDBAL($articleDetailId)
667
    {
668
        $articleDetailId = (int) $articleDetailId;
669
        $builder = $this->manager->getConnection()->createQueryBuilder();
670
        $builder->select('items.shop_id')
671
            ->from('s_plugin_connect_items', 'items')
672
            ->where('items.article_detail_id = :articleDetailId')
673
            ->setParameter(':articleDetailId', $articleDetailId);
674
675
        return (bool) $builder->execute()->fetchColumn();
676
    }
677
678
    /**
679
     * Extract article ID and detail ID
680
     * from source ID
681
     *
682
     * @param $sourceId
683
     * @return array
684
     */
685
    public function explodeArticleId($sourceId)
686
    {
687
        $articleId = explode('-', $sourceId);
688
689
        if (isset($articleId[1]) && isset($articleId[1])) {
690
            return $articleId;
691
        }
692
693
        return [
694
            $articleId[0]
695
        ];
696
    }
697
698
    /**
699
     * Creates Shopware product model
700
     *
701
     * @param Product $product
702
     * @return ProductModel
703
     */
704
    public function createProductModel(Product $product)
705
    {
706
        //todo@sb: Add test
707
        $model = new ProductModel();
708
        $model->setActive(false);
709
        $model->setName($product->title);
710
        $this->manager->persist($model);
711
712
        return $model;
713
    }
714
715
    /**
716
     * Returns main article detail by given groupId
717
     *
718
     * @param $product
719
     * @param int $mode
720
     * @return null|ProductModel
721
     */
722 View Code Duplication
    public function getArticleByRemoteProduct(Product $product, $mode = Query::HYDRATE_OBJECT)
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...
723
    {
724
        $builder = $this->manager->createQueryBuilder();
725
        $builder->select(['ba', 'd']);
726
        $builder->from('Shopware\CustomModels\Connect\Attribute', 'ba');
727
        $builder->join('ba.articleDetail', 'd');
728
        $builder->leftJoin('d.attribute', 'at');
729
730
        $builder->where('ba.groupId = :groupId AND ba.isMainVariant = 1 AND ba.shopId = :shopId');
731
        $query = $builder->getQuery();
732
733
        $query->setParameter('groupId', $product->groupId);
734
        $query->setParameter('shopId', $product->shopId);
735
        $result = $query->getResult(
736
            $mode
737
        );
738
739
        if (isset($result[0])) {
740
            /** @var \Shopware\CustomModels\Connect\Attribute $attribute */
741
            $attribute = $result[0];
742
743
            return $attribute->getArticle();
744
        }
745
746
        return null;
747
    }
748
749
    /**
750
     * @param int $articleId
751
     * @return array
752
     */
753
    public function getSourceIdsFromArticleId($articleId)
754
    {
755
        $rows = $this->manager->getConnection()->fetchAll(
756
            'SELECT source_id FROM s_plugin_connect_items WHERE article_id = ? AND exported = 1',
757
            [$articleId]
758
        );
759
760
        return array_map(function ($row) {
761
            return $row['source_id'];
762
        }, $rows);
763
    }
764
765
    /**
766
     * @param Unit $localUnit
767
     * @param string $remoteUnit
768
     */
769
    public function updateUnitInRelatedProducts(Unit $localUnit, $remoteUnit)
770
    {
771
        $statement = $this->manager->getConnection()->prepare('UPDATE s_articles_details sad
772
            LEFT JOIN s_articles_attributes saa ON sad.id = saa.articledetailsID
773
            SET sad.unitID = :unitId
774
            WHERE saa.connect_remote_unit = :remoteUnit');
775
776
        $statement->bindValue(':unitId', $localUnit->getId(), \PDO::PARAM_INT);
777
        $statement->bindValue(':remoteUnit', $remoteUnit, \PDO::PARAM_STR);
778
779
        $statement->execute();
780
    }
781
782
    /**
783
     * Checks whether given sourceId is main variant.
784
     * Works only with local products.
785
     * SourceIds pattern is articleId-variantId (58-142)
786
     *
787
     * For remote product check is_main_variant flag in
788
     * s_plugin_connect_items
789
     *
790
     * @param string $sourceId
791
     * @return bool
792
     */
793
    public function isMainVariant($sourceId)
794
    {
795
        $isMainVariant = $this->manager->getConnection()->fetchColumn(
796
            'SELECT d.kind
797
              FROM s_plugin_connect_items spci
798
              LEFT JOIN s_articles_details d ON spci.article_detail_id = d.id
799
              WHERE source_id = ?',
800
            [$sourceId]
801
        );
802
803
        if ($isMainVariant != 1) {
804
            return false;
805
        }
806
807
        return true;
808
    }
809
810
    public function getLocalArticleCount()
811
    {
812
        return $this->manager->getRepository(ConnectAttribute::class)->getLocalArticleCount();
813
    }
814
815
    /**
816
     * Recreates ConnectCategories wit the specified offset and batchsize
817
     * @param int $offset
818
     * @param int $batchsize
819
     */
820
    public function recreateConnectCategories($offset, $batchsize)
821
    {
822
        $result = $this->manager->getConnection()->executeQuery(
823
            'SELECT `article_id`, `category`, `shop_id` FROM `s_plugin_connect_items` WHERE shop_id IS NOT NULL GROUP BY `article_id` ORDER BY `id` LIMIT ? OFFSET ?',
824
            [$batchsize, $offset],
825
            [\PDO::PARAM_INT, \PDO::PARAM_INT]
826
        );
827
828
        while ($row = $result->fetch()) {
829
            $categories = json_decode($row['category'], true);
830
            $countAssignedCategories = $this->manager->getConnection()->executeQuery(
831
                'SELECT COUNT(`connect_category_id`) AS categories_count FROM s_plugin_connect_product_to_categories WHERE articleID = ?',
832
                [$row['article_id']]
833
            )->fetchColumn();
834
835
            if (count($categories) != $countAssignedCategories) {
836
                $shopId = $row['shop_id'];
837
                foreach ($categories as $categoryKey => $category) {
838
                    $selectedCategory = $this->manager->getConnection()->executeQuery(
839
                        'SELECT `id` FROM s_plugin_connect_categories WHERE category_key = ? AND shop_id = ?',
840
                        [$categoryKey, $shopId]
841
                    );
842 View Code Duplication
                    if (!($res = $selectedCategory->fetch())) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
843
                        $this->manager->getConnection()->executeQuery(
844
                            'INSERT INTO s_plugin_connect_categories (category_key, label, shop_id) VALUES (?, ?, ?)',
845
                            [$categoryKey, $category, $shopId]
846
                        );
847
                        $categoryId = (int) $this->manager->getConnection()->lastInsertId();
848
                    } else {
849
                        $categoryId = (int) $res['id'];
850
                    }
851
                    $selectedProductToCategory = $this->manager->getConnection()->executeQuery(
852
                        'SELECT COUNT(*) FROM s_plugin_connect_product_to_categories WHERE connect_category_id = ? AND articleID = ?',
853
                        [$categoryId, (int) $row['article_id']]
854
                    )->fetchColumn();
855
                    if ((int) $selectedProductToCategory === 0) {
856
                        $this->manager->getConnection()->executeQuery(
857
                            'INSERT INTO s_plugin_connect_product_to_categories (connect_category_id, articleID) VALUES (?, ?)',
858
                            [$categoryId, (int) $row['article_id']]
859
                            );
860
                    }
861
                }
862
            }
863
        }
864
865
        $totalCount = $this->getProductCountForCategoryRecovery();
866
        if ($batchsize + $offset >= $totalCount) {
867
            $configComponent = ConfigFactory::getConfigInstance();
868
            $configComponent->setConfig('recreateConnectCategories', 1);
869
        }
870
    }
871
872
    /**
873
     * @return int
874
     */
875
    public function getProductCountForCategoryRecovery()
876
    {
877
        return (int) $this->manager->getConnection()->executeQuery('
878
          SELECT COUNT(*) 
879
          FROM (
880
            SELECT COUNT(*) FROM `s_plugin_connect_items` WHERE shop_id IS NOT NULL GROUP BY `article_id`
881
          ) AS Z')->fetchColumn();
882
    }
883
884
    /**
885
     * adds the shopId to the ConnectCategoriesTable
886
     * @param int $offset
887
     * @param int $batchsize
888
     */
889
    public function addShopIdToConnectCategories($offset, $batchsize)
890
    {
891
        $result = $this->manager->getConnection()->executeQuery(
892
            'SELECT `article_id`, `category`, `shop_id` FROM `s_plugin_connect_items` WHERE shop_id IS NOT NULL GROUP BY `article_id` ORDER BY `id` LIMIT ? OFFSET ?',
893
            [$batchsize, $offset],
894
            [\PDO::PARAM_INT, \PDO::PARAM_INT]
895
        );
896
897
        while ($row = $result->fetch()) {
898
            $categories = json_decode($row['category'], true);
899
            $this->manager->getConnection()->executeQuery(
900
                'DELETE FROM s_plugin_connect_product_to_categories WHERE articleID = ?',
901
                [$row['article_id']]
902
            );
903
904
            $shopId = (int) $row['shop_id'];
905
            foreach ($categories as $categoryKey => $category) {
906
                $this->addShopIdToConnectCategory($categoryKey, $shopId, $category, $row);
907
            }
908
        }
909
910
        $totalCount = $this->getProductCountForCategoryRecovery();
911
        if ($batchsize + $offset >= $totalCount) {
912
            $configComponent = ConfigFactory::getConfigInstance();
913
            $configComponent->setConfig('addShopIdToConnectCategories', 1);
914
        }
915
    }
916
917
    /**
918
     * @param $categoryKey
919
     * @param $shopId
920
     * @param $category
921
     * @param $row
922
     */
923
    private function addShopIdToConnectCategory($categoryKey, $shopId, $category, $row)
924
    {
925
        $selectedCategory = $this->manager->getConnection()->executeQuery(
926
            'SELECT `id` FROM s_plugin_connect_categories WHERE category_key = ? AND shop_id = ?',
927
            [$categoryKey, $shopId]
928
        );
929
        if (!($res = $selectedCategory->fetch())) {
930
            $categoryId = $this->createCategoryWithShopId($categoryKey, $shopId, $category);
931
        } else {
932
            $categoryId = (int) $res['id'];
933
        }
934
        $this->manager->getConnection()->executeQuery(
935
            'INSERT INTO s_plugin_connect_product_to_categories (articleID, connect_category_id) VALUES (?, ?)',
936
            [$row['article_id'], $categoryId]
937
        );
938
    }
939
940
    /**
941
     * @param string $categoryKey
942
     * @param int $shopId
943
     * @param string $category
944
     * @return int
945
     */
946
    private function createCategoryWithShopId($categoryKey, $shopId, $category)
947
    {
948
        $selectedCategory = $this->manager->getConnection()->executeQuery(
949
            'SELECT `id` FROM s_plugin_connect_categories WHERE category_key = ? AND shop_id IS NULL',
950
            [$categoryKey]
951
        );
952 View Code Duplication
        if (!($res = $selectedCategory->fetch())) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
953
            $this->manager->getConnection()->executeQuery(
954
                'INSERT INTO s_plugin_connect_categories (category_key, label, shop_id) VALUES (?, ?, ?)',
955
                [$categoryKey, $category, $shopId]
956
            );
957
            $createdCategoryId = (int) $this->manager->getConnection()->lastInsertId();
958
            $this->assignLocalCategories($createdCategoryId, $categoryKey);
959
960
            return $createdCategoryId;
961
        }
962
963
        $this->manager->getConnection()->executeQuery(
964
            'UPDATE s_plugin_connect_categories SET shop_id = ? WHERE id = ?',
965
            [$shopId, $res['id']]
966
        );
967
968
        return (int) $res['id'];
969
    }
970
971
    /**
972
     * @param int $createdCategoryId
973
     * @param string $categoryKey
974
     */
975
    private function assignLocalCategories($createdCategoryId, $categoryKey)
976
    {
977
        $originalCategoryId = $this->manager->getConnection()->fetchColumn(
978
            'SELECT `id` FROM s_plugin_connect_categories WHERE category_key = ? AND id <> ?',
979
            [$categoryKey, $createdCategoryId]
980
        );
981
        $localCategories = $this->manager->getConnection()->executeQuery(
982
            'SELECT `local_category_id` FROM s_plugin_connect_categories_to_local_categories WHERE remote_category_id = ?',
983
            [$originalCategoryId]
984
        )->fetchAll(\PDO::FETCH_COLUMN);
985
986
        foreach ($localCategories as $localCategoryId) {
987
            $this->manager->getConnection()->executeQuery(
988
                'INSERT INTO s_plugin_connect_categories_to_local_categories (remote_category_id, local_category_id) VALUES (?, ?)',
989
                [$createdCategoryId, $localCategoryId]
990
            );
991
        }
992
    }
993
}
994