Completed
Push — master ( c34ece...9cc13a )
by Jonas
13s
created

ProductStreamService   B

Complexity

Total Complexity 43

Size/Duplication

Total Lines 383
Duplicated Lines 0 %

Coupling/Cohesion

Components 2
Dependencies 5

Importance

Changes 0
Metric Value
dl 0
loc 383
rs 8.96
c 0
b 0
f 0
wmc 43
lcom 2
cbo 5

24 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 9 1
A prepareStreamsAssignments() 0 19 3
A getAssignmentsForStream() 0 19 3
A getStreamAssignments() 0 13 1
A isConnectStream() 0 10 2
A activateConnectProductsByStream() 0 4 1
A findStream() 0 4 1
A findStreams() 0 4 1
A filterExportedStreams() 0 4 1
A collectRelatedStreamsAssignments() 0 23 4
A allowToRemove() 0 14 4
A getArticlesIds() 0 8 2
A isStatic() 0 8 2
A getList() 0 20 4
A getAllExportedStreams() 0 4 1
A createStreamAttribute() 0 11 2
A countProductsInStaticStream() 0 4 1
A isStreamExported() 0 4 1
A markProductsToBeRemovedFromStream() 0 4 1
A createStreamRelation() 0 4 1
A removeMarkedStreamRelations() 0 4 1
A getConnectStreamIds() 0 4 1
A changeStatus() 0 15 3
A log() 0 8 1

How to fix   Complexity   

Complex Class

Complex classes like ProductStreamService often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use ProductStreamService, and based on these observations, apply Extract Interface, too.

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\ProductStream;
9
10
use Shopware\CustomModels\Connect\ProductStreamAttribute;
11
use Shopware\Models\ProductStream\ProductStream;
12
use Shopware\CustomModels\Connect\ProductStreamAttributeRepository;
13
use ShopwarePlugins\Connect\Components\Config;
14
15
class ProductStreamService
16
{
17
    const DYNAMIC_STREAM = 1;
18
    const STATIC_STREAM = 2;
19
    const STATUS_EXPORT = 'export';
20
    const STATUS_DELETE = 'delete';
21
    const STATUS_ERROR = 'error';
22
    const STATUS_SYNCED = 'synced';
23
    const STATUS_PENDING = 'pending';
24
    const PRODUCT_LIMIT = 100;
25
26
    //Available statuses for exported stream
27
    const EXPORTED_STATUSES = [
28
        self::STATUS_EXPORT,
29
        self::STATUS_SYNCED,
30
        self::STATUS_ERROR,
31
        self::STATUS_PENDING,
32
    ];
33
34
    /**
35
     * @var ProductStreamRepository
36
     */
37
    private $productStreamRepository;
38
39
    /**
40
     * @var ProductStreamAttributeRepository
41
     */
42
    private $streamAttrRepository;
43
44
    /** @var Config */
45
    private $config;
46
47
    /**
48
     * @param ProductStreamRepository $productStreamRepository
49
     * @param ProductStreamAttributeRepository $streamAttrRepository
50
     * @param Config $config
51
     */
52
    public function __construct(
53
        ProductStreamRepository $productStreamRepository,
54
        ProductStreamAttributeRepository $streamAttrRepository,
55
        Config $config
56
    ) {
57
        $this->productStreamRepository = $productStreamRepository;
58
        $this->streamAttrRepository = $streamAttrRepository;
59
        $this->config = $config;
60
    }
61
62
    /**
63
     * @param $streamId
64
     * @param bool $appendCurrent
65
     * @return ProductStreamsAssignments
66
     */
67
    public function prepareStreamsAssignments($streamId, $appendCurrent = true)
68
    {
69
        $stream = $this->findStream($streamId);
70
71
        $articleIds = array_keys($this->getArticlesIds($stream));
72
73
        $assignment = $this->collectRelatedStreamsAssignments($articleIds);
74
75
        if ($appendCurrent) {
76
            //merge prev with current streams
77
            foreach ($articleIds as $articleId) {
78
                $assignment[$articleId][$stream->getId()] = $stream->getName();
79
            }
80
        }
81
82
        return new ProductStreamsAssignments(
83
            ['assignments' => $assignment]
84
        );
85
    }
86
87
    /**
88
     * @param $streamId
89
     * @param bool $appendCurrent
0 ignored issues
show
Bug introduced by
There is no parameter named $appendCurrent. Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
90
     * @return ProductStreamsAssignments
91
     */
92
    public function getAssignmentsForStream($streamId)
93
    {
94
        $stream = $this->findStream($streamId);
95
        $articleIds = $this->getArticlesIds($stream);
96
        $assignment = [];
97
98
        foreach ($articleIds as $articleId => $deleted) {
99
            if ($deleted === 1) {
100
                $assignment[$articleId] = [];
101
                continue;
102
            };
103
104
            $assignment[$articleId][$stream->getId()] = $stream->getName();
105
        }
106
107
        return new ProductStreamsAssignments(
108
            ['assignments' => $assignment]
109
        );
110
    }
111
112
    /**
113
     * @param $streamId
114
     * @throws \Exception
115
     * @return ProductStreamsAssignments
116
     */
117
    public function getStreamAssignments($streamId)
118
    {
119
        //checks stream existence
120
        $stream = $this->findStream($streamId);
121
122
        $articleIds = array_keys($this->getArticlesIds($stream));
123
124
        $assignment = $this->collectRelatedStreamsAssignments($articleIds);
125
126
        return new ProductStreamsAssignments(
127
            ['assignments' => $assignment]
128
        );
129
    }
130
131
    /**
132
     * @param ProductStream $stream
133
     * @return bool
134
     */
135
    public function isConnectStream(ProductStream $stream)
136
    {
137
        $attribute = $stream->getAttribute();
138
139
        if (!$attribute) {
140
            return false;
141
        }
142
143
        return (bool) $attribute->getConnectIsRemote();
144
    }
145
146
    /**
147
     * @param ProductStream $stream
148
     * @return bool
149
     */
150
    public function activateConnectProductsByStream(ProductStream $stream)
151
    {
152
        return $this->productStreamRepository->activateConnectProductsByStream($stream);
153
    }
154
155
    /**
156
     * @param $streamId
157
     * @return mixed
158
     */
159
    public function findStream($streamId)
160
    {
161
        return $this->productStreamRepository->findById($streamId);
162
    }
163
164
    /**
165
     * @param array $streamIds
166
     * @return \Shopware\Models\ProductStream\ProductStream[]
167
     */
168
    public function findStreams(array $streamIds)
169
    {
170
        return $this->productStreamRepository->findByIds($streamIds);
171
    }
172
173
    /**
174
     * Filter the stream ids, it will return only the exported ones
175
     *
176
     * @param array $streamIds
177
     * @return array
178
     */
179
    public function filterExportedStreams(array $streamIds)
180
    {
181
        return $this->productStreamRepository->filterExportedStreams($streamIds);
182
    }
183
184
    /**
185
     * @param array $articleIds
186
     * @return array
187
     */
188
    public function collectRelatedStreamsAssignments(array $articleIds)
189
    {
190
        $assignment = [];
191
192
        $collection = $this->productStreamRepository->fetchAllPreviousExportedStreams($articleIds);
193
194
        //prepare previous related streams
195
        foreach ($collection as $item) {
196
            //does not append the streams which were marked deleted
197
            if ($item['deleted'] == ProductStreamAttribute::STREAM_RELATION_DELETED) {
198
                if (!isset($assignment[$item['articleId']])) {
199
                    //adds empty array if there is no other stream for this product
200
                    $assignment[$item['articleId']] = [];
201
                }
202
203
                continue;
204
            }
205
206
            $assignment[$item['articleId']][$item['streamId']] = $item['name'];
207
        }
208
209
        return $assignment;
210
    }
211
212
    /**
213
     * @param ProductStreamsAssignments $assignments
214
     * @param $streamId
215
     * @param $articleId
216
     * @return bool
217
     */
218
    public function allowToRemove(ProductStreamsAssignments $assignments, $streamId, $articleId)
219
    {
220
        $streamAssignments = $assignments->getStreamsByArticleId($articleId);
221
222
        if (!$streamAssignments || !isset($streamAssignments[$streamId])) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $streamAssignments 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
            return false;
224
        }
225
226
        if (count($streamAssignments) > 1) {
227
            return false;
228
        }
229
230
        return true;
231
    }
232
233
    /**
234
     * @param ProductStream $stream
235
     * @return array
236
     */
237
    public function getArticlesIds(ProductStream $stream)
238
    {
239
        if ($this->isStatic($stream)) {
240
            return $this->productStreamRepository->fetchArticleIdsFromStaticStream($stream);
241
        }
242
243
        return $this->productStreamRepository->fetchArticleIdsFromDynamicStream($stream);
244
    }
245
246
    /**
247
     * @param ProductStream $productStream
248
     * @return bool
249
     */
250
    public function isStatic(ProductStream $productStream)
251
    {
252
        if ($productStream->getType() == self::STATIC_STREAM) {
253
            return true;
254
        }
255
256
        return false;
257
    }
258
259
    /**
260
     * @param null $start
261
     * @param null $limit
262
     * @return array
263
     */
264
    public function getList($start = null, $limit = null)
265
    {
266
        $streamList = $this->productStreamRepository->fetchStreamList($start, $limit);
267
268
        $isCronActive = $this->config->isCronActive();
269
270
        $streams = $streamList['streams'];
271
        foreach ($streams as $index => $stream) {
272
            if ($stream['type'] == self::STATIC_STREAM) {
273
                $streams[$index]['productCount'] = $this->countProductsInStaticStream($stream['id']);
274
            } elseif ($stream['type'] == self::DYNAMIC_STREAM) {
275
                $streams[$index]['enableRow'] = $isCronActive;
276
            }
277
        }
278
279
        return [
280
            'data' => $streams,
281
            'total' => $streamList['total']
282
        ];
283
    }
284
285
    /**
286
     * @param $type
287
     * @return array
288
     */
289
    public function getAllExportedStreams($type)
290
    {
291
        return $this->productStreamRepository->fetchExportedStreams($type);
292
    }
293
294
    /**
295
     * @param ProductStream $stream
296
     * @return ProductStreamAttribute
297
     */
298
    public function createStreamAttribute(ProductStream $stream)
299
    {
300
        $streamAttribute = $this->streamAttrRepository->findOneBy(['streamId' => $stream->getId()]);
301
302
        if (!$streamAttribute) {
303
            $streamAttribute = $this->streamAttrRepository->create();
304
            $streamAttribute->setStreamId($stream->getId());
305
        }
306
307
        return $streamAttribute;
308
    }
309
310
    /**
311
     * @param $streamId
312
     * @return string
313
     */
314
    public function countProductsInStaticStream($streamId)
315
    {
316
        return $this->productStreamRepository->countProductsInStaticStream($streamId);
317
    }
318
319
    /**
320
     * @param $streamId
321
     * @return bool
322
     */
323
    public function isStreamExported($streamId)
324
    {
325
        return $this->streamAttrRepository->isStreamExported($streamId);
326
    }
327
328
    /**
329
     * @param $streamId
330
     * @return \Doctrine\DBAL\Driver\Statement|int
331
     */
332
    public function markProductsToBeRemovedFromStream($streamId)
333
    {
334
        return $this->productStreamRepository->markProductsToBeRemovedFromStream($streamId);
335
    }
336
337
    /**
338
     * @param $streamId
339
     * @param array $articleIds
340
     * @return array
341
     */
342
    public function createStreamRelation($streamId, array $articleIds)
343
    {
344
        return $this->productStreamRepository->createStreamRelation($streamId, $articleIds);
345
    }
346
347
    /**
348
     * @return \Doctrine\DBAL\Driver\Statement|int
349
     */
350
    public function removeMarkedStreamRelations()
351
    {
352
        return $this->productStreamRepository->removeMarkedStreamRelations();
353
    }
354
355
    /**
356
     * @return array
357
     */
358
    public function getConnectStreamIds()
359
    {
360
        return $this->productStreamRepository->fetchConnectStreamIds();
361
    }
362
363
    /**
364
     * @param int $streamId
365
     * @param string $status
366
     * @param string $exportMessage
0 ignored issues
show
Documentation introduced by
Should the type for parameter $exportMessage not be string|null?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
367
     */
368
    public function changeStatus($streamId, $status, $exportMessage = null)
369
    {
370
        $streamAttr = $this->streamAttrRepository->findOneBy(['streamId' => (int) $streamId]);
371
372
        if (!$streamAttr) {
373
            $streamAttr = $this->streamAttrRepository->create();
374
            $streamAttr->setStreamId($streamId);
375
        }
376
377
        $streamAttr->setExportStatus($status);
378
        if ($exportMessage !== null) {
379
            $streamAttr->setExportMessage($exportMessage);
380
        }
381
        $this->streamAttrRepository->save($streamAttr);
382
    }
383
384
    /**
385
     * @param $streamId
386
     * @param $message
387
     * @deprecated Use changeStatus instead. Will be removed in version 1.2.0
388
     */
389
    public function log($streamId, $message)
390
    {
391
        /** @var ProductStreamAttribute $streamAttr */
392
        $streamAttr = $this->streamAttrRepository->findOneBy(['streamId' => $streamId]);
393
        $streamAttr->setExportMessage($message);
394
395
        $this->streamAttrRepository->save($streamAttr);
396
    }
397
}
398