Skip to content

Commit 1cefdac

Browse files
[12.x] isSoftDeletable(), isPrunable(), and isMassPrunable() to model class (#56060)
* feat(database): ✨ Add isSoftDeletable(), isPrunable(), and isMassPrunable() to model class * fix(database): 🐛 Call model method instead of command method * Restore "only check for soft deletes once when mass-pruning" Co-authored-by: Luke Kuzmish <42181698+cosmastech@users.noreply.github.com> See #55274 See #56060 (comment) * Fix typo Follow-up to 07520f2 * formatting * fix test --------- Co-authored-by: Taylor Otwell <taylor@laravel.com>
1 parent ddad40d commit 1cefdac

File tree

10 files changed

+39
-37
lines changed

10 files changed

+39
-37
lines changed

src/Illuminate/Database/Console/PruneCommand.php

Lines changed: 4 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,6 @@
44

55
use Illuminate\Console\Command;
66
use Illuminate\Contracts\Events\Dispatcher;
7-
use Illuminate\Database\Eloquent\MassPrunable;
8-
use Illuminate\Database\Eloquent\Prunable;
9-
use Illuminate\Database\Eloquent\SoftDeletes;
107
use Illuminate\Database\Events\ModelPruningFinished;
118
use Illuminate\Database\Events\ModelPruningStarting;
129
use Illuminate\Database\Events\ModelsPruned;
@@ -101,7 +98,7 @@ protected function pruneModel(string $model)
10198
? $instance->prunableChunkSize
10299
: $this->option('chunk');
103100

104-
$total = $this->isPrunable($model)
101+
$total = $model::isPrunable()
105102
? $instance->pruneAll($chunkSize)
106103
: 0;
107104

@@ -141,7 +138,7 @@ protected function models()
141138
})
142139
->when(! empty($except), fn ($models) => $models->reject(fn ($model) => in_array($model, $except)))
143140
->filter(fn ($model) => class_exists($model))
144-
->filter(fn ($model) => $this->isPrunable($model))
141+
->filter(fn ($model) => $model::isPrunable())
145142
->values();
146143
}
147144

@@ -161,31 +158,18 @@ protected function getPath()
161158
return app_path('Models');
162159
}
163160

164-
/**
165-
* Determine if the given model class is prunable.
166-
*
167-
* @param string $model
168-
* @return bool
169-
*/
170-
protected function isPrunable($model)
171-
{
172-
$uses = class_uses_recursive($model);
173-
174-
return in_array(Prunable::class, $uses) || in_array(MassPrunable::class, $uses);
175-
}
176-
177161
/**
178162
* Display how many models will be pruned.
179163
*
180-
* @param string $model
164+
* @param class-string $model
181165
* @return void
182166
*/
183167
protected function pretendToPrune($model)
184168
{
185169
$instance = new $model;
186170

187171
$count = $instance->prunable()
188-
->when(in_array(SoftDeletes::class, class_uses_recursive(get_class($instance))), function ($query) {
172+
->when($model::isSoftDeletable(), function ($query) {
189173
$query->withTrashed();
190174
})->count();
191175

src/Illuminate/Database/Eloquent/Factories/Factory.php

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@
88
use Illuminate\Contracts\Foundation\Application;
99
use Illuminate\Database\Eloquent\Collection as EloquentCollection;
1010
use Illuminate\Database\Eloquent\Model;
11-
use Illuminate\Database\Eloquent\SoftDeletes;
1211
use Illuminate\Support\Carbon;
1312
use Illuminate\Support\Collection;
1413
use Illuminate\Support\Enumerable;
@@ -971,7 +970,7 @@ public function __call($method, $parameters)
971970
return $this->macroCall($method, $parameters);
972971
}
973972

974-
if ($method === 'trashed' && in_array(SoftDeletes::class, class_uses_recursive($this->modelName()))) {
973+
if ($method === 'trashed' && $this->modelName()::isSoftDeletable()) {
975974
return $this->state([
976975
$this->newModel()->getDeletedAtColumn() => $parameters[0] ?? Carbon::now()->subDay(),
977976
]);

src/Illuminate/Database/Eloquent/MassPrunable.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ public function pruneAll(int $chunkSize = 1000)
2323

2424
$total = 0;
2525

26-
$softDeletable = in_array(SoftDeletes::class, class_uses_recursive(get_class($this)));
26+
$softDeletable = static::isSoftDeletable();
2727

2828
do {
2929
$total += $count = $softDeletable

src/Illuminate/Database/Eloquent/Model.php

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2289,6 +2289,30 @@ public function setPerPage($perPage)
22892289
return $this;
22902290
}
22912291

2292+
/**
2293+
* Determine if the model is soft deletable.
2294+
*/
2295+
public static function isSoftDeletable(): bool
2296+
{
2297+
return in_array(SoftDeletes::class, class_uses_recursive(static::class));
2298+
}
2299+
2300+
/**
2301+
* Determine if the model is prunable.
2302+
*/
2303+
protected function isPrunable(): bool
2304+
{
2305+
return in_array(Prunable::class, class_uses_recursive(static::class)) || static::isMassPrunable();
2306+
}
2307+
2308+
/**
2309+
* Determine if the model is mass prunable.
2310+
*/
2311+
protected function isMassPrunable(): bool
2312+
{
2313+
return in_array(MassPrunable::class, class_uses_recursive(static::class));
2314+
}
2315+
22922316
/**
22932317
* Determine if lazy loading is disabled.
22942318
*

src/Illuminate/Database/Eloquent/Prunable.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ public function pruneAll(int $chunkSize = 1000)
2020
$total = 0;
2121

2222
$this->prunable()
23-
->when(in_array(SoftDeletes::class, class_uses_recursive(static::class)), function ($query) {
23+
->when(static::isSoftDeletable(), function ($query) {
2424
$query->withTrashed();
2525
})->chunkById($chunkSize, function ($models) use (&$total) {
2626
$models->each(function ($model) use (&$total) {
@@ -64,7 +64,7 @@ public function prune()
6464
{
6565
$this->pruning();
6666

67-
return in_array(SoftDeletes::class, class_uses_recursive(static::class))
67+
return static::isSoftDeletable()
6868
? $this->forceDelete()
6969
: $this->delete();
7070
}

src/Illuminate/Database/Eloquent/Relations/HasOneOrManyThrough.php

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@
99
use Illuminate\Database\Eloquent\Model;
1010
use Illuminate\Database\Eloquent\ModelNotFoundException;
1111
use Illuminate\Database\Eloquent\Relations\Concerns\InteractsWithDictionary;
12-
use Illuminate\Database\Eloquent\SoftDeletes;
1312
use Illuminate\Database\Query\Grammars\MySqlGrammar;
1413
use Illuminate\Database\UniqueConstraintViolationException;
1514

@@ -146,7 +145,7 @@ public function getQualifiedParentKeyName()
146145
*/
147146
public function throughParentSoftDeletes()
148147
{
149-
return in_array(SoftDeletes::class, class_uses_recursive($this->throughParent));
148+
return $this->throughParent::isSoftDeletable();
150149
}
151150

152151
/**

src/Illuminate/Foundation/Testing/Concerns/InteractsWithDatabase.php

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44

55
use Illuminate\Contracts\Support\Jsonable;
66
use Illuminate\Database\Eloquent\Model;
7-
use Illuminate\Database\Eloquent\SoftDeletes;
87
use Illuminate\Database\Events\QueryExecuted;
98
use Illuminate\Support\Arr;
109
use Illuminate\Support\Facades\DB;
@@ -223,8 +222,7 @@ public function expectsDatabaseQueryCount($expected, $connection = null)
223222
*/
224223
protected function isSoftDeletableModel($model)
225224
{
226-
return $model instanceof Model
227-
&& in_array(SoftDeletes::class, class_uses_recursive($model));
225+
return $model instanceof Model && $model::isSoftDeletable();
228226
}
229227

230228
/**

src/Illuminate/Routing/ImplicitRouteBinding.php

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44

55
use Illuminate\Contracts\Routing\UrlRoutable;
66
use Illuminate\Database\Eloquent\ModelNotFoundException;
7-
use Illuminate\Database\Eloquent\SoftDeletes;
87
use Illuminate\Routing\Exceptions\BackedEnumCaseNotFoundException;
98
use Illuminate\Support\Reflector;
109
use Illuminate\Support\Str;
@@ -42,14 +41,14 @@ public static function resolveForRoute($container, $route)
4241

4342
$parent = $route->parentOfParameter($parameterName);
4443

45-
$routeBindingMethod = $route->allowsTrashedBindings() && in_array(SoftDeletes::class, class_uses_recursive($instance))
44+
$routeBindingMethod = $route->allowsTrashedBindings() && $instance::isSoftDeletable()
4645
? 'resolveSoftDeletableRouteBinding'
4746
: 'resolveRouteBinding';
4847

4948
if ($parent instanceof UrlRoutable &&
5049
! $route->preventsScopedBindings() &&
5150
($route->enforcesScopedBindings() || array_key_exists($parameterName, $route->bindingFields()))) {
52-
$childRouteBindingMethod = $route->allowsTrashedBindings() && in_array(SoftDeletes::class, class_uses_recursive($instance))
51+
$childRouteBindingMethod = $route->allowsTrashedBindings() && $instance::isSoftDeletable()
5352
? 'resolveSoftDeletableChildRouteBinding'
5453
: 'resolveChildRouteBinding';
5554

src/Illuminate/Routing/RouteBinding.php

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44

55
use Closure;
66
use Illuminate\Database\Eloquent\ModelNotFoundException;
7-
use Illuminate\Database\Eloquent\SoftDeletes;
87
use Illuminate\Support\Str;
98

109
class RouteBinding
@@ -68,7 +67,7 @@ public static function forModel($container, $class, $callback = null)
6867
// throw a not found exception otherwise we will return the instance.
6968
$instance = $container->make($class);
7069

71-
$routeBindingMethod = $route?->allowsTrashedBindings() && in_array(SoftDeletes::class, class_uses_recursive($instance))
70+
$routeBindingMethod = $route?->allowsTrashedBindings() && $instance::isSoftDeletable()
7271
? 'resolveSoftDeletableRouteBinding'
7372
: 'resolveRouteBinding';
7473

tests/Support/SupportArrTest.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -292,8 +292,8 @@ public function testWhereNotNull(): void
292292
$array = array_values(Arr::whereNotNull(['a', null, 'b', null, 'c']));
293293
$this->assertEquals(['a', 'b', 'c'], $array);
294294

295-
$array = array_values(Arr::whereNotNull([null, 1, 'string', 0.0, false, [], new stdClass(), fn () => null]));
296-
$this->assertEquals([1, 'string', 0.0, false, [], new stdClass(), fn () => null], $array);
295+
$array = array_values(Arr::whereNotNull([null, 1, 'string', 0.0, false, [], $class = new stdClass(), $function = fn () => null]));
296+
$this->assertEquals([1, 'string', 0.0, false, [], $class, $function], $array);
297297
}
298298

299299
public function testFirst()

0 commit comments

Comments
 (0)