Completed
Push — master ( 4c9730...bcd28a )
by Jonas
14s
created

ConnectExport::addGroupBy()   A

Complexity

Conditions 5
Paths 5

Size

Total Lines 20

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 5
nc 5
nop 2
dl 0
loc 20
rs 9.2888
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 Doctrine\DBAL\DBALException;
11
use Shopware\Connect\SDK;
12
use Shopware\CustomModels\Connect\Attribute;
13
use ShopwarePlugins\Connect\Components\Marketplace\MarketplaceGateway;
14
use ShopwarePlugins\Connect\Components\Validator\ProductAttributesValidator;
15
use Shopware\Components\Model\ModelManager;
16
use Shopware\Models\Article\Article;
17
use Shopware\Models\Article\Detail;
18
use Shopware\Models\Category\Category;
19
use ShopwarePlugins\Connect\Components\ProductStream\ProductStreamsAssignments;
20
use ShopwarePlugins\Connect\Struct\ExportList;
21
use ShopwarePlugins\Connect\Struct\SearchCriteria;
22
use Enlight_Event_EventManager;
23
24
class ConnectExport
25
{
26
    const BATCH_SIZE = 200;
27
28
    /** @var
29
     * Helper
30
     */
31
    protected $helper;
32
33
    /** @var
34
     * SDK
35
     */
36
    protected $sdk;
37
38
    /** @var
39
     * ModelManager
40
     */
41
    protected $manager;
42
43
    /**
44
     * @var ProductAttributesValidator
45
     */
46
    protected $productAttributesValidator;
47
48
    /** @var
49
     * MarketplaceGateway
50
     */
51
    protected $marketplaceGateway;
52
53
    /**
54
     * @var ErrorHandler
55
     */
56
    protected $errorHandler;
57
58
    /**
59
     * @var Config
60
     */
61
    protected $configComponent;
62
63
    /**
64
     * @var Enlight_Event_EventManager
65
     */
66
    private $eventManager;
67
68
    /**
69
     * ConnectExport constructor.
70
     * @param Helper $helper
71
     * @param SDK $sdk
72
     * @param ModelManager $manager
73
     * @param ProductAttributesValidator $productAttributesValidator
74
     * @param Config $configComponent
75
     * @param \ShopwarePlugins\Connect\Components\ErrorHandler $errorHandler
76
     * @param Enlight_Event_EventManager $eventManager
77
     */
78
    public function __construct(
79
        Helper $helper,
80
        SDK $sdk,
81
        ModelManager $manager,
82
        ProductAttributesValidator $productAttributesValidator,
83
        Config $configComponent,
84
        ErrorHandler $errorHandler,
85
        Enlight_Event_EventManager $eventManager
86
    ) {
87
        $this->helper = $helper;
88
        $this->sdk = $sdk;
89
        $this->manager = $manager;
90
        $this->productAttributesValidator = $productAttributesValidator;
91
        $this->configComponent = $configComponent;
92
        $this->errorHandler = $errorHandler;
93
        $this->eventManager = $eventManager;
94
    }
95
96
    /**
97
     * Load article entity
98
     *
99
     * @param $id
100
     * @return null|\Shopware\Models\Article\Article
101
     */
102
    public function getArticleModelById($id)
103
    {
104
        return $this->manager->getRepository('Shopware\Models\Article\Article')->find($id);
105
    }
106
107
    /**
108
     * Load article detail entity
109
     *
110
     * @param $id
111
     * @return null|\Shopware\Models\Article\Detail
112
     */
113
    public function getArticleDetailById($id)
114
    {
115
        return $this->manager->getRepository('Shopware\Models\Article\Detail')->find($id);
116
    }
117
118
    /**
119
     * Helper function to mark a given array of source ids for connect update
120
     *
121
     * There is a problem with flush when is called from life cycle event in php7,
122
     * this flag '$isEvent' is preventing the flush
123
     *
124
     * @param array $ids
125
     * @param ProductStreamsAssignments|null $streamsAssignments
126
     * @return array
127
     */
128
    public function export(array $ids, ProductStreamsAssignments $streamsAssignments = null)
129
    {
130
        $ids = $this->eventManager->filter(
131
            'Connect_Supplier_Get_Products_Filter_Source_IDS',
132
            $ids,
133
            [
134
                'subject' => $this
135
            ]
136
        );
137
138
        $connectItems = $this->fetchConnectItems($ids);
139
140
        $this->eventManager->notify(
141
            'Connect_Supplier_Get_All_Products_Before',
142
            [
143
                'subject' => $this,
144
                'products' => $connectItems
145
            ]
146
        );
147
148
        $this->manager->beginTransaction();
149
        $excludeInactiveProducts = $this->configComponent->getConfig('excludeInactiveProducts');
0 ignored issues
show
Bug introduced by
Are you sure the assignment to $excludeInactiveProducts is correct as $this->configComponent->...cludeInactiveProducts') (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...
150
151
        foreach ($connectItems as &$item) {
152
            $model = $this->getArticleDetailById($item['articleDetailId']);
153
            if ($model === null) {
154
                continue;
155
            }
156
157
            $connectAttribute = $this->helper->getOrCreateConnectAttributeByModel($model);
158
159
            if ($excludeInactiveProducts && !$model->getActive()) {
160
                $this->updateLocalConnectItem(
161
                    $connectAttribute->getSourceId(),
162
                    [
163
                        'export_status' => Attribute::STATUS_INACTIVE,
164
                        'exported' => false,
165
                        'export_message' =>  Shopware()->Snippets()->getNamespace('backend/connect/view/main')->get(
166
                            'export/message/error_product_is_not_active',
167
                            'Produkt ist inaktiv',
168
                            true
169
                        ),
170
                    ]
171
                );
172
                $this->manager->refresh($connectAttribute);
173
                continue;
174
            }
175
176
            if (!$this->helper->isProductExported($connectAttribute)) {
177
                $status = Attribute::STATUS_INSERT;
178
            } else {
179
                $status = Attribute::STATUS_UPDATE;
180
            }
181
182
            $categories = $this->helper->getConnectCategoryForProduct($item['articleId']);
183
            if (is_string($categories)) {
184
                $categories = [$categories];
185
            }
186
            $categories = json_encode($categories);
187
188
            $this->updateLocalConnectItem(
189
                $connectAttribute->getSourceId(),
190
                [
191
                    'export_status' => $status,
192
                    'export_message' => null,
193
                    'exported' => true,
194
                    'category' => $categories,
195
                ]
196
            );
197
198
            try {
199
                $this->productAttributesValidator->validate($this->extractProductAttributes($model));
200
                if ($status == Attribute::STATUS_INSERT) {
201
                    $this->sdk->recordInsert($item['sourceId']);
202
                } else {
203
                    $this->sdk->recordUpdate($item['sourceId']);
204
                }
205
206
                if ($this->helper->isMainVariant($item['sourceId']) &&
207
                    $streamsAssignments !== null &&
208
                    $streamsAssignments->getStreamsByArticleId($item['articleId']) !== null
209
                ) {
210
                    $this->sdk->recordStreamAssignment(
211
                        $item['sourceId'],
212
                        $streamsAssignments->getStreamsByArticleId($item['articleId']),
213
                        $item['groupId']
214
                    );
215
                }
216
            } catch (\Exception $e) {
217
                if ($this->errorHandler->isPriceError($e)) {
218
                    $this->updateLocalConnectItem(
219
                        $connectAttribute->getSourceId(),
220
                        [
221
                            'export_status' => Attribute::STATUS_ERROR_PRICE,
222
                            'export_message' => Shopware()->Snippets()->getNamespace('backend/connect/view/main')->get(
223
                                'export/message/error_price_status',
224
                                'There is an empty price field',
225
                                true
226
                            ),
227
                        ]
228
                    );
229
                } else {
230
                    $this->updateLocalConnectItem(
231
                        $connectAttribute->getSourceId(),
232
                        [
233
                            'export_status' => Attribute::STATUS_ERROR,
234
                            'export_message' => $e->getMessage() . "\n" . $e->getTraceAsString(),
235
                        ]
236
                    );
237
                }
238
239
                $this->errorHandler->handle($e);
240
            }
241
            $this->manager->refresh($connectAttribute);
242
        }
243
244
        try {
245
            $this->manager->commit();
246
        } catch (\Exception $e) {
247
            $this->manager->rollback();
248
            $this->errorHandler->handle($e);
249
        }
250
251
        return $this->errorHandler->getMessages();
252
    }
253
254
    public function processChanged(array $ids)
255
    {
256
        $deleted = $this->manager->getConnection()->executeQuery(
257
            'SELECT ci.source_id
258
            FROM s_plugin_connect_items AS ci
259
            LEFT JOIN s_articles_details AS ad ON ad.id = ci.article_detail_id
260
            WHERE ad.id IS NULL AND ci.source_id IN (?)',
261
            [$ids],
262
            [\Doctrine\DBAL\Connection::PARAM_STR_ARRAY]
263
        )->fetchAll(\PDO::FETCH_COLUMN);
264
265
        $inactive = $this->manager->getConnection()->executeQuery(
266
            'SELECT ci.source_id
267
             FROM s_plugin_connect_items AS ci
268
             JOIN s_articles as a ON ci.article_id = a.id
269
             WHERE a.active = 0 AND ci.source_id IN (?)',
270
            [$ids],
271
            [\Doctrine\DBAL\Connection::PARAM_STR_ARRAY]
272
        )->fetchAll(\PDO::FETCH_COLUMN);
273
        $deleted = array_merge($deleted, $inactive);
274
275
        $updatedIds = array_diff($ids, $deleted);
276
        if ($updatedIds === null) {
277
            $updatedIds = [];
278
        }
279
        $this->export($updatedIds);
280
281
        $this->markProductsDeleted($deleted);
282
        $this->markProductsDeleted($inactive);
283
    }
284
285
    /**
286
     * @param array $ids
287
     */
288
    private function markProductsDeleted($ids)
289
    {
290
        foreach ($ids as $sourceId) {
291
            $this->recordDelete($sourceId);
292
        }
293
294
        $this->manager->getConnection()->executeQuery(
295
            'UPDATE s_plugin_connect_items SET export_status = ? WHERE source_id IN (?)',
296
            [Attribute::STATUS_DELETE, $ids],
297
            [\PDO::PARAM_STR, \Doctrine\DBAL\Connection::PARAM_STR_ARRAY]
298
        );
299
    }
300
301
    /**
302
     * Update connect attribute data
303
     *
304
     * @param string $sourceId
305
     * @param array $params
306
     */
307
    private function updateLocalConnectItem($sourceId, $params = [])
308
    {
309
        if (empty($params)) {
310
            return;
311
        }
312
        $possibleValues = [
313
            Attribute::STATUS_DELETE,
314
            Attribute::STATUS_INSERT,
315
            Attribute::STATUS_UPDATE,
316
            Attribute::STATUS_ERROR,
317
            Attribute::STATUS_ERROR_PRICE,
318
            Attribute::STATUS_INACTIVE,
319
            Attribute::STATUS_SYNCED,
320
            null,
321
        ];
322
323
        if (isset($params['export_status']) && !in_array($params['export_status'], $possibleValues)) {
324
            throw new \InvalidArgumentException('Invalid export status');
325
        }
326
327
        if (isset($params['exported']) && !is_bool($params['exported'])) {
328
            throw new \InvalidArgumentException('Parameter $exported must be boolean.');
329
        }
330
331
        $builder = $this->manager->getConnection()->createQueryBuilder();
332
        $builder->update('s_plugin_connect_items', 'ci');
333
        array_walk($params, function ($param, $name) use ($builder) {
334
            $builder->set('ci.' . $name, ':' . $name)
335
                    ->setParameter($name, $param);
336
        });
337
338
        $builder->where('source_id = :sourceId')
339
                ->setParameter('sourceId', $sourceId)
340
                ->andWhere('shop_id IS NULL')
341
                ->execute();
342
    }
343
344
    /**
345
     * Fetch connect items
346
     * Default order is main variant first, after that regular variants.
347
     * This is needed, because first received variant with an unknown groupId in Connect
348
     * will be selected as main variant.
349
     *
350
     * @param array $sourceIds
351
     * @param bool $orderByMainVariants
352
     * @return array
353
     */
354
    public function fetchConnectItems(array $sourceIds, $orderByMainVariants = true)
355
    {
356
        if (count($sourceIds) == 0) {
357
            return [];
358
        }
359
360
        $implodedIds = '"' . implode('","', $sourceIds) . '"';
361
        $query = "SELECT bi.article_id as articleId,
362
                    bi.article_detail_id as articleDetailId,
363
                    bi.export_status as exportStatus,
364
                    bi.export_message as exportMessage,
365
                    bi.source_id as sourceId,
366
                    bi.exported,
367
                    a.name as title,
368
                    IF (a.configurator_set_id IS NOT NULL, a.id, NULL) as groupId,
369
                    d.ordernumber as number
370
            FROM s_plugin_connect_items bi
371
            LEFT JOIN s_articles a ON bi.article_id = a.id
372
            LEFT JOIN s_articles_details d ON bi.article_detail_id = d.id
373
            WHERE bi.source_id IN ($implodedIds)";
374
375
        if ($orderByMainVariants === false) {
376
            $query .= ';';
377
378
            return Shopware()->Db()->fetchAll($query);
379
        }
380
381
        $query .= 'AND d.kind = ?;';
382
        $mainVariants = Shopware()->Db()->fetchAll($query, [1]);
383
        $regularVariants = Shopware()->Db()->fetchAll($query, [2]);
384
385
        return array_merge($mainVariants, $regularVariants);
386
    }
387
388
    /**
389
     * Helper function to return export product ids
390
     * @return array
391
     */
392
    public function getExportArticlesIds()
393
    {
394
        $builder = $this->manager->createQueryBuilder();
395
        $builder->from('Shopware\CustomModels\Connect\Attribute', 'at');
396
        $builder->join('at.article', 'a');
397
        $builder->join('a.mainDetail', 'd');
398
        $builder->leftJoin('d.prices', 'p', 'with', "p.from = 1 AND p.customerGroupKey = 'EK'");
399
        $builder->leftJoin('a.supplier', 's');
400
        $builder->leftJoin('a.tax', 't');
401
402
        $builder->select(['a.id']);
403
404
        $builder->where("at.exportStatus = 'update' OR at.exportStatus = 'insert' OR at.exportStatus = 'error'");
405
        $builder->andWhere('at.shopId IS NULL');
406
407
        $query = $builder->getQuery();
408
        $articles = $query->getArrayResult();
409
410
        $ids = [];
411
        foreach ($articles as $article) {
412
            $ids[] = $article['id'];
413
        }
414
415
        return $ids;
416
    }
417
418
    /**
419
     * Helper function to count how many changes
420
     * are waiting to be synchronized
421
     *
422
     * @return int
423
     */
424
    public function getChangesCount()
425
    {
426
        $sql = 'SELECT COUNT(*) FROM `sw_connect_change`';
427
428
        return (int) Shopware()->Db()->fetchOne($sql);
429
    }
430
431
    /**
432
     * Mark single connect product detail for delete
433
     *
434
     * @param \Shopware\Models\Article\Detail $detail
435
     */
436
    public function syncDeleteDetail(Detail $detail)
437
    {
438
        $attribute = $this->helper->getConnectAttributeByModel($detail);
439
        // force fetching ConnectAttribute from DB
440
        // if it was update via query builder
441
        // changes are not visible, because of doctrine proxy cache
442
        $this->manager->refresh($attribute);
443
444
        if (!$this->helper->isProductExported($attribute)) {
445
            return;
446
        }
447
        $this->sdk->recordDelete($attribute->getSourceId());
448
        $attribute->setExportStatus(Attribute::STATUS_DELETE);
449
        $attribute->setExported(false);
450
        $this->manager->persist($attribute);
451
        $this->manager->flush($attribute);
452
    }
453
454
    /**
455
     * Mark all product variants for delete
456
     *
457
     * @param Article $article
458
     */
459
    public function setDeleteStatusForVariants(Article $article)
460
    {
461
        $builder = $this->manager->createQueryBuilder();
462
        $builder->select(['at.sourceId'])
463
            ->from('Shopware\CustomModels\Connect\Attribute', 'at')
464
            ->where('at.articleId = :articleId')
465
            ->andWhere('at.exported = 1')
466
            ->setParameter(':articleId', $article->getId());
467
        $connectItems = $builder->getQuery()->getArrayResult();
468
469
        foreach ($connectItems as $item) {
470
            $this->sdk->recordDelete($item['sourceId']);
471
        }
472
473
        $builder = $this->manager->createQueryBuilder();
474
        $builder->update('Shopware\CustomModels\Connect\Attribute', 'at')
475
            ->set('at.exportStatus', $builder->expr()->literal(Attribute::STATUS_DELETE))
476
            ->set('at.exported', 0)
477
            ->where('at.articleId = :articleId')
478
            ->setParameter(':articleId', $article->getId());
479
480
        $builder->getQuery()->execute();
481
    }
482
483
    /**
484
     * @param array $sourceIds
485
     * @param $status
486
     */
487
    public function updateConnectItemsStatus(array $sourceIds, $status)
488
    {
489
        if (empty($sourceIds)) {
490
            return;
491
        }
492
493
        $chunks = array_chunk($sourceIds, self::BATCH_SIZE);
494
495
        $exported = false;
496
        if ($status == Attribute::STATUS_DELETE) {
497
            $exported = true;
498
        }
499
500
        foreach ($chunks as $chunk) {
501
            $builder = $this->manager->getConnection()->createQueryBuilder();
502
            $builder->update('s_plugin_connect_items', 'ci')
503
                ->set('ci.export_status', ':status')
504
                ->set('ci.exported', ':exported')
505
                ->where('source_id IN (:sourceIds)')
506
                ->setParameter('sourceIds', $chunk, \Doctrine\DBAL\Connection::PARAM_STR_ARRAY)
507
                ->setParameter('status', $status)
508
                ->setParameter('exported', $exported)
509
                ->execute();
510
        }
511
    }
512
513
    /**
514
     * @param SearchCriteria $criteria
515
     * @return ExportList
516
     */
517
    public function getExportList(SearchCriteria $criteria)
518
    {
519
        $customProductsTableExists = false;
520
        try {
521
            $builder = $this->manager->getConnection()->createQueryBuilder();
522
            $builder->select('id');
523
            $builder->from('s_plugin_custom_products_template');
524
            $builder->setMaxResults(1);
525
            $builder->execute()->fetch();
526
527
            $customProductsTableExists = true;
528
        } catch (DBALException $e) {
0 ignored issues
show
Bug introduced by
The class Doctrine\DBAL\DBALException does not exist. Did you forget a USE statement, or did you not list all dependencies?

Scrutinizer analyzes your composer.json/composer.lock file if available to determine the classes, and functions that are defined by your dependencies.

It seems like the listed class was neither found in your dependencies, nor was it found in the analyzed files in your repository. If you are using some other form of dependency management, you might want to disable this analysis.

Loading history...
529
            // ignore it
530
            // custom products is not installed
531
        }
532
533
        $builder = $this->manager->getConnection()->createQueryBuilder();
534
        $builder->select([
535
            'a.id',
536
            'd.ordernumber as number',
537
            'd.inStock as inStock',
538
            'a.name as name',
539
            's.name as supplier',
540
            'a.active as active',
541
            't.tax as tax',
542
            'p.price * (100 + t.tax) / 100 as price',
543
            'i.category',
544
            'i.export_status as exportStatus',
545
            'i.export_message as exportMessage',
546
            'i.cron_update as cronUpdate'
547
        ])
548
            ->from('s_plugin_connect_items', 'i')
549
            ->leftJoin('i', 's_articles', 'a', 'a.id = i.article_id')
550
            ->leftJoin('a', 's_articles_details', 'd', 'a.main_detail_id = d.id')
551
            ->leftJoin('d', 's_articles_prices', 'p', 'd.id = p.articledetailsID')
552
            ->leftJoin('a', 's_core_tax', 't', 'a.taxID = t.id')
553
            ->leftJoin('a', 's_articles_supplier', 's', 'a.supplierID = s.id')
554
            ->where('i.shop_id IS NULL');
555
556
        if ($customProductsTableExists) {
557
            $builder->addSelect('IF(spcptpr.template_id > 0, 1, 0) as customProduct')
558
                    ->leftJoin('a', 's_plugin_custom_products_template_product_relation', 'spcptpr', 'a.id = spcptpr.article_id');
559
        }
560
561
        if ($criteria->search) {
562
            $builder->andWhere('d.ordernumber LIKE :search OR a.name LIKE :search OR s.name LIKE :search')
563
                ->setParameter('search', $criteria->search);
564
        }
565
566
        if ($criteria->categoryId) {
567
568
            // Get all children categories
569
            $qBuilder = $this->manager->getConnection()->createQueryBuilder();
570
            $qBuilder->select('c.id');
571
            $qBuilder->from('s_categories', 'c');
572
            $qBuilder->where('c.path LIKE :categoryIdSearch');
573
            $qBuilder->orWhere('c.id = :categoryId');
574
            $qBuilder->setParameter(':categoryId', $criteria->categoryId);
575
            $qBuilder->setParameter(':categoryIdSearch', "%|$criteria->categoryId|%");
576
577
            $categoryIds = $qBuilder->execute()->fetchAll(\PDO::FETCH_COLUMN);
578
579
            if (count($categoryIds) === 0) {
580
                $categoryIds = [$criteria->categoryId];
581
            }
582
583
            $builder->innerJoin('a', 's_articles_categories', 'sac', 'a.id = sac.articleID')
584
                ->andWhere('sac.categoryID IN (:categoryIds)')
585
                ->setParameter('categoryIds', $categoryIds, \Doctrine\DBAL\Connection::PARAM_STR_ARRAY);
586
        }
587
588
        if ($criteria->supplierId) {
589
            $builder->andWhere('a.supplierID = :supplierId')
590
                ->setParameter('supplierId', $criteria->supplierId);
591
        }
592
593
        if ($criteria->exportStatus) {
594
            $errorStatuses = [Attribute::STATUS_ERROR, Attribute::STATUS_ERROR_PRICE];
595
596
            if (in_array($criteria->exportStatus, $errorStatuses)) {
597
                $builder->andWhere('i.export_status IN (:status)')
598
                    ->setParameter('status', $errorStatuses, \Doctrine\DBAL\Connection::PARAM_STR_ARRAY);
599
            } elseif ($criteria->exportStatus == Attribute::STATUS_INACTIVE) {
600
                $builder->andWhere('a.active = :status')
601
                    ->setParameter('status', false);
602
            } else {
603
                $builder->andWhere('i.export_status LIKE :status')
604
                    ->setParameter('status', $criteria->exportStatus);
605
            }
606
        }
607
608
        if ($criteria->active) {
609
            $builder->andWhere('a.active = :active')
610
                ->setParameter('active', $criteria->active);
611
        }
612
613
        if ($criteria->orderBy) {
614
            $this->addGroupBy($criteria, $builder);
615
        }
616
617
        $totalBuilder = clone $builder;
618
        $builder->groupBy('i.article_id');
619
        $builder->setFirstResult($criteria->offset);
620
        $builder->setMaxResults($criteria->limit);
621
        $data = $builder->execute()->fetchAll();
622
623
        $totalBuilder->select('COUNT(DISTINCT a.id)');
624
        $total = $totalBuilder->execute()->fetchColumn();
625
626
        return new ExportList([
627
            'articles' => $data,
628
            'count' => $total,
629
        ]);
630
    }
631
632
    public function clearConnectItems()
633
    {
634
        $this->deleteAllConnectProducts();
635
        $this->resetConnectItemsStatus();
636
    }
637
638
    /**
639
     * @param int $articleId
640
     */
641
    public function markArticleForCronUpdate($articleId)
642
    {
643
        $this->manager->getConnection()->update(
644
            's_plugin_connect_items',
645
            ['cron_update' => 1],
646
            ['article_id' => (int) $articleId]
647
        );
648
    }
649
650
    /**
651
     * Wrapper method
652
     *
653
     * @param string $sourceId
654
     */
655
    public function recordDelete($sourceId)
656
    {
657
        $this->sdk->recordDelete($sourceId);
658
    }
659
660
    /**
661
     * Deletes products hash
662
     */
663
    private function deleteAllConnectProducts()
664
    {
665
        $builder = $this->manager->getConnection()->createQueryBuilder();
666
        $builder->delete('sw_connect_product');
667
        $builder->execute();
668
    }
669
670
    /**
671
     * Resets all item status
672
     */
673
    private function resetConnectItemsStatus()
674
    {
675
        $builder = $this->manager->getConnection()->createQueryBuilder();
676
        $builder->update('s_plugin_connect_items', 'ci')
677
            ->set('export_status', ':exportStatus')
678
            ->set('revision', ':revision')
679
            ->set('exported', 0)
680
            ->setParameter('exportStatus', null)
681
            ->setParameter('revision', null);
682
683
        $builder->execute();
684
    }
685
686
    private function getMarketplaceGateway()
687
    {
688
        //todo@fixme: Implement better way to get MarketplaceGateway
689
        if (!$this->marketplaceGateway) {
690
            $this->marketplaceGateway = new MarketplaceGateway($this->manager);
691
        }
692
693
        return $this->marketplaceGateway;
694
    }
695
696
    /**
697
     * Extracts all marketplaces attributes from product
698
     *
699
     * @param Detail $detail
700
     * @return array
701
     */
702
    private function extractProductAttributes(Detail $detail)
703
    {
704
        $marketplaceAttributes = [];
705
        $marketplaceAttributes['purchaseUnit'] = $detail->getPurchaseUnit();
706
        $marketplaceAttributes['referenceUnit'] = $detail->getReferenceUnit();
707
708
        // marketplace attributes are available only for SEM shops
709
        if ($this->configComponent->getConfig('isDefault', true)) {
710
            return $marketplaceAttributes;
711
        }
712
713
        foreach ($this->getMarketplaceGateway()->getMappings() as $mapping) {
714
            $shopwareAttribute = $mapping['shopwareAttributeKey'];
715
            $getter = 'get' . ucfirst($shopwareAttribute);
716
717
            if (method_exists($detail->getAttribute(), $getter)) {
718
                $marketplaceAttributes[$shopwareAttribute] = $detail->getAttribute()->{$getter}();
719
            }
720
        }
721
722
        return $marketplaceAttributes;
723
    }
724
725
    /**
726
     * @param Category $category
727
     */
728
    public function markProductsInToBeDeletedCategories(Category $category)
729
    {
730
        $categoryId = $category->getId();
731
        $builder = $this->manager->getConnection()->createQueryBuilder();
732
        $builder->select('categories.id')
733
            ->from('s_categories', 'categories')
734
            ->where('categories.path LIKE :categoryIDs')
735
            ->orWhere('categories.id = :categoryID')
736
            ->setParameter('categoryIDs', "%|$categoryId|%")
737
            ->setParameter('categoryID', $categoryId);
738
        $categoriesToBeDeleted = $builder->execute()->fetchAll(\PDO::FETCH_COLUMN);
739
740
        if ($categoriesToBeDeleted) {
741
            $articlesInDeletedCategories = [];
742
            foreach ($categoriesToBeDeleted as $categoryToBeDeleted) {
743
                //it's necessary to fetch all articleIDs in the deleted categories
744
                //because DQL doesn't allow a join in update
745
                $builder->select('articleCategories.articleID')
746
                    ->from('s_articles_categories', 'articleCategories')
747
                    ->where('articleCategories.categoryID = (:categoryID)')
748
                    ->setParameter('categoryID', $categoryToBeDeleted);
749
                $articlesInCategory = $builder->execute()->fetchAll(\PDO::FETCH_COLUMN);
750
                foreach ($articlesInCategory as $articleId) {
751
                    //trick to get just unique articleIDs -> should be faster than array_unique(array_merge())
752
                    $articlesInDeletedCategories[$articleId] = true;
753
                }
754
            }
755
756
            //we can't export Products directly because Categories are still there
757
            //we are in preRemove
758
            //we just mark them do be updated
759
            if ($articlesInDeletedCategories) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $articlesInDeletedCategories of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
760
                $builder->update('s_plugin_connect_items', 'connectItems')
761
                    ->set('connectItems.cron_update', 1)
762
                    ->where('connectItems.article_id IN (:articleIDs)')
763
                    ->andWhere('connectItems.exported = 1')
764
                    ->setParameter('articleIDs', array_keys($articlesInDeletedCategories), \Doctrine\DBAL\Connection::PARAM_STR_ARRAY);
765
766
                $builder->execute();
767
            }
768
        }
769
    }
770
771
    /**
772
     * exports every article that is marked with cron_update = 1
773
     * this is called in postRemoveCategories
774
     * to change products if their category was deleted
775
     */
776
    public function handleMarkedProducts()
777
    {
778
        $builder = $this->manager->getConnection()->createQueryBuilder();
779
        $builder->select('items.article_id')
780
            ->from('s_plugin_connect_items', 'items')
781
            ->where('items.cron_update = 1');
782
        $articlesToBeExported = $builder->execute()->fetchAll(\PDO::FETCH_COLUMN);
783
784
        if ($articlesToBeExported) {
785
            $this->export($articlesToBeExported);
786
787
            $builder->update('s_plugin_connect_items', 'items')
788
                ->set('items.cron_update', 0);
789
            $builder->execute();
790
        }
791
    }
792
793
    /**
794
     * @param SearchCriteria $criteria
795
     * @param $builder
796
     */
797
    private function addGroupBy(SearchCriteria $criteria, $builder)
798
    {
799
        if ($criteria->orderBy === 'exportStatus') {
800
            $builder->orderBy('i.export_status', $criteria->orderByDirection);
801
            return;
802
        }
803
        if ($criteria->orderBy === 'name') {
804
            $builder->orderBy('a.name', $criteria->orderByDirection);
805
            return;
806
        }
807
        if ($criteria->orderBy === 'supplier') {
808
            $builder->orderBy('s.name', $criteria->orderByDirection);
809
            return;
810
        }
811
        if ($criteria->orderBy === 'number') {
812
            $builder->orderBy('d.ordernumber', $criteria->orderByDirection);
813
            return;
814
        }
815
        $builder->orderBy($criteria->orderBy, $criteria->orderByDirection);
816
    }
817
}
818