jeanlrnt /
laravel-cancellable
| 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
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
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
Loading history...
|
|||||||||
| 52 | |||||||||
| 53 | if (is_null($this->getKeyName())) { |
||||||||
|
0 ignored issues
–
show
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
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
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
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
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
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
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
Loading history...
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
Loading history...
|
|||||||||
| 89 | |||||||||
| 90 | $time = $this->freshTimestamp(); |
||||||||
|
0 ignored issues
–
show
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
Loading history...
|
|||||||||
| 91 | |||||||||
| 92 | $columns = [$this->getCancelledAtColumn() => $this->fromDateTime($time)]; |
||||||||
|
0 ignored issues
–
show
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
Loading history...
|
|||||||||
| 93 | |||||||||
| 94 | $this->{$this->getCancelledAtColumn()} = $time; |
||||||||
| 95 | |||||||||
| 96 | if ($this->usesTimestamps() && ! is_null($this->getUpdatedAtColumn())) { |
||||||||
|
0 ignored issues
–
show
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
Loading history...
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
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
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
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
|
|||||||||
| 125 | |||||||||
| 126 | $result = $this->save(); |
||||||||
|
0 ignored issues
–
show
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
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
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
Loading history...
|
|||||||||
| 206 | } |
||||||||
| 207 | } |
||||||||
| 208 |