Completed
Push — master ( 3474fd...81362a )
by Daniel
13s
created

Article::modifyConnectArticle()   C

Complexity

Conditions 11
Paths 9

Size

Total Lines 62
Code Lines 32

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 62
rs 6.1722
c 0
b 0
f 0
cc 11
eloc 32
nc 9
nop 1

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
namespace ShopwarePlugins\Connect\Subscribers;
4
use Shopware\CustomModels\Connect\Attribute;
5
use ShopwarePlugins\Connect\Components\Config;
6
use Shopware\Connect\Struct\Change\FromShop\MakeMainVariant;
7
use Shopware\Models\Customer\Group;
8
use Shopware\Connect\Gateway;
9
use Shopware\Components\Model\ModelManager;
10
use ShopwarePlugins\Connect\Components\ConnectExport;
11
use Shopware\Models\Article\Article as ArticleModel;
12
use ShopwarePlugins\Connect\Components\Helper;
13
14
/**
15
 * Class Article
16
 * @package ShopwarePlugins\Connect\Subscribers
17
 */
18
class Article extends BaseSubscriber
19
{
20
    /**
21
     * @var \Shopware\Connect\Gateway\PDO
22
     */
23
    private $connectGateway;
24
25
    /**
26
     * @var \Shopware\Components\Model\ModelManager
27
     */
28
    private $modelManager;
29
30
    /**
31
     * @var \Shopware\Models\Customer\Group
32
     */
33
    private $customerGroupRepository;
34
35
    /**
36
     * @var \Shopware\Models\Article\Detail
37
     */
38
    private $detailRepository;
39
40
    /**
41
     * @var \ShopwarePlugins\Connect\Components\ConnectExport
42
     */
43
    private $connectExport;
44
45
    /**
46
     * @var Helper
47
     */
48
    private $helper;
49
50
    /**
51
     * @var Config
52
     */
53
    private $config;
54
55
    public function __construct(
56
        Gateway $connectGateway,
57
        ModelManager $modelManager,
58
        ConnectExport $connectExport,
59
        Helper $helper,
60
        Config $config
61
    ) {
62
        parent::__construct();
63
        $this->connectGateway = $connectGateway;
0 ignored issues
show
Documentation Bug introduced by
$connectGateway is of type object<Shopware\Connect\Gateway>, but the property $connectGateway was declared to be of type object<Shopware\Connect\Gateway\PDO>. Are you sure that you always receive this specific sub-class here, or does it make sense to add an instanceof check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a given class or a super-class is assigned to a property that is type hinted more strictly.

Either this assignment is in error or an instanceof check should be added for that assignment.

class Alien {}

class Dalek extends Alien {}

class Plot
{
    /** @var  Dalek */
    public $villain;
}

$alien = new Alien();
$plot = new Plot();
if ($alien instanceof Dalek) {
    $plot->villain = $alien;
}
Loading history...
64
        $this->modelManager = $modelManager;
65
        $this->connectExport = $connectExport;
66
        $this->helper = $helper;
67
        $this->config = $config;
68
    }
69
70
    public function getSubscribedEvents()
71
    {
72
        return array(
73
            'Shopware_Controllers_Backend_Article::preparePricesAssociatedData::after' => 'enforceConnectPriceWhenSaving',
74
            'Enlight_Controller_Action_PostDispatch_Backend_Article' => 'extendBackendArticle',
75
            'Enlight_Controller_Action_PreDispatch_Backend_Article' => 'preBackendArticle',
76
            'Enlight_Controller_Action_PostDispatch_Frontend_Detail' => 'modifyConnectArticle',
77
            'Enlight_Controller_Action_PreDispatch_Frontend_Detail' => 'extendFrontendArticle'
78
        );
79
    }
80
81
    /**
82
     * @return \Shopware\Models\Article\Detail
83
     */
84
    public function getDetailRepository()
85
    {
86
        if (!$this->detailRepository) {
87
            $this->detailRepository = $this->modelManager->getRepository('Shopware\Models\Article\Detail');
88
        }
89
90
        return $this->detailRepository;
91
    }
92
93
    /**
94
     * @return \Shopware\Components\Model\ModelRepository|Group
95
     */
96
    public function getCustomerGroupRepository()
97
    {
98
        if (!$this->customerGroupRepository) {
99
            $this->customerGroupRepository = $this->modelManager->getRepository('Shopware\Models\Customer\Group');
100
        }
101
        return $this->customerGroupRepository;
102
    }
103
104
    /**
105
     * @param \Enlight_Event_EventArgs $args
106
     */
107
    public function preBackendArticle(\Enlight_Event_EventArgs $args)
108
    {
109
        /** @var $subject \Enlight_Controller_Action */
110
        $subject = $args->getSubject();
111
        $request = $subject->Request();
112
113
        switch ($request->getActionName()) {
114
            case 'saveDetail':
115
                if ($request->getParam('standard')) {
116
                    $this->generateMainVariantChange($request->getParam('id'));
117
                }
118
                break;
119
            case 'createConfiguratorVariants':
120
                if (!$articleId = $request->getParam('articleId')) {
121
                    return;
122
                }
123
124
                $this->deleteVariants($articleId);
125
                break;
126
        }
127
    }
128
129
    /**
130
     * @event Enlight_Controller_Action_PostDispatch_Backend_Article
131
     * @param \Enlight_Event_EventArgs $args
132
     */
133
    public function extendBackendArticle(\Enlight_Event_EventArgs $args)
134
    {
135
        /** @var $subject \Enlight_Controller_Action */
136
        $subject = $args->getSubject();
137
        $request = $subject->Request();
138
139
        switch ($request->getActionName()) {
140
            case 'index':
141
                $this->registerMyTemplateDir();
142
                $this->registerMySnippets();
143
                $subject->View()->extendsTemplate(
144
                    'backend/article/connect.js'
145
                );
146
                break;
147
            case 'load':
148
                $this->registerMyTemplateDir();
149
                $this->registerMySnippets();
150
                $subject->View()->extendsTemplate(
151
                    'backend/article/model/attribute_connect.js'
152
                );
153
                $subject->View()->assign('disableConnectPrice', 'true');
154
                $subject->View()->extendsTemplate(
155
                    'backend/article/view/detail/connect_tab.js'
156
                );
157
                $subject->View()->extendsTemplate(
158
                    'backend/article/view/detail/prices_connect.js'
159
                );
160
                $subject->View()->extendsTemplate(
161
                    'backend/article/controller/detail_connect.js'
162
                );
163
                $subject->View()->extendsTemplate(
164
                    'backend/article/view/detail/connect_properties.js'
165
                );
166
                break;
167
            case 'setPropertyList':
168
                // property values are saved in different ajax call then
169
                // property group and this will generate wrong Connect changes.
170
                // after the property values are saved, the temporary property group is no needed
171
                // and it will generate right Connect changes
172
                $articleId = $request->getParam('articleId', null);
173
174
                /** @var ArticleModel $article */
175
                $article = $this->modelManager->find(ArticleModel::class, $articleId);
176
177
                if (!$article) {
178
                    return;
179
                }
180
181
                if (!$article->getPropertyGroup()) {
182
                    return;
183
                }
184
185
                // Check if entity is a connect product
186
                $attribute = $this->helper->getConnectAttributeByModel($article);
187
                if (!$attribute) {
188
                    return;
189
                }
190
191
                // if article is not exported to Connect
192
                // don't need to generate changes
193
                if (!$this->helper->isProductExported($attribute) || !empty($attribute->getShopId())) {
194
                    return;
195
                }
196
197
                if (!$this->hasPriceType()) {
198
                    return;
199
                }
200
201
                $detail = $article->getMainDetail();
202
203
                if ($detail->getAttribute()->getConnectPropertyGroup()) {
204
                    $detail->getAttribute()->setConnectPropertyGroup(null);
205
                    $this->modelManager->persist($detail);
206
                    $this->modelManager->flush();
207
                }
208
209
                $sourceIds = Shopware()->Db()->fetchCol(
210
                    'SELECT source_id FROM s_plugin_connect_items WHERE article_id = ?',
211
                    array($article->getId())
212
                );
213
214
                $this->connectExport->export($sourceIds);
215
                break;
216
            case 'createConfiguratorVariants':
217
                // main detail should be updated as well, because shopware won't call lifecycle event
218
                // even postUpdate of Detail. By this way Connect will generate change for main variant,
219
                // otherwise $product->variant property is an empty array
220
                // if main detail is not changed, Connect SDK won't generate change for it.
221
                // ticket CON-3747
222
                if (!$articleId = $request->getParam('articleId')) {
223
                    return;
224
                }
225
226
                $this->regenerateChangesForArticle($articleId);
227
                break;
228
            case 'getPropertyList':
229
                $subject->View()->data = $this->addConnectFlagToProperties(
230
                    $subject->View()->data
231
                );
232
                break;
233
            case 'deleteAllVariants':
234
                if ($articleId = $request->getParam('articleId')) {
235
                    /** @var ArticleModel $article */
236
                    $article = $this->modelManager->find(ArticleModel::class, (int) $articleId);
237
                    if (!$article) {
238
                        return;
239
                    }
240
241
                    $this->deleteVariants($articleId);
242
                }
243
                break;
244
            default:
245
                break;
246
        }
247
    }
248
249
    /**
250
     * @param int $articleId
251
     */
252
    public function regenerateChangesForArticle($articleId)
253
    {
254
        $autoUpdateProducts = $this->config->getConfig('autoUpdateProducts', Config::UPDATE_AUTO);
0 ignored issues
show
Bug introduced by
Are you sure the assignment to $autoUpdateProducts is correct as $this->config->getConfig...ts\Config::UPDATE_AUTO) (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...
255
        if ($autoUpdateProducts == Config::UPDATE_MANUAL) {
256
            return;
257
        }
258
259
        /** @var \Shopware\Models\Article\Article $article */
260
        $article = $this->modelManager->getRepository(ArticleModel::class)->find((int)$articleId);
261
        if (!$article) {
262
            return;
263
         }
264
265
        $attribute = $this->helper->getConnectAttributeByModel($article);
266
        if (!$attribute) {
267
            return;
268
        }
269
270
        // Check if entity is a connect product
271
        if (!$this->helper->isProductExported($attribute)) {
272
            return;
273
        }
274
275
        if ($autoUpdateProducts == Config::UPDATE_CRON_JOB) {
276
            $this->connectExport->markArticleForCronUpdate($articleId);
277
            return;
278
        }
279
280
        $this->connectExport->export($this->helper->getArticleSourceIds([$articleId]));
281
    }
282
283
    /**
284
     * Delete all variants of given product except main one
285
     *
286
     * @param int $articleId
287
     */
288
    private function deleteVariants($articleId)
289
    {
290
        $autoUpdateProducts = $this->config->getConfig('autoUpdateProducts', Config::UPDATE_AUTO);
0 ignored issues
show
Bug introduced by
Are you sure the assignment to $autoUpdateProducts is correct as $this->config->getConfig...ts\Config::UPDATE_AUTO) (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...
291
        if ($autoUpdateProducts == Config::UPDATE_MANUAL) {
292
            return;
293
        }
294
295
        /** @var \Shopware\Models\Article\Article $article */
296
        $article = $this->modelManager->getRepository(ArticleModel::class)->find((int)$articleId);
297
        if (!$article) {
298
            return;
299
        }
300
301
        $connectAttribute = $this->helper->getConnectAttributeByModel($article);
302
        if (!$connectAttribute) {
303
            return;
304
        }
305
306
        // Check if entity is a connect product
307
        if (!$this->helper->isProductExported($connectAttribute)) {
308
            return;
309
        }
310
311
        $mainVariantSourceId = $connectAttribute->getSourceId();
312
        $sourceIds = array_filter(
313
            $this->helper->getArticleSourceIds([$article->getId()]),
314
            function ($sourceId) use ($mainVariantSourceId) {
315
                return $sourceId != $mainVariantSourceId;
316
            }
317
        );
318
319
        foreach ($sourceIds as $sourceId) {
320
            $this->getSDK()->recordDelete($sourceId);
321
        }
322
323
        $this->connectExport->updateConnectItemsStatus($sourceIds, Attribute::STATUS_DELETE);
324
    }
325
326
    public function addConnectFlagToProperties($data)
327
    {
328
        $groups = [];
329
        foreach ($data as $group) {
330
            $options = [];
331
            foreach ($group['value'] as $value) {
332
                $element = $value;
333
                $optionId = $value['id'];
334
                $valueModel = $this->modelManager->getRepository('Shopware\Models\Property\Value')->find($optionId);
335
336
                $attribute = null;
337
                if ($valueModel) {
338
                    $attribute = $valueModel->getAttribute();
339
                }
340
341
                if ($attribute && $attribute->getConnectIsRemote()) {
342
                    $element['connect'] = true;
343
                } else {
344
                    $element['connect'] = false;
345
                }
346
                $options[] = $element;
347
            }
348
349
            $group['value'] = $options;
350
            $groups[] = $group;
351
        }
352
353
        return $groups;
354
    }
355
356
    /**
357
     * @param $detailId
358
     */
359
    public function generateMainVariantChange($detailId)
360
    {
361
        $detail = $this->getDetailRepository()->findOneBy(array('id' => $detailId));
362
363
        if (!$detail instanceof \Shopware\Models\Article\Detail) {
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...
364
            return;
365
        }
366
367
        //if it is already main variant dont generate MakeMainVariant change
368
        if ($detail->getKind() == 1) {
369
            return;
370
        }
371
372
        $attribute = $this->helper->getConnectAttributeByModel($detail);
373
374
        if (!$attribute) {
375
            return;
376
        }
377
        // Check if entity is a connect product
378
        if (!$this->helper->isProductExported($attribute)) {
379
            return;
380
        }
381
382
        if (!$this->hasPriceType()) {
383
            return;
384
        }
385
386
        $groupId = $attribute->getGroupId() ? $attribute->getGroupId() : $attribute->getArticleId();
387
388
        $mainVariant = new MakeMainVariant(array(
389
            'sourceId' => $attribute->getSourceId(),
390
            'groupId' => $groupId
391
        ));
392
393
        try {
394
            $this->getSDK()->makeMainVariant($mainVariant);
395
        } catch (\Exception $e) {
396
            // if sn is not available, proceed without exception
397
        }
398
    }
399
400
    /**
401
     * When saving prices make sure, that the connectPrice is stored in net
402
     *
403
     * @param \Enlight_Hook_HookArgs $args
404
     */
405
    public function enforceConnectPriceWhenSaving(\Enlight_Hook_HookArgs $args)
406
    {
407
        /** @var array $prices */
408
        $prices = $args->getReturn();
409
410
        $connectCustomerGroup = $this->getConnectCustomerGroup();
411
        if (!$connectCustomerGroup) {
412
            return;
413
        }
414
        $connectCustomerGroupKey = $connectCustomerGroup->getKey();
415
        $defaultPrices = array();
416
        foreach ($prices as $key => $priceData) {
417
            if ($priceData['customerGroupKey'] == $connectCustomerGroupKey) {
418
                return;
419
            }
420
            if ($priceData['customerGroupKey'] == 'EK') {
421
                $defaultPrices[] = $priceData;
422
            }
423
        }
424
425
        foreach ($defaultPrices as $price) {
426
            $prices[] = array(
427
                'from' => $price['from'],
428
                'to' => $price['to'],
429
                'price' => $price['price'],
430
                'pseudoPrice' => $price['pseudoPrice'],
431
                'basePrice' => $price['basePrice'],
432
                'percent' => $price['percent'],
433
                'customerGroup' => $connectCustomerGroup,
434
                'article' => $price['article'],
435
                'articleDetail' => $price['articleDetail'],
436
            );
437
        }
438
439
        $args->setReturn($prices);
440
    }
441
442
    /**
443
     * @return \Shopware\Models\Customer\Group|null
444
     */
445 View Code Duplication
    public function getConnectCustomerGroup()
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...
446
    {
447
        $repo = Shopware()->Models()->getRepository('Shopware\Models\Attribute\CustomerGroup');
448
        /** @var \Shopware\Models\Attribute\CustomerGroup $model */
449
        $model = $repo->findOneBy(array('connectGroup' => true));
450
451
        $customerGroup = null;
0 ignored issues
show
Unused Code introduced by
$customerGroup is not used, you could remove the assignment.

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

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

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

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

Loading history...
452
        if ($model && $model->getCustomerGroup()) {
453
            return $model->getCustomerGroup();
454
        }
455
456
        return null;
457
    }
458
459
    /**
460
     * Load article detail
461
     *
462
     * @param \Enlight_Event_EventArgs $args
463
     */
464
    public function extendFrontendArticle(\Enlight_Event_EventArgs $args)
465
    {
466
        /** @var \Enlight_Controller_Request_RequestHttp $request */
467
        $request = $args->getSubject()->Request();
468
        if ($request->getActionName() != 'index') {
469
            return;
470
        }
471
472
        $detailId = (int) $request->sArticleDetail;
473
        if ($detailId === 0) {
474
            return;
475
        }
476
477
        /** @var \Shopware\Models\Article\Detail $detailModel */
478
        $detailModel = Shopware()->Models()->getRepository('Shopware\Models\Article\Detail')->find($detailId);
479
        if (!$detailModel) {
480
            return;
481
        }
482
483
        $params = array();
484
        /** @var \Shopware\Models\Article\Configurator\Option $option */
485
        foreach ($detailModel->getConfiguratorOptions() as $option) {
486
            $groupId = $option->getGroup()->getId();
487
            $params[$groupId] = $option->getId();
488
        }
489
        $request->setPost('group', $params);
490
    }
491
492
    /**
493
     * Should be possible to buy connect products
494
     * when they're not in stock.
495
     * Depends on remote shop configuration.
496
     *
497
     * @param \Enlight_Event_EventArgs $args
498
     */
499
    public function modifyConnectArticle(\Enlight_Event_EventArgs $args)
500
    {
501
        /** @var \Enlight_Controller_Request_RequestHttp $request */
502
        $request = $args->getSubject()->Request();
503
504
        if ($request->getActionName() != 'index') {
505
            return;
506
        }
507
        $subject = $args->getSubject();
508
        $article = $subject->View()->getAssign('sArticle');
509
        if (!$article) {
510
            return;
511
        }
512
513
        // when article stock is greater than 0
514
        // we don't need to modify it.
515
        if ($article['instock'] > 0) {
516
            return;
517
        }
518
519
        $articleId = $article['articleID'];
520
        $remoteShopId = $this->getRemoteShopId($articleId);
521
        if (!$remoteShopId) {
522
            // article is not imported via Connect
523
            return;
524
        }
525
526
        /** @var \Shopware\Models\Article\Article $articleModel */
527
        $articleModel = Shopware()->Models()->getRepository('Shopware\Models\Article\Article')->find($articleId);
528
        if (!$articleModel) {
529
            return;
530
        }
531
532
        $shopConfiguration = $this->connectGateway->getShopConfiguration($remoteShopId);
0 ignored issues
show
Documentation introduced by
$remoteShopId is of type boolean|integer, but the function expects a string.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
533
        if ($shopConfiguration->sellNotInStock && !$articleModel->getLastStock()) {
534
            // if selNotInStock is = true and article getLastStock = false
535
            // we don't need to modify it
536
            return;
537
        }
538
539
        if (!$shopConfiguration->sellNotInStock && $articleModel->getLastStock()) {
540
            // if sellNotInStock is = false and article getLastStock = true
541
            // we don't need to modify it
542
            return;
543
        }
544
545
        // sellNotInStock is opposite on articleLastStock
546
        // when it's true, lastStock must be false
547
        $articleModel->setLastStock(!$shopConfiguration->sellNotInStock);
548
        Shopware()->Models()->persist($articleModel);
549
        Shopware()->Models()->flush();
550
551
        // modify assigned article
552
        if ($shopConfiguration->sellNotInStock) {
553
            $article['laststock'] = false;
554
            $article['instock'] = 100;
555
            $article['isAvailable'] = true;
556
        } else {
557
            $article['laststock'] = true;
558
        }
559
        $subject->View()->assign('sArticle', $article);
560
    }
561
562
    /**
563
     * Not using the default helper-methods here, in order to keep this small and without any dependencies
564
     * to the SDK
565
     *
566
     * @param $id
567
     * @return boolean|int
568
     */
569
    private function getRemoteShopId($id)
570
    {
571
        $sql = 'SELECT shop_id FROM s_plugin_connect_items WHERE article_id = ? AND shop_id IS NOT NULL';
572
        return Shopware()->Db()->fetchOne($sql, array($id));
573
    }
574
}