Skip to content

Commit c420ccb

Browse files
authored
Dont stop pruning if pruning one model fails (#55237)
1 parent 1194817 commit c420ccb

File tree

2 files changed

+57
-2
lines changed

2 files changed

+57
-2
lines changed

src/Illuminate/Database/Eloquent/Prunable.php

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,10 @@
22

33
namespace Illuminate\Database\Eloquent;
44

5+
use Illuminate\Contracts\Debug\ExceptionHandler;
56
use Illuminate\Database\Events\ModelsPruned;
67
use LogicException;
8+
use Throwable;
79

810
trait Prunable
911
{
@@ -21,9 +23,21 @@ public function pruneAll(int $chunkSize = 1000)
2123
->when(in_array(SoftDeletes::class, class_uses_recursive(static::class)), function ($query) {
2224
$query->withTrashed();
2325
})->chunkById($chunkSize, function ($models) use (&$total) {
24-
$models->each->prune();
26+
$models->each(function ($model) use (&$total) {
27+
try {
28+
$model->prune();
2529

26-
$total += $models->count();
30+
$total++;
31+
} catch (Throwable $e) {
32+
$handler = app(ExceptionHandler::class);
33+
34+
if ($handler) {
35+
$handler->report($e);
36+
} else {
37+
throw $e;
38+
}
39+
}
40+
});
2741

2842
event(new ModelsPruned(static::class, $total));
2943
});

tests/Integration/Database/EloquentPrunableTest.php

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,14 @@
22

33
namespace Illuminate\Tests\Integration\Database;
44

5+
use Exception;
56
use Illuminate\Database\Eloquent\Model;
67
use Illuminate\Database\Eloquent\Prunable;
78
use Illuminate\Database\Eloquent\SoftDeletes;
89
use Illuminate\Database\Events\ModelsPruned;
910
use Illuminate\Database\Schema\Blueprint;
1011
use Illuminate\Support\Facades\Event;
12+
use Illuminate\Support\Facades\Exceptions;
1113
use Illuminate\Support\Facades\Schema;
1214
use LogicException;
1315

@@ -20,6 +22,7 @@ protected function afterRefreshingDatabase()
2022
'prunable_soft_delete_test_models',
2123
'prunable_test_model_missing_prunable_methods',
2224
'prunable_with_custom_prune_method_test_models',
25+
'prunable_with_exceptions',
2326
])->each(function ($table) {
2427
Schema::create($table, function (Blueprint $table) {
2528
$table->increments('id');
@@ -97,6 +100,27 @@ public function testPruneWithCustomPruneMethod()
97100

98101
Event::assertDispatched(ModelsPruned::class, 1);
99102
}
103+
104+
public function testPruneWithExceptionAtOneOfModels()
105+
{
106+
Event::fake();
107+
Exceptions::fake();
108+
109+
collect(range(1, 5000))->map(function ($id) {
110+
return ['name' => 'foo'];
111+
})->chunk(200)->each(function ($chunk) {
112+
PrunableWithException::insert($chunk->all());
113+
});
114+
115+
$count = (new PrunableWithException)->pruneAll();
116+
117+
$this->assertEquals(999, $count);
118+
119+
Event::assertDispatched(ModelsPruned::class, 1);
120+
Event::assertDispatched(fn (ModelsPruned $event) => $event->count === 999);
121+
Exceptions::assertReportedCount(1);
122+
Exceptions::assertReported(fn (Exception $exception) => $exception->getMessage() === 'foo bar');
123+
}
100124
}
101125

102126
class PrunableTestModel extends Model
@@ -136,6 +160,23 @@ public function prune()
136160
}
137161
}
138162

163+
class PrunableWithException extends Model
164+
{
165+
use Prunable;
166+
167+
public function prunable()
168+
{
169+
return $this->where('id', '<=', 1000);
170+
}
171+
172+
public function prune()
173+
{
174+
if ($this->id === 500) {
175+
throw new Exception('foo bar');
176+
}
177+
}
178+
}
179+
139180
class PrunableTestModelMissingPrunableMethod extends Model
140181
{
141182
use Prunable;

0 commit comments

Comments
 (0)