Cancellable   A
last analyzed

Complexity

Total Complexity 21

Size/Duplication

Total Lines 189
Duplicated Lines 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 39
dl 0
loc 189
rs 10
c 1
b 0
f 0
wmc 21

12 Methods

Rating   Name   Duplication   Size   Complexity  
A runCancel() 0 19 3
A getCancelledAtColumn() 0 3 2
A bootCancellable() 0 3 1
A unCancel() 0 18 2
A cancel() 0 30 4
A unCancelling() 0 3 1
A isCancelled() 0 4 2
A getQualifiedCancelledAtColumn() 0 3 1
A cancelled() 0 3 1
A initializeCancellable() 0 4 2
A cancelling() 0 3 1
A unCancelled() 0 3 1
1
<?php
2
3
namespace LaravelCancellable;
4
5
use Closure;
6
use Exception;
7
use Illuminate\Database\Eloquent\Builder as EloquentBuilder;
8
use Illuminate\Database\Query\Builder as QueryBuilder;
9
use Illuminate\Support\Carbon;
10
use LaravelCancellable\Scopes\CancellableScope;
11
12
/**
13
 * @method static static|EloquentBuilder|QueryBuilder withCancelled()
14
 * @method static static|EloquentBuilder|QueryBuilder onlyCancelled()
15
 * @method static static|EloquentBuilder|QueryBuilder withoutCancelled()
16
 */
17
trait Cancellable
18
{
19
20
    /**
21
     * Boot the cancelling trait for a model.
22
     *
23
     * @return void
24
     */
25
    public static function bootCancellable(): void
26
    {
27
        static::addGlobalScope(new CancellableScope);
28
    }
29
30
    /**
31
     * Initialize the cancellable trait for an instance.
32
     *
33
     * @return void
34
     */
35
    public function initializeCancellable(): void
36
    {
37
        if (! isset($this->casts[$this->getCancelledAtColumn()])) {
38
            $this->casts[$this->getCancelledAtColumn()] = 'datetime';
0 ignored issues
show
Bug Best Practice introduced by
The property casts does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
39
        }
40
    }
41
42
    /**
43
     * Cancel the model.
44
     *
45
     * @return bool|void|null
46
     *
47
     * @throws Exception
48
     */
49
    public function cancel()
50
    {
51
        $this->mergeAttributesFromClassCasts();
0 ignored issues
show
Bug introduced by
It seems like mergeAttributesFromClassCasts() 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

51
        $this->/** @scrutinizer ignore-call */ 
52
               mergeAttributesFromClassCasts();
Loading history...
52
53
        if (is_null($this->getKeyName())) {
0 ignored issues
show
Bug introduced by
It seems like getKeyName() 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

53
        if (is_null($this->/** @scrutinizer ignore-call */ getKeyName())) {
Loading history...
54
            throw new \RuntimeException('No primary key defined on model.');
55
        }
56
57
        // If the model doesn't exist, there is nothing to cancel.
58
        if (! $this->exists) {
59
            return;
60
        }
61
62
        // If the cancelling event doesn't return false, we'll continue
63
        // with the operation.
64
        if ($this->fireModelEvent('cancelling') === false) {
0 ignored issues
show
Bug introduced by
It seems like fireModelEvent() 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

64
        if ($this->/** @scrutinizer ignore-call */ fireModelEvent('cancelling') === false) {
Loading history...
65
            return false;
66
        }
67
68
        // Update the timestamps for each of the models owners. Breaking any caching
69
        // on the parents
70
        $this->touchOwners();
0 ignored issues
show
Bug introduced by
It seems like touchOwners() 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

70
        $this->/** @scrutinizer ignore-call */ 
71
               touchOwners();
Loading history...
71
72
        $this->runCancel();
73
74
        // Fire cancelled event to allow hooking into the post-cancel operations.
75
        $this->fireModelEvent('cancelled', false);
76
77
        // Return true as the cancel is presumably successful.
78
        return true;
79
    }
80
81
    /**
82
     * Perform the actual cancel query on this model instance.
83
     *
84
     * @return void
85
     */
86
    public function runCancel(): void
87
    {
88
        $query = $this->setKeysForSaveQuery($this->newModelQuery());
0 ignored issues
show
Bug introduced by
It seems like setKeysForSaveQuery() 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

88
        /** @scrutinizer ignore-call */ 
89
        $query = $this->setKeysForSaveQuery($this->newModelQuery());
Loading history...
Bug introduced by
It seems like newModelQuery() 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

88
        $query = $this->setKeysForSaveQuery($this->/** @scrutinizer ignore-call */ newModelQuery());
Loading history...
89
90
        $time = $this->freshTimestamp();
0 ignored issues
show
Bug introduced by
It seems like freshTimestamp() 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

90
        /** @scrutinizer ignore-call */ 
91
        $time = $this->freshTimestamp();
Loading history...
91
92
        $columns = [$this->getCancelledAtColumn() => $this->fromDateTime($time)];
0 ignored issues
show
Bug introduced by
It seems like fromDateTime() 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

92
        $columns = [$this->getCancelledAtColumn() => $this->/** @scrutinizer ignore-call */ fromDateTime($time)];
Loading history...
93
94
        $this->{$this->getCancelledAtColumn()} = $time;
95
96
        if ($this->usesTimestamps() && ! is_null($this->getUpdatedAtColumn())) {
0 ignored issues
show
Bug introduced by
It seems like usesTimestamps() 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

96
        if ($this->/** @scrutinizer ignore-call */ usesTimestamps() && ! is_null($this->getUpdatedAtColumn())) {
Loading history...
Bug introduced by
It seems like getUpdatedAtColumn() 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

96
        if ($this->usesTimestamps() && ! is_null($this->/** @scrutinizer ignore-call */ getUpdatedAtColumn())) {
Loading history...
97
            $this->{$this->getUpdatedAtColumn()} = $time;
98
99
            $columns[$this->getUpdatedAtColumn()] = $this->fromDateTime($time);
100
        }
101
102
        $query->update($columns);
103
104
        $this->syncOriginalAttributes(array_keys($columns));
0 ignored issues
show
Bug introduced by
It seems like syncOriginalAttributes() 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

104
        $this->/** @scrutinizer ignore-call */ 
105
               syncOriginalAttributes(array_keys($columns));
Loading history...
105
    }
106
107
    /**
108
     * Retrieve the model.
109
     *
110
     * @return bool
111
     *
112
     */
113
    public function unCancel(): bool
114
    {
115
        // If the cancelling event return false, we will exit the operation.
116
        // Otherwise, we will clear the cancelled at timestamp and continue
117
        // with the operation
118
        if ($this->fireModelEvent('unCancelling') === false) {
119
            return false;
120
        }
121
122
        $this->{$this->getCancelledAtColumn()} = null;
123
124
        $this->exists = true;
0 ignored issues
show
Bug Best Practice introduced by
The property exists does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
125
126
        $result = $this->save();
0 ignored issues
show
Bug introduced by
It seems like save() 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

126
        /** @scrutinizer ignore-call */ 
127
        $result = $this->save();
Loading history...
127
128
        $this->fireModelEvent('unCancelled', false);
129
130
        return $result;
131
    }
132
133
    /**
134
     * Determine if the model instance has been cancelled.
135
     *
136
     * @return bool
137
     */
138
    public function isCancelled(): bool
139
    {
140
        return !is_null($this->{$this->getCancelledAtColumn()})
141
            && (Carbon::create($this->{$this->getCancelledAtColumn()}) <= Carbon::now());
142
    }
143
144
    /**
145
     * Register a "cancelling" model event callback with the dispatcher.
146
     *
147
     * @param  Closure|string  $callback
148
     * @return void
149
     */
150
    public static function cancelling($callback): void
151
    {
152
        static::registerModelEvent('cancelling', $callback);
153
    }
154
155
    /**
156
     * Register a "cancelled" model event callback with the dispatcher.
157
     *
158
     * @param  Closure|string  $callback
159
     * @return void
160
     */
161
    public static function cancelled($callback): void
162
    {
163
        static::registerModelEvent('cancelled', $callback);
164
    }
165
166
    /**
167
     * Register a "un-cancelling" model event callback with the dispatcher.
168
     *
169
     * @param  Closure|string  $callback
170
     * @return void
171
     */
172
    public static function unCancelling($callback): void
173
    {
174
        static::registerModelEvent('unCancelling', $callback);
175
    }
176
177
    /**
178
     * Register a "un-cancelled" model event callback with the dispatcher.
179
     *
180
     * @param  Closure|string  $callback
181
     * @return void
182
     */
183
    public static function unCancelled($callback): void
184
    {
185
        static::registerModelEvent('unCancelled', $callback);
186
    }
187
188
    /**
189
     * Get the name of the "cancelled at" column.
190
     *
191
     * @return string
192
     */
193
    public function getCancelledAtColumn(): string
194
    {
195
        return defined('static::CANCELLED_AT') ? constant('static::CANCELLED_AT') : 'cancelled_at';
196
    }
197
198
    /**
199
     * Get the fully qualified "cancelled at" column.
200
     *
201
     * @return string
202
     */
203
    public function getQualifiedCancelledAtColumn(): string
204
    {
205
        return $this->qualifyColumn($this->getCancelledAtColumn());
0 ignored issues
show
Bug introduced by
It seems like qualifyColumn() 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

205
        return $this->/** @scrutinizer ignore-call */ qualifyColumn($this->getCancelledAtColumn());
Loading history...
206
    }
207
}
208