Order   D
last analyzed

Complexity

Total Complexity 59

Size/Duplication

Total Lines 435
Duplicated Lines 0 %

Coupling/Cohesion

Components 2
Dependencies 3

Importance

Changes 0
Metric Value
wmc 59
lcom 2
cbo 3
dl 0
loc 435
rs 4.08
c 0
b 0
f 0

36 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 6 1
A getId() 0 4 1
A getCheckoutCompletedAt() 0 4 1
A setCheckoutCompletedAt() 0 4 1
A isCheckoutCompleted() 0 4 1
A completeCheckout() 0 4 1
A getNumber() 0 4 1
A setNumber() 0 4 1
A getNotes() 0 4 1
A setNotes() 0 4 1
A getItems() 0 4 1
A clearItems() 0 6 1
A countItems() 0 4 1
A addItem() 0 12 2
A removeItem() 0 9 2
A hasItem() 0 4 1
A getItemsTotal() 0 4 1
A recalculateItemsTotal() 0 9 2
A getTotal() 0 4 1
A getTotalQuantity() 0 10 2
A getState() 0 4 1
A setState() 0 4 1
A isEmpty() 0 4 1
A getAdjustments() 0 10 2
A getAdjustmentsRecursively() 0 11 3
A addAdjustment() 0 8 2
A removeAdjustment() 0 8 3
A hasAdjustment() 0 4 1
A getAdjustmentsTotal() 0 15 4
A getAdjustmentsTotalRecursively() 0 11 3
A removeAdjustments() 0 10 3
A removeAdjustmentsRecursively() 0 7 2
A recalculateAdjustmentsTotal() 0 12 3
A recalculateTotal() 0 8 2
A addToAdjustmentsTotal() 0 7 2
A subtractFromAdjustmentsTotal() 0 7 2

How to fix   Complexity   

Complex Class

Complex classes like Order 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 Order, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
/*
4
 * This file is part of the Sylius package.
5
 *
6
 * (c) Paweł Jędrzejewski
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 */
11
12
declare(strict_types=1);
13
14
namespace Sylius\Component\Order\Model;
15
16
use Doctrine\Common\Collections\ArrayCollection;
17
use Doctrine\Common\Collections\Collection;
18
use Sylius\Component\Resource\Model\TimestampableTrait;
19
20
class Order implements OrderInterface
21
{
22
    use TimestampableTrait;
23
24
    /**
25
     * @var mixed
26
     */
27
    protected $id;
28
29
    /**
30
     * @var \DateTimeInterface|null
31
     */
32
    protected $checkoutCompletedAt;
33
34
    /**
35
     * @var string|null
36
     */
37
    protected $number;
38
39
    /**
40
     * @var string|null
41
     */
42
    protected $notes;
43
44
    /**
45
     * @var Collection|OrderItemInterface[]
46
     */
47
    protected $items;
48
49
    /**
50
     * @var int
51
     */
52
    protected $itemsTotal = 0;
53
54
    /**
55
     * @var Collection|AdjustmentInterface[]
56
     */
57
    protected $adjustments;
58
59
    /**
60
     * @var int
61
     */
62
    protected $adjustmentsTotal = 0;
63
64
    /**
65
     * Items total + adjustments total.
66
     *
67
     * @var int
68
     */
69
    protected $total = 0;
70
71
    /**
72
     * @var string
73
     */
74
    protected $state = OrderInterface::STATE_CART;
75
76
    public function __construct()
77
    {
78
        $this->items = new ArrayCollection();
0 ignored issues
show
Documentation Bug introduced by
It seems like new \Doctrine\Common\Collections\ArrayCollection() of type object<Doctrine\Common\C...ctions\ArrayCollection> is incompatible with the declared type object<Doctrine\Common\C...el\OrderItemInterface>> of property $items.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
79
        $this->adjustments = new ArrayCollection();
0 ignored issues
show
Documentation Bug introduced by
It seems like new \Doctrine\Common\Collections\ArrayCollection() of type object<Doctrine\Common\C...ctions\ArrayCollection> is incompatible with the declared type object<Doctrine\Common\C...l\AdjustmentInterface>> of property $adjustments.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
80
        $this->createdAt = new \DateTime();
81
    }
82
83
    /**
84
     * {@inheritdoc}
85
     */
86
    public function getId()
87
    {
88
        return $this->id;
89
    }
90
91
    /**
92
     * {@inheritdoc}
93
     */
94
    public function getCheckoutCompletedAt(): ?\DateTimeInterface
95
    {
96
        return $this->checkoutCompletedAt;
97
    }
98
99
    /**
100
     * {@inheritdoc}
101
     */
102
    public function setCheckoutCompletedAt(?\DateTimeInterface $checkoutCompletedAt): void
103
    {
104
        $this->checkoutCompletedAt = $checkoutCompletedAt;
105
    }
106
107
    /**
108
     * {@inheritdoc}
109
     */
110
    public function isCheckoutCompleted(): bool
111
    {
112
        return null !== $this->checkoutCompletedAt;
113
    }
114
115
    /**
116
     * {@inheritdoc}
117
     */
118
    public function completeCheckout(): void
119
    {
120
        $this->checkoutCompletedAt = new \DateTime();
121
    }
122
123
    /**
124
     * {@inheritdoc}
125
     */
126
    public function getNumber(): ?string
127
    {
128
        return $this->number;
129
    }
130
131
    /**
132
     * {@inheritdoc}
133
     */
134
    public function setNumber(?string $number): void
135
    {
136
        $this->number = $number;
137
    }
138
139
    /**
140
     * {@inheritdoc}
141
     */
142
    public function getNotes(): ?string
143
    {
144
        return $this->notes;
145
    }
146
147
    /**
148
     * {@inheritdoc}
149
     */
150
    public function setNotes(?string $notes): void
151
    {
152
        $this->notes = $notes;
153
    }
154
155
    /**
156
     * {@inheritdoc}
157
     */
158
    public function getItems(): Collection
159
    {
160
        return $this->items;
161
    }
162
163
    /**
164
     * {@inheritdoc}
165
     */
166
    public function clearItems(): void
167
    {
168
        $this->items->clear();
169
170
        $this->recalculateItemsTotal();
171
    }
172
173
    /**
174
     * {@inheritdoc}
175
     */
176
    public function countItems(): int
177
    {
178
        return $this->items->count();
179
    }
180
181
    /**
182
     * {@inheritdoc}
183
     */
184
    public function addItem(OrderItemInterface $item): void
185
    {
186
        if ($this->hasItem($item)) {
187
            return;
188
        }
189
190
        $this->itemsTotal += $item->getTotal();
191
        $this->items->add($item);
192
        $item->setOrder($this);
193
194
        $this->recalculateTotal();
195
    }
196
197
    /**
198
     * {@inheritdoc}
199
     */
200
    public function removeItem(OrderItemInterface $item): void
201
    {
202
        if ($this->hasItem($item)) {
203
            $this->items->removeElement($item);
204
            $this->itemsTotal -= $item->getTotal();
205
            $this->recalculateTotal();
206
            $item->setOrder(null);
207
        }
208
    }
209
210
    /**
211
     * {@inheritdoc}
212
     */
213
    public function hasItem(OrderItemInterface $item): bool
214
    {
215
        return $this->items->contains($item);
216
    }
217
218
    /**
219
     * {@inheritdoc}
220
     */
221
    public function getItemsTotal(): int
222
    {
223
        return $this->itemsTotal;
224
    }
225
226
    /**
227
     * {@inheritdoc}
228
     */
229
    public function recalculateItemsTotal(): void
230
    {
231
        $this->itemsTotal = 0;
232
        foreach ($this->items as $item) {
233
            $this->itemsTotal += $item->getTotal();
234
        }
235
236
        $this->recalculateTotal();
237
    }
238
239
    /**
240
     * {@inheritdoc}
241
     */
242
    public function getTotal(): int
243
    {
244
        return $this->total;
245
    }
246
247
    /**
248
     * {@inheritdoc}
249
     */
250
    public function getTotalQuantity(): int
251
    {
252
        $quantity = 0;
253
254
        foreach ($this->items as $item) {
255
            $quantity += $item->getQuantity();
256
        }
257
258
        return $quantity;
259
    }
260
261
    /**
262
     * {@inheritdoc}
263
     */
264
    public function getState(): string
265
    {
266
        return $this->state;
267
    }
268
269
    /**
270
     * {@inheritdoc}
271
     */
272
    public function setState(string $state): void
273
    {
274
        $this->state = $state;
275
    }
276
277
    /**
278
     * {@inheritdoc}
279
     */
280
    public function isEmpty(): bool
281
    {
282
        return $this->items->isEmpty();
283
    }
284
285
    /**
286
     * {@inheritdoc}
287
     */
288
    public function getAdjustments(?string $type = null): Collection
289
    {
290
        if (null === $type) {
291
            return $this->adjustments;
292
        }
293
294
        return $this->adjustments->filter(function (AdjustmentInterface $adjustment) use ($type) {
295
            return $type === $adjustment->getType();
296
        });
297
    }
298
299
    /**
300
     * {@inheritdoc}
301
     */
302
    public function getAdjustmentsRecursively(?string $type = null): Collection
303
    {
304
        $adjustments = clone $this->getAdjustments($type);
305
        foreach ($this->items as $item) {
306
            foreach ($item->getAdjustmentsRecursively($type) as $adjustment) {
307
                $adjustments->add($adjustment);
308
            }
309
        }
310
311
        return $adjustments;
312
    }
313
314
    /**
315
     * {@inheritdoc}
316
     */
317
    public function addAdjustment(AdjustmentInterface $adjustment): void
318
    {
319
        if (!$this->hasAdjustment($adjustment)) {
320
            $this->adjustments->add($adjustment);
321
            $this->addToAdjustmentsTotal($adjustment);
322
            $adjustment->setAdjustable($this);
323
        }
324
    }
325
326
    /**
327
     * {@inheritdoc}
328
     */
329
    public function removeAdjustment(AdjustmentInterface $adjustment): void
330
    {
331
        if (!$adjustment->isLocked() && $this->hasAdjustment($adjustment)) {
332
            $this->adjustments->removeElement($adjustment);
333
            $this->subtractFromAdjustmentsTotal($adjustment);
334
            $adjustment->setAdjustable(null);
335
        }
336
    }
337
338
    /**
339
     * {@inheritdoc}
340
     */
341
    public function hasAdjustment(AdjustmentInterface $adjustment): bool
342
    {
343
        return $this->adjustments->contains($adjustment);
344
    }
345
346
    /**
347
     * {@inheritdoc}
348
     */
349
    public function getAdjustmentsTotal(?string $type = null): int
350
    {
351
        if (null === $type) {
352
            return $this->adjustmentsTotal;
353
        }
354
355
        $total = 0;
356
        foreach ($this->getAdjustments($type) as $adjustment) {
357
            if (!$adjustment->isNeutral()) {
358
                $total += $adjustment->getAmount();
359
            }
360
        }
361
362
        return $total;
363
    }
364
365
    /**
366
     * {@inheritdoc}
367
     */
368
    public function getAdjustmentsTotalRecursively(?string $type = null): int
369
    {
370
        $total = 0;
371
        foreach ($this->getAdjustmentsRecursively($type) as $adjustment) {
372
            if (!$adjustment->isNeutral()) {
373
                $total += $adjustment->getAmount();
374
            }
375
        }
376
377
        return $total;
378
    }
379
380
    /**
381
     * {@inheritdoc}
382
     */
383
    public function removeAdjustments(?string $type = null): void
384
    {
385
        foreach ($this->getAdjustments($type) as $adjustment) {
386
            if ($adjustment->isLocked()) {
387
                continue;
388
            }
389
390
            $this->removeAdjustment($adjustment);
391
        }
392
    }
393
394
    /**
395
     * {@inheritdoc}
396
     */
397
    public function removeAdjustmentsRecursively(?string $type = null): void
398
    {
399
        $this->removeAdjustments($type);
400
        foreach ($this->items as $item) {
401
            $item->removeAdjustmentsRecursively($type);
402
        }
403
    }
404
405
    /**
406
     * {@inheritdoc}
407
     */
408
    public function recalculateAdjustmentsTotal(): void
409
    {
410
        $this->adjustmentsTotal = 0;
411
412
        foreach ($this->adjustments as $adjustment) {
413
            if (!$adjustment->isNeutral()) {
414
                $this->adjustmentsTotal += $adjustment->getAmount();
415
            }
416
        }
417
418
        $this->recalculateTotal();
419
    }
420
421
    /**
422
     * Items total + Adjustments total.
423
     */
424
    protected function recalculateTotal(): void
425
    {
426
        $this->total = $this->itemsTotal + $this->adjustmentsTotal;
427
428
        if ($this->total < 0) {
429
            $this->total = 0;
430
        }
431
    }
432
433
    /**
434
     * @param AdjustmentInterface $adjustment
435
     */
436
    protected function addToAdjustmentsTotal(AdjustmentInterface $adjustment): void
437
    {
438
        if (!$adjustment->isNeutral()) {
439
            $this->adjustmentsTotal += $adjustment->getAmount();
440
            $this->recalculateTotal();
441
        }
442
    }
443
444
    /**
445
     * @param AdjustmentInterface $adjustment
446
     */
447
    protected function subtractFromAdjustmentsTotal(AdjustmentInterface $adjustment): void
448
    {
449
        if (!$adjustment->isNeutral()) {
450
            $this->adjustmentsTotal -= $adjustment->getAmount();
451
            $this->recalculateTotal();
452
        }
453
    }
454
}
455