Completed
Push — remove-content-bundle ( 1b4274...9f7fdd )
by Kamil
36:32 queued 17:56
created

Order::getLastShipment()   A

Complexity

Conditions 4
Paths 4

Size

Total Lines 15
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 15
rs 9.2
c 0
b 0
f 0
nc 4
cc 4
eloc 8
nop 0

1 Method

Rating   Name   Duplication   Size   Complexity  
A Order::addPromotion() 0 6 2
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
namespace Sylius\Component\Core\Model;
13
14
use Doctrine\Common\Collections\ArrayCollection;
15
use Doctrine\Common\Collections\Collection;
16
use Sylius\Component\Channel\Model\ChannelInterface as BaseChannelInterface;
17
use Sylius\Component\Core\OrderCheckoutStates;
18
use Sylius\Component\Core\OrderPaymentStates;
19
use Sylius\Component\Core\OrderShippingStates;
20
use Sylius\Component\Customer\Model\CustomerInterface as BaseCustomerInterface;
21
use Sylius\Component\Order\Model\Order as BaseOrder;
22
use Sylius\Component\Payment\Model\PaymentInterface as BasePaymentInterface;
23
use Sylius\Component\Promotion\Model\PromotionCouponInterface as BaseCouponInterface;
24
use Sylius\Component\Promotion\Model\PromotionInterface as BasePromotionInterface;
25
use Webmozart\Assert\Assert;
26
27
/**
28
 * @author Paweł Jędrzejewski <[email protected]>
29
 * @author Michał Marcinkowski <[email protected]>
30
 */
31
class Order extends BaseOrder implements OrderInterface
32
{
33
    /**
34
     * @var BaseCustomerInterface
35
     */
36
    protected $customer;
37
38
    /**
39
     * @var ChannelInterface
40
     */
41
    protected $channel;
42
43
    /**
44
     * @var AddressInterface
45
     */
46
    protected $shippingAddress;
47
48
    /**
49
     * @var AddressInterface
50
     */
51
    protected $billingAddress;
52
53
    /**
54
     * @var Collection|BasePaymentInterface[]
55
     */
56
    protected $payments;
57
58
    /**
59
     * @var Collection|ShipmentInterface[]
60
     */
61
    protected $shipments;
62
63
    /**
64
     * @var string
65
     */
66
    protected $currencyCode;
67
68
    /**
69
     * @var float
70
     */
71
    protected $exchangeRate = 1.0;
72
73
    /**
74
     * @var string
75
     */
76
    protected $localeCode;
77
78
    /**
79
     * @var BaseCouponInterface
80
     */
81
    protected $promotionCoupon;
82
83
    /**
84
     * @var string
85
     */
86
    protected $checkoutState = OrderCheckoutStates::STATE_CART;
87
88
    /**
89
     * @var string
90
     */
91
    protected $paymentState = OrderPaymentStates::STATE_CART;
92
93
    /**
94
     * @var string
95
     */
96
    protected $shippingState = OrderShippingStates::STATE_CART;
97
98
    /**
99
     * @var Collection|BasePromotionInterface[]
100
     */
101
    protected $promotions;
102
103
    /**
104
     * @var string
105
     */
106
    protected $tokenValue;
107
108
    public function __construct()
109
    {
110
        parent::__construct();
111
112
        $this->payments = new ArrayCollection();
113
        $this->shipments = new ArrayCollection();
114
        $this->promotions = new ArrayCollection();
115
    }
116
117
    /**
118
     * {@inheritdoc}
119
     */
120
    public function getCustomer()
121
    {
122
        return $this->customer;
123
    }
124
125
    /**
126
     * {@inheritdoc}
127
     */
128
    public function setCustomer(BaseCustomerInterface $customer = null)
129
    {
130
        $this->customer = $customer;
131
    }
132
133
    /**
134
     * {@inheritdoc}
135
     */
136
    public function getChannel()
137
    {
138
        return $this->channel;
139
    }
140
141
    /**
142
     * {@inheritdoc}
143
     */
144
    public function setChannel(BaseChannelInterface $channel = null)
145
    {
146
        $this->channel = $channel;
0 ignored issues
show
Documentation Bug introduced by
It seems like $channel can also be of type object<Sylius\Component\...Model\ChannelInterface>. However, the property $channel is declared as type object<Sylius\Component\...Model\ChannelInterface>. Maybe add an additional type 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 mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
147
    }
148
149
    /**
150
     * {@inheritdoc}
151
     */
152
    public function getUser()
153
    {
154
        if (null === $this->customer) {
155
            return null;
156
        }
157
158
        return $this->customer->getUser();
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface Sylius\Component\Customer\Model\CustomerInterface as the method getUser() does only exist in the following implementations of said interface: Sylius\Component\Core\Model\Customer.

Let’s take a look at an example:

interface User
{
    /** @return string */
    public function getPassword();
}

class MyUser implements User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different implementation of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the interface:

    interface User
    {
        /** @return string */
        public function getPassword();
    
        /** @return string */
        public function getDisplayName();
    }
    
Loading history...
159
    }
160
161
    /**
162
     * {@inheritdoc}
163
     */
164
    public function getShippingAddress()
165
    {
166
        return $this->shippingAddress;
167
    }
168
169
    /**
170
     * {@inheritdoc}
171
     */
172
    public function setShippingAddress(AddressInterface $address)
173
    {
174
        $this->shippingAddress = $address;
175
    }
176
177
    /**
178
     * {@inheritdoc}
179
     */
180
    public function getBillingAddress()
181
    {
182
        return $this->billingAddress;
183
    }
184
185
    /**
186
     * {@inheritdoc}
187
     */
188
    public function setBillingAddress(AddressInterface $address)
189
    {
190
        $this->billingAddress = $address;
191
    }
192
193
    /**
194
     * {@inheritdoc}
195
     */
196
    public function getCheckoutState()
197
    {
198
        return $this->checkoutState;
199
    }
200
201
    /**
202
     * {@inheritdoc}
203
     */
204
    public function setCheckoutState($checkoutState)
205
    {
206
        $this->checkoutState = $checkoutState;
207
    }
208
209
    /**
210
     * {@inheritdoc}
211
     */
212
    public function getPaymentState()
213
    {
214
        return $this->paymentState;
215
    }
216
217
    /**
218
     * {@inheritdoc}
219
     */
220
    public function setPaymentState($paymentState)
221
    {
222
        $this->paymentState = $paymentState;
223
    }
224
225
    /**
226
     * {@inheritdoc}
227
     */
228
    public function getItemUnits()
229
    {
230
        $units = new ArrayCollection();
231
232
        /** @var $item OrderItem */
233
        foreach ($this->getItems() as $item) {
234
            foreach ($item->getUnits() as $unit) {
235
                $units->add($unit);
236
            }
237
        }
238
239
        return $units;
240
    }
241
242
    /**
243
     * {@inheritdoc}
244
     */
245
    public function getItemUnitsByVariant(ProductVariantInterface $variant)
246
    {
247
        return $this->getItemUnits()->filter(function (OrderItemUnitInterface $itemUnit) use ($variant) {
248
            return $variant === $itemUnit->getStockable();
249
        });
250
    }
251
252
    /**
253
     * {@inheritdoc}
254
     */
255
    public function getPayments()
256
    {
257
        return $this->payments;
258
    }
259
260
    /**
261
     * {@inheritdoc}
262
     */
263
    public function hasPayments()
264
    {
265
        return !$this->payments->isEmpty();
266
    }
267
268
    /**
269
     * {@inheritdoc}
270
     */
271
    public function addPayment(BasePaymentInterface $payment)
272
    {
273
        /** @var $payment PaymentInterface */
274
        if (!$this->hasPayment($payment)) {
275
            $this->payments->add($payment);
276
            $payment->setOrder($this);
277
        }
278
    }
279
280
    /**
281
     * {@inheritdoc}
282
     */
283
    public function removePayment(BasePaymentInterface $payment)
284
    {
285
        /** @var $payment PaymentInterface */
286
        if ($this->hasPayment($payment)) {
287
            $this->payments->removeElement($payment);
288
            $payment->setOrder(null);
289
        }
290
    }
291
292
    /**
293
     * {@inheritdoc}
294
     */
295
    public function hasPayment(BasePaymentInterface $payment)
296
    {
297
        return $this->payments->contains($payment);
298
    }
299
300
    /**
301
     * {@inheritdoc}
302
     */
303
    public function getLastNewPayment()
304
    {
305
        if ($this->payments->isEmpty()) {
306
            return null;
307
        }
308
309
        $payment = $this->payments->filter(function (BasePaymentInterface $payment) {
310
            return $payment->getState() === BasePaymentInterface::STATE_NEW;
311
        })->last();
312
313
        return $payment !== false ? $payment : null;
314
    }
315
316
    /**
317
     * {@inheritdoc}
318
     */
319
    public function getShipments()
320
    {
321
        return $this->shipments;
322
    }
323
324
    /**
325
     * {@inheritdoc}
326
     */
327
    public function hasShipments()
328
    {
329
        return !$this->shipments->isEmpty();
330
    }
331
332
    /**
333
     * {@inheritdoc}
334
     */
335
    public function addShipment(ShipmentInterface $shipment)
336
    {
337
        if (!$this->hasShipment($shipment)) {
338
            $shipment->setOrder($this);
339
            $this->shipments->add($shipment);
340
        }
341
    }
342
343
    /**
344
     * {@inheritdoc}
345
     */
346
    public function removeShipment(ShipmentInterface $shipment)
347
    {
348
        if ($this->hasShipment($shipment)) {
349
            $shipment->setOrder(null);
350
            $this->shipments->removeElement($shipment);
351
        }
352
    }
353
354
    /**
355
     * {@inheritdoc}
356
     */
357
    public function removeShipments()
358
    {
359
        $this->shipments->clear();
360
    }
361
362
    /**
363
     * {@inheritdoc}
364
     */
365
    public function hasShipment(ShipmentInterface $shipment)
366
    {
367
        return $this->shipments->contains($shipment);
368
    }
369
370
    /**
371
     * {@inheritdoc}
372
     */
373
    public function getPromotionCoupon()
374
    {
375
        return $this->promotionCoupon;
376
    }
377
378
    /**
379
     * {@inheritdoc}
380
     */
381
    public function setPromotionCoupon(BaseCouponInterface $coupon = null)
382
    {
383
        $this->promotionCoupon = $coupon;
384
    }
385
386
    /**
387
     * {@inheritdoc}
388
     */
389
    public function getPromotionSubjectTotal()
390
    {
391
        return $this->getItemsTotal();
392
    }
393
394
    /**
395
     * {@inheritdoc}
396
     */
397
    public function getPromotionSubjectCount()
398
    {
399
        return $this->getTotalQuantity();
400
    }
401
402
    /**
403
     * {@inheritdoc}
404
     */
405
    public function getCurrencyCode()
406
    {
407
        return $this->currencyCode;
408
    }
409
410
    /**
411
     * {@inheritdoc}
412
     */
413
    public function setCurrencyCode($currencyCode)
414
    {
415
        Assert::string($currencyCode);
416
417
        $this->currencyCode = $currencyCode;
418
    }
419
420
    /**
421
     * {@inheritdoc}
422
     */
423
    public function getExchangeRate()
424
    {
425
        return $this->exchangeRate;
426
    }
427
428
    /**
429
     * {@inheritdoc}
430
     */
431
    public function setExchangeRate($exchangeRate)
432
    {
433
        $this->exchangeRate = (float) $exchangeRate;
434
    }
435
436
    /**
437
     * {@inheritdoc}
438
     */
439
    public function getLocaleCode()
440
    {
441
        return $this->localeCode;
442
    }
443
444
    /**
445
     * {@inheritdoc}
446
     */
447
    public function setLocaleCode($localeCode)
448
    {
449
        Assert::string($localeCode);
450
451
        $this->localeCode = $localeCode;
452
    }
453
454
    /**
455
     * {@inheritdoc}
456
     */
457
    public function getShippingState()
458
    {
459
        return $this->shippingState;
460
    }
461
462
    /**
463
     * {@inheritdoc}
464
     */
465
    public function setShippingState($state)
466
    {
467
        $this->shippingState = $state;
468
    }
469
470
    /**
471
     * {@inheritdoc}
472
     */
473
    public function hasPromotion(BasePromotionInterface $promotion)
474
    {
475
        return $this->promotions->contains($promotion);
476
    }
477
478
    /**
479
     * {@inheritdoc}
480
     */
481
    public function addPromotion(BasePromotionInterface $promotion)
482
    {
483
        if (!$this->hasPromotion($promotion)) {
484
            $this->promotions->add($promotion);
485
        }
486
    }
487
488
    /**
489
     * {@inheritdoc}
490
     */
491
    public function removePromotion(BasePromotionInterface $promotion)
492
    {
493
        if ($this->hasPromotion($promotion)) {
494
            $this->promotions->removeElement($promotion);
495
        }
496
    }
497
498
    /**
499
     * {@inheritdoc}
500
     */
501
    public function getPromotions()
502
    {
503
        return $this->promotions;
504
    }
505
506
    /**
507
     * Returns sum of neutral and non neutral tax adjustments on order and total tax of order items.
508
     *
509
     * {@inheritdoc}
510
     */
511
    public function getTaxTotal()
512
    {
513
        $taxTotal = 0;
514
515
        foreach ($this->getAdjustments(AdjustmentInterface::TAX_ADJUSTMENT) as $taxAdjustment) {
516
            $taxTotal += $taxAdjustment->getAmount();
517
        }
518
        foreach ($this->items as $item) {
519
            $taxTotal += $item->getTaxTotal();
520
        }
521
522
        return $taxTotal;
523
    }
524
525
    /**
526
     * Returns shipping fee together with taxes decreased by shipping discount.
527
     *
528
     * @return int
529
     */
530
    public function getShippingTotal()
531
    {
532
        $shippingTotal = $this->getAdjustmentsTotal(AdjustmentInterface::SHIPPING_ADJUSTMENT);
533
        $shippingTotal += $this->getAdjustmentsTotal(AdjustmentInterface::ORDER_SHIPPING_PROMOTION_ADJUSTMENT);
534
        $shippingTotal += $this->getAdjustmentsTotal(AdjustmentInterface::TAX_ADJUSTMENT);
535
536
        return $shippingTotal;
537
    }
538
539
    /**
540
     * Returns amount of order discount. Does not include order item and shipping discounts.
541
     *
542
     * @return int
543
     */
544
    public function getOrderPromotionTotal()
545
    {
546
        $orderPromotionTotal = 0;
547
548
        foreach ($this->items as $item) {
549
            $orderPromotionTotal += $item->getAdjustmentsTotalRecursively(AdjustmentInterface::ORDER_PROMOTION_ADJUSTMENT);
550
        }
551
552
        return $orderPromotionTotal;
553
    }
554
555
    /**
556
     * {@inheritdoc}
557
     */
558
    public function setTokenValue($tokenValue)
559
    {
560
        $this->tokenValue = $tokenValue;
561
    }
562
563
    /**
564
     * {@inheritdoc}
565
     */
566
    public function getTokenValue()
567
    {
568
        return $this->tokenValue;
569
    }
570
}
571