Passed
Push — main ( f8041e...326712 )
by Michael
03:31
created

HasCoupons   A

Complexity

Total Complexity 11

Size/Duplication

Total Lines 155
Duplicated Lines 0 %

Test Coverage

Coverage 100%

Importance

Changes 10
Bugs 0 Features 1
Metric Value
eloc 29
c 10
b 0
f 1
dl 0
loc 155
ccs 32
cts 32
cp 1
rs 10
wmc 11

10 Methods

Rating   Name   Duplication   Size   Complexity  
A redeemCoupon() 0 5 1
A verifyCoupon() 0 3 1
A isCouponRedeemed() 0 7 1
A initializeHasCoupons() 0 4 1
A isCouponOverLimit() 0 5 2
A verifyCouponOr() 0 6 1
A redeemCouponOr() 0 6 1
A coupons() 0 6 1
A redeemBy() 0 5 1
A isCouponAlreadyUsed() 0 3 1
1
<?php
2
3
declare(strict_types=1);
4
5
namespace MichaelRubel\Couponables;
6
7
use Illuminate\Database\Eloquent\Model;
8
use Illuminate\Database\Eloquent\Relations\MorphToMany;
9
use Illuminate\Support\Str;
10
use MichaelRubel\Couponables\Models\Contracts\CouponContract;
11
use MichaelRubel\Couponables\Services\Contracts\CouponServiceContract;
12
use MichaelRubel\EnhancedContainer\Call;
13
use MichaelRubel\EnhancedContainer\Core\CallProxy;
14
15
trait HasCoupons
16
{
17
    /**
18
     * @var CallProxy
19
     */
20
    protected static CallProxy $bindable;
21
22
    /**
23
     * @var CallProxy
24
     */
25
    protected static CallProxy $bindableService;
26
27
    /**
28
     * Initialize the method binding objects.
29
     *
30
     * @return void
31
     */
32 36
    public function initializeHasCoupons(): void
33
    {
34 36
        self::$bindable        = call($this);
35 36
        self::$bindableService = call(CouponServiceContract::class);
36
    }
37
38
    /**
39
     * Polymorphic relation to the coupons.
40
     *
41
     * @return MorphToMany
42
     */
43 18
    public function coupons(): MorphToMany
44
    {
45 18
        return $this->morphToMany(
0 ignored issues
show
Bug introduced by
It seems like morphToMany() must be provided by classes using this trait. How about adding it as abstract method to this trait? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

45
        return $this->/** @scrutinizer ignore-call */ morphToMany(
Loading history...
46 18
            self::$bindableService->model->getInternal(Call::INSTANCE),
47 18
            Str::singular(config('couponables.pivot_table', 'couponables'))
48 18
        )->withPivot(self::$bindableService->pivot->getRedeemedAtColumn());
49
    }
50
51
    /**
52
     * Perform coupon verification.
53
     *
54
     * @param string|null $code
55
     *
56
     * @return CouponContract
57
     */
58 4
    public function verifyCoupon(?string $code): CouponContract
59
    {
60 4
        return self::$bindableService->verifyCoupon($code, $this);
61
    }
62
63
    /**
64
     * Verify the coupon or do something else on fail.
65
     *
66
     * @param string|null $code
67
     * @param mixed|null $callback
68
     * @param bool $report
69
     *
70
     * @return mixed
71
     */
72 3
    public function verifyCouponOr(?string $code, mixed $callback = null, bool $report = false): mixed
73
    {
74 3
        return rescue(
75 3
            callback: fn () => self::$bindable->verifyCoupon($code),
76
            rescue: $callback,
77
            report: $report
78
        );
79
    }
80
81
    /**
82
     * Use the coupon.
83
     *
84
     * @param string|null $code
85
     * @param Model|null  $redeemed
86
     *
87
     * @return CouponContract
88
     */
89 23
    public function redeemCoupon(?string $code, ?Model $redeemed = null): CouponContract
90
    {
91 23
        $coupon = self::$bindableService->verifyCoupon($code, $this);
92
93 16
        return self::$bindableService->applyCoupon($coupon, $this, $redeemed);
94
    }
95
96
    /**
97
     * Redeem the code using model.
98
     *
99
     * @param Model       $model
100
     * @param string|null $couponCode
101
     *
102
     * @return CouponContract
103
     */
104 1
    public function redeemBy(Model $model, ?string $couponCode): CouponContract
105
    {
106 1
        $coupon = self::$bindableService->verifyCoupon($couponCode, $model);
107
108 1
        return self::$bindableService->applyCoupon($coupon, $model, $this);
109
    }
110
111
    /**
112
     * Redeem the coupon or do something else on fail.
113
     *
114
     * @param string|null $code
115
     * @param mixed|null $callback
116
     * @param bool $report
117
     *
118
     * @return mixed
119
     */
120 3
    public function redeemCouponOr(?string $code, mixed $callback = null, bool $report = false): mixed
121
    {
122 3
        return rescue(
123 3
            callback: fn () => self::$bindable->redeemCoupon($code, null),
124
            rescue: $callback,
125
            report: $report
126
        );
127
    }
128
129
    /**
130
     * Check if the coupon is already redeemed by the model at least once.
131
     *
132
     * @param string $code
133
     *
134
     * @return bool
135
     */
136 5
    public function isCouponRedeemed(string $code): bool
137
    {
138 5
        $column = self::$bindableService->model->getCodeColumn();
139
140 5
        return $this->coupons()
141 5
            ->where($column, $code)
142 5
            ->exists();
143
    }
144
145
    /**
146
     * Check if coupon with this code is already used.
147
     *
148
     * @param string|null $code
149
     *
150
     * @return bool
151
     */
152 3
    public function isCouponAlreadyUsed(?string $code): bool
153
    {
154 3
        return self::$bindable->isCouponRedeemed($code);
155
    }
156
157
    /**
158
     * Check if the coupon is over limit for the model.
159
     *
160
     * @param string|null $code
161
     *
162
     * @return bool
163
     *
164
     */
165 1
    public function isCouponOverLimit(?string $code): bool
166
    {
167 1
        $coupon = self::$bindableService->getCoupon($code);
168
169 1
        return ! is_null($coupon) && call($coupon)->isOverLimitFor($this);
170
    }
171
}
172