Completed
Pull Request — master (#452)
by Jonas
03:17
created

ConnectExport::processChanged()   B

Complexity

Conditions 3
Paths 4

Size

Total Lines 27
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 3
eloc 13
nc 4
nop 1
dl 0
loc 27
rs 8.8571
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])->fetchAll(\PDO::FETCH_COLUMN);
263
264
        $updatedIds = array_diff($ids, $deleted);
265
        if ($updatedIds === null)
266
        {
267
            $updatedIds = [];
268
        }
269
        $this->export($updatedIds);
270
271
        foreach ($deleted as $sourceId) {
272
            $this->recordDelete($sourceId);
273
        }
274
275
        $this->manager->getConnection()->executeQuery('
276
            UPDATE s_plugin_connect_items SET export_status = ? WHERE source_id IN (?)',
277
            [Attribute::STATUS_DELETE, $deleted],
278
            [\PDO::PARAM_STR, \Doctrine\DBAL\Connection::PARAM_STR_ARRAY]
279
            );
280
    }
281
    /**
282
     * Update connect attribute data
283
     *
284
     * @param string $sourceId
285
     * @param array $params
286
     */
287
    private function updateLocalConnectItem($sourceId, $params = [])
288
    {
289
        if (empty($params)) {
290
            return;
291
        }
292
        $possibleValues = [
293
            Attribute::STATUS_DELETE,
294
            Attribute::STATUS_INSERT,
295
            Attribute::STATUS_UPDATE,
296
            Attribute::STATUS_ERROR,
297
            Attribute::STATUS_ERROR_PRICE,
298
            Attribute::STATUS_INACTIVE,
299
            Attribute::STATUS_SYNCED,
300
            null,
301
        ];
302
303
        if (isset($params['export_status']) && !in_array($params['export_status'], $possibleValues)) {
304
            throw new \InvalidArgumentException('Invalid export status');
305
        }
306
307
        if (isset($params['exported']) && !is_bool($params['exported'])) {
308
            throw new \InvalidArgumentException('Parameter $exported must be boolean.');
309
        }
310
311
        $builder = $this->manager->getConnection()->createQueryBuilder();
312
        $builder->update('s_plugin_connect_items', 'ci');
313
        array_walk($params, function ($param, $name) use ($builder) {
314
            $builder->set('ci.' . $name, ':' . $name)
315
                    ->setParameter($name, $param);
316
        });
317
318
        $builder->where('source_id = :sourceId')
319
                ->setParameter('sourceId', $sourceId)
320
                ->andWhere('shop_id IS NULL')
321
                ->execute();
322
    }
323
324
    /**
325
     * Fetch connect items
326
     * Default order is main variant first, after that regular variants.
327
     * This is needed, because first received variant with an unknown groupId in Connect
328
     * will be selected as main variant.
329
     *
330
     * @param array $sourceIds
331
     * @param bool $orderByMainVariants
332
     * @return array
333
     */
334
    public function fetchConnectItems(array $sourceIds, $orderByMainVariants = true)
335
    {
336
        if (count($sourceIds) == 0) {
337
            return [];
338
        }
339
340
        $implodedIds = '"' . implode('","', $sourceIds) . '"';
341
        $query = "SELECT bi.article_id as articleId,
342
                    bi.article_detail_id as articleDetailId,
343
                    bi.export_status as exportStatus,
344
                    bi.export_message as exportMessage,
345
                    bi.source_id as sourceId,
346
                    bi.exported,
347
                    a.name as title,
348
                    IF (a.configurator_set_id IS NOT NULL, a.id, NULL) as groupId,
349
                    d.ordernumber as number
350
            FROM s_plugin_connect_items bi
351
            LEFT JOIN s_articles a ON bi.article_id = a.id
352
            LEFT JOIN s_articles_details d ON bi.article_detail_id = d.id
353
            WHERE bi.source_id IN ($implodedIds)";
354
355
        if ($orderByMainVariants === false) {
356
            $query .= ';';
357
358
            return Shopware()->Db()->fetchAll($query);
359
        }
360
361
        $query .= 'AND d.kind = ?;';
362
        $mainVariants = Shopware()->Db()->fetchAll($query, [1]);
363
        $regularVariants = Shopware()->Db()->fetchAll($query, [2]);
364
365
        return array_merge($mainVariants, $regularVariants);
366
    }
367
368
    /**
369
     * Helper function to return export product ids
370
     * @return array
371
     */
372
    public function getExportArticlesIds()
373
    {
374
        $builder = $this->manager->createQueryBuilder();
375
        $builder->from('Shopware\CustomModels\Connect\Attribute', 'at');
376
        $builder->join('at.article', 'a');
377
        $builder->join('a.mainDetail', 'd');
378
        $builder->leftJoin('d.prices', 'p', 'with', "p.from = 1 AND p.customerGroupKey = 'EK'");
379
        $builder->leftJoin('a.supplier', 's');
380
        $builder->leftJoin('a.tax', 't');
381
382
        $builder->select(['a.id']);
383
384
        $builder->where("at.exportStatus = 'update' OR at.exportStatus = 'insert' OR at.exportStatus = 'error'");
385
        $builder->andWhere('at.shopId IS NULL');
386
387
        $query = $builder->getQuery();
388
        $articles = $query->getArrayResult();
389
390
        $ids = [];
391
        foreach ($articles as $article) {
392
            $ids[] = $article['id'];
393
        }
394
395
        return $ids;
396
    }
397
398
    /**
399
     * Helper function to count how many changes
400
     * are waiting to be synchronized
401
     *
402
     * @return int
403
     */
404
    public function getChangesCount()
405
    {
406
        $sql = 'SELECT COUNT(*) FROM `sw_connect_change`';
407
408
        return (int) Shopware()->Db()->fetchOne($sql);
409
    }
410
411
    /**
412
     * Mark single connect product detail for delete
413
     *
414
     * @param \Shopware\Models\Article\Detail $detail
415
     */
416
    public function syncDeleteDetail(Detail $detail)
417
    {
418
        $attribute = $this->helper->getConnectAttributeByModel($detail);
419
        // force fetching ConnectAttribute from DB
420
        // if it was update via query builder
421
        // changes are not visible, because of doctrine proxy cache
422
        $this->manager->refresh($attribute);
423
424
        if (!$this->helper->isProductExported($attribute)) {
425
            return;
426
        }
427
        $this->sdk->recordDelete($attribute->getSourceId());
428
        $attribute->setExportStatus(Attribute::STATUS_DELETE);
429
        $attribute->setExported(false);
430
        $this->manager->persist($attribute);
431
        $this->manager->flush($attribute);
432
    }
433
434
    /**
435
     * Mark all product variants for delete
436
     *
437
     * @param Article $article
438
     */
439
    public function setDeleteStatusForVariants(Article $article)
440
    {
441
        $builder = $this->manager->createQueryBuilder();
442
        $builder->select(['at.sourceId'])
443
            ->from('Shopware\CustomModels\Connect\Attribute', 'at')
444
            ->where('at.articleId = :articleId')
445
            ->andWhere('at.exported = 1')
446
            ->setParameter(':articleId', $article->getId());
447
        $connectItems = $builder->getQuery()->getArrayResult();
448
449
        foreach ($connectItems as $item) {
450
            $this->sdk->recordDelete($item['sourceId']);
451
        }
452
453
        $builder = $this->manager->createQueryBuilder();
454
        $builder->update('Shopware\CustomModels\Connect\Attribute', 'at')
455
            ->set('at.exportStatus', $builder->expr()->literal(Attribute::STATUS_DELETE))
456
            ->set('at.exported', 0)
457
            ->where('at.articleId = :articleId')
458
            ->setParameter(':articleId', $article->getId());
459
460
        $builder->getQuery()->execute();
461
    }
462
463
    /**
464
     * @param array $sourceIds
465
     * @param $status
466
     */
467
    public function updateConnectItemsStatus(array $sourceIds, $status)
468
    {
469
        if (empty($sourceIds)) {
470
            return;
471
        }
472
473
        $chunks = array_chunk($sourceIds, self::BATCH_SIZE);
474
475
        $exported = false;
476
        if ($status == Attribute::STATUS_DELETE) {
477
            $exported = true;
478
        }
479
480
        foreach ($chunks as $chunk) {
481
            $builder = $this->manager->getConnection()->createQueryBuilder();
482
            $builder->update('s_plugin_connect_items', 'ci')
483
                ->set('ci.export_status', ':status')
484
                ->set('ci.exported', ':exported')
485
                ->where('source_id IN (:sourceIds)')
486
                ->setParameter('sourceIds', $chunk, \Doctrine\DBAL\Connection::PARAM_STR_ARRAY)
487
                ->setParameter('status', $status)
488
                ->setParameter('exported', $exported)
489
                ->execute();
490
        }
491
    }
492
493
    /**
494
     * @param SearchCriteria $criteria
495
     * @return ExportList
496
     */
497
    public function getExportList(SearchCriteria $criteria)
498
    {
499
        $customProductsTableExists = false;
500
        try {
501
            $builder = $this->manager->getConnection()->createQueryBuilder();
502
            $builder->select('id');
503
            $builder->from('s_plugin_custom_products_template');
504
            $builder->setMaxResults(1);
505
            $builder->execute()->fetch();
506
507
            $customProductsTableExists = true;
508
        } 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...
509
            // ignore it
510
            // custom products is not installed
511
        }
512
513
        $builder = $this->manager->getConnection()->createQueryBuilder();
514
        $builder->select([
515
            'a.id',
516
            'd.ordernumber as number',
517
            'd.inStock as inStock',
518
            'a.name as name',
519
            's.name as supplier',
520
            'a.active as active',
521
            't.tax as tax',
522
            'p.price * (100 + t.tax) / 100 as price',
523
            'i.category',
524
            'i.export_status as exportStatus',
525
            'i.export_message as exportMessage',
526
            'i.cron_update as cronUpdate'
527
        ])
528
            ->from('s_plugin_connect_items', 'i')
529
            ->leftJoin('i', 's_articles', 'a', 'a.id = i.article_id')
530
            ->leftJoin('a', 's_articles_details', 'd', 'a.main_detail_id = d.id')
531
            ->leftJoin('d', 's_articles_prices', 'p', 'd.id = p.articledetailsID')
532
            ->leftJoin('a', 's_core_tax', 't', 'a.taxID = t.id')
533
            ->leftJoin('a', 's_articles_supplier', 's', 'a.supplierID = s.id')
534
            ->groupBy('i.article_id')
535
            ->where('i.shop_id IS NULL');
536
537
        if ($customProductsTableExists) {
538
            $builder->addSelect('IF(spcptpr.template_id > 0, 1, 0) as customProduct')
539
                    ->leftJoin('a', 's_plugin_custom_products_template_product_relation', 'spcptpr', 'a.id = spcptpr.article_id');
540
        }
541
542
        if ($criteria->search) {
543
            $builder->andWhere('d.ordernumber LIKE :search OR a.name LIKE :search OR s.name LIKE :search')
544
                ->setParameter('search', $criteria->search);
545
        }
546
547
        if ($criteria->categoryId) {
548
549
            // Get all children categories
550
            $qBuilder = $this->manager->getConnection()->createQueryBuilder();
551
            $qBuilder->select('c.id');
552
            $qBuilder->from('s_categories', 'c');
553
            $qBuilder->where('c.path LIKE :categoryIdSearch');
554
            $qBuilder->orWhere('c.id = :categoryId');
555
            $qBuilder->setParameter(':categoryId', $criteria->categoryId);
556
            $qBuilder->setParameter(':categoryIdSearch', "%|$criteria->categoryId|%");
557
558
            $categoryIds = $qBuilder->execute()->fetchAll(\PDO::FETCH_COLUMN);
559
560
            if (count($categoryIds) === 0) {
561
                $categoryIds = [$criteria->categoryId];
562
            }
563
564
            $builder->innerJoin('a', 's_articles_categories', 'sac', 'a.id = sac.articleID')
565
                ->andWhere('sac.categoryID IN (:categoryIds)')
566
                ->setParameter('categoryIds', $categoryIds, \Doctrine\DBAL\Connection::PARAM_STR_ARRAY);
567
        }
568
569
        if ($criteria->supplierId) {
570
            $builder->andWhere('a.supplierID = :supplierId')
571
                ->setParameter('supplierId', $criteria->supplierId);
572
        }
573
574
        if ($criteria->exportStatus) {
575
            $errorStatuses = [Attribute::STATUS_ERROR, Attribute::STATUS_ERROR_PRICE];
576
577
            if (in_array($criteria->exportStatus, $errorStatuses)) {
578
                $builder->andWhere('i.export_status IN (:status)')
579
                    ->setParameter('status', $errorStatuses, \Doctrine\DBAL\Connection::PARAM_STR_ARRAY);
580
            } elseif ($criteria->exportStatus == Attribute::STATUS_INACTIVE) {
581
                $builder->andWhere('a.active = :status')
582
                    ->setParameter('status', false);
583
            } else {
584
                $builder->andWhere('i.export_status LIKE :status')
585
                    ->setParameter('status', $criteria->exportStatus);
586
            }
587
        }
588
589
        if ($criteria->active) {
590
            $builder->andWhere('a.active = :active')
591
                ->setParameter('active', $criteria->active);
592
        }
593
594
        if ($criteria->orderBy) {
595
            $builder->orderBy($criteria->orderBy, $criteria->orderByDirection);
596
        }
597
598
        $builder->setFirstResult($criteria->offset);
599
        $builder->setMaxResults($criteria->limit);
600
601
        $data = $builder->execute()->fetchAll();
602
603
        $total = $this->manager->getConnection()->fetchColumn(
604
            'SELECT COUNT(DISTINCT article_id) FROM s_plugin_connect_items WHERE shop_id IS NULL'
605
        );
606
607
        return new ExportList([
608
            'articles' => $data,
609
            'count' => $total,
610
        ]);
611
    }
612
613
    public function clearConnectItems()
614
    {
615
        $this->deleteAllConnectProducts();
616
        $this->resetConnectItemsStatus();
617
    }
618
619
    /**
620
     * @param int $articleId
621
     */
622
    public function markArticleForCronUpdate($articleId)
623
    {
624
        $this->manager->getConnection()->update(
625
            's_plugin_connect_items',
626
            ['cron_update' => 1],
627
            ['article_id' => (int) $articleId]
628
        );
629
    }
630
631
    /**
632
     * Wrapper method
633
     *
634
     * @param string $sourceId
635
     */
636
    public function recordDelete($sourceId)
637
    {
638
        $this->sdk->recordDelete($sourceId);
639
    }
640
641
    /**
642
     * Deletes products hash
643
     */
644
    private function deleteAllConnectProducts()
645
    {
646
        $builder = $this->manager->getConnection()->createQueryBuilder();
647
        $builder->delete('sw_connect_product');
648
        $builder->execute();
649
    }
650
651
    /**
652
     * Resets all item status
653
     */
654
    private function resetConnectItemsStatus()
655
    {
656
        $builder = $this->manager->getConnection()->createQueryBuilder();
657
        $builder->update('s_plugin_connect_items', 'ci')
658
            ->set('export_status', ':exportStatus')
659
            ->set('revision', ':revision')
660
            ->set('exported', 0)
661
            ->setParameter('exportStatus', null)
662
            ->setParameter('revision', null);
663
664
        $builder->execute();
665
    }
666
667
    private function getMarketplaceGateway()
668
    {
669
        //todo@fixme: Implement better way to get MarketplaceGateway
670
        if (!$this->marketplaceGateway) {
671
            $this->marketplaceGateway = new MarketplaceGateway($this->manager);
672
        }
673
674
        return $this->marketplaceGateway;
675
    }
676
677
    /**
678
     * Extracts all marketplaces attributes from product
679
     *
680
     * @param Detail $detail
681
     * @return array
682
     */
683
    private function extractProductAttributes(Detail $detail)
684
    {
685
        $marketplaceAttributes = [];
686
        $marketplaceAttributes['purchaseUnit'] = $detail->getPurchaseUnit();
687
        $marketplaceAttributes['referenceUnit'] = $detail->getReferenceUnit();
688
689
        // marketplace attributes are available only for SEM shops
690
        if ($this->configComponent->getConfig('isDefault', true)) {
691
            return $marketplaceAttributes;
692
        }
693
694
        foreach ($this->getMarketplaceGateway()->getMappings() as $mapping) {
695
            $shopwareAttribute = $mapping['shopwareAttributeKey'];
696
            $getter = 'get' . ucfirst($shopwareAttribute);
697
698
            if (method_exists($detail->getAttribute(), $getter)) {
699
                $marketplaceAttributes[$shopwareAttribute] = $detail->getAttribute()->{$getter}();
700
            }
701
        }
702
703
        return $marketplaceAttributes;
704
    }
705
706
    /**
707
     * @param Category $category
708
     */
709
    public function markProductsInToBeDeletedCategories(Category $category)
710
    {
711
        $categoryId = $category->getId();
712
        $builder = $this->manager->getConnection()->createQueryBuilder();
713
        $builder->select('categories.id')
714
            ->from('s_categories', 'categories')
715
            ->where('categories.path LIKE :categoryIDs')
716
            ->orWhere('categories.id = :categoryID')
717
            ->setParameter('categoryIDs', "%|$categoryId|%")
718
            ->setParameter('categoryID', $categoryId);
719
        $categoriesToBeDeleted = $builder->execute()->fetchAll(\PDO::FETCH_COLUMN);
720
721
        if ($categoriesToBeDeleted) {
722
            $articlesInDeletedCategories = [];
723
            foreach ($categoriesToBeDeleted as $categoryToBeDeleted) {
724
                //it's necessary to fetch all articleIDs in the deleted categories
725
                //because DQL doesn't allow a join in update
726
                $builder->select('articleCategories.articleID')
727
                    ->from('s_articles_categories', 'articleCategories')
728
                    ->where('articleCategories.categoryID = (:categoryID)')
729
                    ->setParameter('categoryID', $categoryToBeDeleted);
730
                $articlesInCategory = $builder->execute()->fetchAll(\PDO::FETCH_COLUMN);
731
                foreach ($articlesInCategory as $articleId) {
732
                    //trick to get just unique articleIDs -> should be faster than array_unique(array_merge())
733
                    $articlesInDeletedCategories[$articleId] = true;
734
                }
735
            }
736
737
            //we can't export Products directly because Categories are still there
738
            //we are in preRemove
739
            //we just mark them do be updated
740
            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...
741
                $builder->update('s_plugin_connect_items', 'connectItems')
742
                    ->set('connectItems.cron_update', 1)
743
                    ->where('connectItems.article_id IN (:articleIDs)')
744
                    ->andWhere('connectItems.exported = 1')
745
                    ->setParameter('articleIDs', array_keys($articlesInDeletedCategories), \Doctrine\DBAL\Connection::PARAM_STR_ARRAY);
746
747
                $builder->execute();
748
            }
749
        }
750
    }
751
752
    /**
753
     * exports every article that is marked with cron_update = 1
754
     * this is called in postRemoveCategories
755
     * to change products if their category was deleted
756
     */
757
    public function handleMarkedProducts()
758
    {
759
        $builder = $this->manager->getConnection()->createQueryBuilder();
760
        $builder->select('items.article_id')
761
            ->from('s_plugin_connect_items', 'items')
762
            ->where('items.cron_update = 1');
763
        $articlesToBeExported = $builder->execute()->fetchAll(\PDO::FETCH_COLUMN);
764
765
        if ($articlesToBeExported) {
766
            $this->export($articlesToBeExported);
767
768
            $builder->update('s_plugin_connect_items', 'items')
769
                ->set('items.cron_update', 0);
770
            $builder->execute();
771
        }
772
    }
773
}
774