Completed
Pull Request — master (#487)
by Jonas
02:52
created

CronJob::exportDynamicStreams()   C

Complexity

Conditions 10
Paths 65

Size

Total Lines 69

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 10
nc 65
nop 1
dl 0
loc 69
rs 6.8096
c 0
b 0
f 0

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
 * (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\Subscribers;
9
10
use Enlight\Event\SubscriberInterface;
11
use Shopware\Connect\SDK;
12
use Shopware\CustomModels\Connect\Attribute;
13
use Shopware\Models\ProductStream\ProductStream;
14
use ShopwarePlugins\Connect\Components\Config;
15
use ShopwarePlugins\Connect\Components\ErrorHandler;
16
use ShopwarePlugins\Connect\Components\Helper;
17
use ShopwarePlugins\Connect\Components\ImageImport;
18
use ShopwarePlugins\Connect\Components\Logger;
19
use ShopwarePlugins\Connect\Components\ConnectExport;
20
use ShopwarePlugins\Connect\Components\ProductStream\ProductSearch;
21
use ShopwarePlugins\Connect\Components\ProductStream\ProductStreamsAssignments;
22
use ShopwarePlugins\Connect\Components\ProductStream\ProductStreamService;
23
use Shopware\Components\DependencyInjection\Container;
24
25
/**
26
 * Cronjob callback
27
 *
28
 * Class CronJob
29
 * @package ShopwarePlugins\Connect\Subscribers
30
 */
31
class CronJob implements SubscriberInterface
32
{
33
    /**
34
     * @var \ShopwarePlugins\Connect\Components\Config
35
     */
36
    private $configComponent;
37
38
    /**
39
     * @var SDK
40
     */
41
    protected $sdk;
42
43
    /**
44
     * @var ProductStreamService
45
     */
46
    protected $streamService;
47
48
    /**
49
     * @var ConnectExport
50
     */
51
    protected $connectExport;
52
53
    /**
54
     * @var Helper
55
     */
56
    private $helper;
57
58
    /**
59
     * @var ProductSearch
60
     */
61
    private $productSearch;
62
63
    /**
64
     * @var Container
65
     */
66
    private $container;
67
68
    /**
69
     * @var ProductStreamService
70
     */
71
    private $productStreamService;
72
73
    /**
74
     * @param SDK $sdk
75
     * @param ConnectExport $connectExport
76
     * @param Config $configComponent
77
     * @param Helper $helper
78
     * @param Container $container
79
     * @param ProductStreamService $productStreamService
80
     */
81 View Code Duplication
    public function __construct(
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...
82
        SDK $sdk,
83
        ConnectExport $connectExport,
84
        Config $configComponent,
85
        Helper $helper,
86
        Container $container,
87
        ProductStreamService $productStreamService
88
    ) {
89
        $this->connectExport = $connectExport;
90
        $this->sdk = $sdk;
91
        $this->configComponent = $configComponent;
92
        $this->helper = $helper;
93
        $this->container = $container;
94
        $this->productStreamService = $productStreamService;
95
    }
96
97
    /**
98
     * {@inheritdoc}
99
     */
100
    public static function getSubscribedEvents()
101
    {
102
        return [
103
            'Shopware_CronJob_ShopwareConnectImportImages' => 'importImages',
104
            'Shopware_CronJob_ShopwareConnectUpdateProducts' => 'updateProducts',
105
            'Shopware_CronJob_ConnectExportDynamicStreams' => 'exportDynamicStreams',
106
        ];
107
    }
108
109
    /**
110
     * @return ImageImport
111
     */
112 View Code Duplication
    public function getImageImport()
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...
113
    {
114
        // do not use thumbnail_manager as a dependency!!!
115
        // MediaService::__construct uses Shop entity
116
        // this also could break the session in backend when it's used in subscriber
117
        return new ImageImport(
118
            Shopware()->Models(),
119
            $this->helper,
120
            $this->container->get('thumbnail_manager'),
121
            new Logger(Shopware()->Db())
122
        );
123
    }
124
125
    /**
126
     * Import images of new products
127
     *
128
     * @param \Shopware_Components_Cron_CronJob $job
129
     * @return bool
130
     */
131
    public function importImages(\Shopware_Components_Cron_CronJob $job)
132
    {
133
        $limit = $this->configComponent->getConfig('articleImagesLimitImport', 10);
0 ignored issues
show
Bug introduced by
Are you sure the assignment to $limit is correct as $this->configComponent->...ImagesLimitImport', 10) (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...
134
        $this->getImageImport()->import($limit);
135
136
        return true;
137
    }
138
139
    /**
140
     * Collect all own products and send them
141
     * to Connect system.
142
     *
143
     * Used to update products with many variants.
144
     *
145
     * @param \Shopware_Components_Cron_CronJob $job
146
     * @return bool
147
     */
148
    public function updateProducts(\Shopware_Components_Cron_CronJob $job)
149
    {
150
        $sourceIds = Shopware()->Db()->fetchCol(
151
            'SELECT source_id FROM s_plugin_connect_items WHERE shop_id IS NULL AND cron_update = 1 AND exported = 1 LIMIT 100'
152
        );
153
154
        if (empty($sourceIds)) {
155
            return true;
156
        }
157
158
        $this->connectExport->processChanged($sourceIds);
159
160
        $quotedSourceIds = Shopware()->Db()->quote($sourceIds);
161
        Shopware()->Db()->query(
162
            "UPDATE s_plugin_connect_items
163
            SET cron_update = false
164
            WHERE source_id IN ($quotedSourceIds)"
165
        )->execute();
166
167
        return true;
168
    }
169
170
    /**
171
     * @param \Shopware_Components_Cron_CronJob $job
172
     */
173
    public function exportDynamicStreams(\Shopware_Components_Cron_CronJob $job)
174
    {
175
        $streams = $this->productStreamService->getAllExportedStreams(ProductStreamService::DYNAMIC_STREAM);
176
        $streamsAssignments = new ProductStreamsAssignments();
177
178
        /** @var ProductStream $stream */
179
        foreach ($streams as $stream) {
180
            $streamId = $stream->getId();
181
            $productSearchResult = $this->getProductSearch()->getProductFromConditionStream($stream);
182
            $orderNumbers = array_keys($productSearchResult->getProducts());
183
184
            //no products found
185
            if (!$orderNumbers) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $orderNumbers 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...
186
                //removes all products from this stream
187
                $this->productStreamService->markProductsToBeRemovedFromStream($streamId);
188
            } else {
189
                $articleIds = $this->helper->getArticleIdsByNumber($orderNumbers);
190
191
                $this->productStreamService->markProductsToBeRemovedFromStream($streamId);
192
                $this->productStreamService->createStreamRelation($streamId, $articleIds);
193
            }
194
195
            try {
196
                $streamsAssignments->merge($this->productStreamService->prepareStreamsAssignments($streamId));
197
            } catch (\RuntimeException $e) {
198
                $this->productStreamService->changeStatus($streamId, ProductStreamService::STATUS_ERROR, $e->getMessage());
199
                continue;
200
            }
201
        }
202
        if (count($streamsAssignments->assignments) === 0) {
203
            return;
204
        }
205
206
        //article ids must be taken from streamsAssignments
207
        $exportArticleIds = $streamsAssignments->getArticleIds();
208
209
        $removeArticleIds = $streamsAssignments->getArticleIdsWithoutStreams();
210
211
        if (!empty($removeArticleIds)) {
212
            $this->removeArticlesFromStream($removeArticleIds);
213
214
            //filter the $exportArticleIds
215
            $exportArticleIds = array_diff($exportArticleIds, $removeArticleIds);
216
        }
217
218
        $sourceIds = $this->helper->getArticleSourceIds($exportArticleIds);
219
220
        $errorMessages = $this->connectExport->export($sourceIds, $streamsAssignments);
221
222
        if ($errorMessages) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $errorMessages 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...
223
            $errorMessagesText = '';
224
            $displayedErrorTypes = [
225
                ErrorHandler::TYPE_DEFAULT_ERROR,
226
                ErrorHandler::TYPE_PRICE_ERROR
227
            ];
228
229
            foreach ($displayedErrorTypes as $displayedErrorType) {
230
                $errorMessagesText .= implode('\n', $errorMessages[$displayedErrorType]);
231
            }
232
233
            foreach ($streams as $stream) {
234
                $this->productStreamService->changeStatus($stream->getId(), ProductStreamService::STATUS_ERROR, $errorMessagesText);
235
            }
236
        }
237
238
        foreach ($streams as $stream) {
239
            $this->productStreamService->changeStatus($stream->getId(), ProductStreamService::STATUS_EXPORT);
240
        }
241
    }
242
243
    /**
244
     * If article is not taking part of any shopware stream it will be removed
245
     * @param array $articleIds
246
     */
247
    private function removeArticlesFromStream(array $articleIds)
248
    {
249
        $sourceIds = $this->helper->getArticleSourceIds($articleIds);
250
        $items = $this->connectExport->fetchConnectItems($sourceIds, false);
251
252
        foreach ($items as $item) {
253
            $this->sdk->recordDelete($item['sourceId']);
254
        }
255
256
        $this->productStreamService->removeMarkedStreamRelations();
257
        $this->connectExport->updateConnectItemsStatus($sourceIds, Attribute::STATUS_DELETE);
258
    }
259
260
    /**
261
     * @return ProductSearch
262
     */
263
    private function getProductSearch()
264
    {
265
        if (!$this->productSearch) {
266
            // HACK
267
            // do not use as a dependency!!!
268
            // this class uses Shopware product search which depends on shop context
269
            // so if it's used as dependency of subscriber, plugin returns error on deactivate
270
            // see CON-4922
271
            $this->productSearch = $this->container->get('swagconnect.product_search');
272
        }
273
274
        return $this->productSearch;
275
    }
276
}
277