diff --git a/src/Illuminate/Database/Console/PruneCommand.php b/src/Illuminate/Database/Console/PruneCommand.php index 74be6b92669d..9aa9f62923e8 100644 --- a/src/Illuminate/Database/Console/PruneCommand.php +++ b/src/Illuminate/Database/Console/PruneCommand.php @@ -19,7 +19,8 @@ class PruneCommand extends Command */ protected $signature = 'model:prune {--model=* : Class names of the models to be pruned} - {--chunk=1000 : The number of models to retrieve per chunk of models to be deleted}'; + {--chunk=1000 : The number of models to retrieve per chunk of models to be deleted} + {--pretend : Display the number of prunable records found instead of deleting them}'; /** * The console command description. @@ -44,6 +45,14 @@ public function handle(Dispatcher $events) return; } + if ($this->option('pretend')) { + $models->each(function ($model) { + $this->pretendToPrune($model); + }); + + return; + } + $events->listen(ModelsPruned::class, function ($event) { $this->info("{$event->count} [{$event->model}] records have been pruned."); }); @@ -104,4 +113,26 @@ protected function isPrunable($model) return in_array(Prunable::class, $uses) || in_array(MassPrunable::class, $uses); } + + /** + * Display how many models will be pruned. + * + * @param string $model + * @return void + */ + protected function pretendToPrune($model) + { + $instance = new $model; + + $count = $instance->prunable() + ->when(in_array(SoftDeletes::class, class_uses_recursive(get_class($instance))), function ($query) { + $query->withTrashed(); + })->count(); + + if ($count === 0) { + $this->info("No prunable [$model] records found."); + } else { + $this->info("{$count} [{$model}] records will be pruned."); + } + } } diff --git a/tests/Database/PruneCommandTest.php b/tests/Database/PruneCommandTest.php index 2b98680c0da4..de5c42f5a228 100644 --- a/tests/Database/PruneCommandTest.php +++ b/tests/Database/PruneCommandTest.php @@ -4,12 +4,15 @@ use Illuminate\Container\Container; use Illuminate\Contracts\Events\Dispatcher as DispatcherContract; +use Illuminate\Database\Capsule\Manager as DB; +use Illuminate\Database\ConnectionResolverInterface; use Illuminate\Database\Console\PruneCommand; use Illuminate\Database\Eloquent\MassPrunable; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Prunable; use Illuminate\Database\Events\ModelsPruned; use Illuminate\Events\Dispatcher; +use Mockery as m; use PHPUnit\Framework\TestCase; use Symfony\Component\Console\Input\ArrayInput; use Symfony\Component\Console\Output\BufferedOutput; @@ -60,6 +63,41 @@ public function testNonPrunableTest() EOF, str_replace("\r", '', $output->fetch())); } + public function testTheCommandMayBePretended() + { + $db = new DB; + $db->addConnection([ + 'driver' => 'sqlite', + 'database' => ':memory:', + ]); + $db->setAsGlobal(); + DB::connection('default')->getSchemaBuilder()->create('prunables', function ($table) { + $table->string('name')->nullable(); + $table->string('value')->nullable(); + }); + DB::connection('default')->table('prunables')->insert([ + ['name' => 'zain', 'value' => 1], + ['name' => 'patrice', 'value' => 2], + ['name' => 'amelia', 'value' => 3], + ['name' => 'stuart', 'value' => 4], + ['name' => 'bello', 'value' => 5], + ]); + $resolver = m::mock(ConnectionResolverInterface::class, ['connection' => $db->getConnection('default')]); + PrunableTestModelWithPrunableRecords::setConnectionResolver($resolver); + + $output = $this->artisan([ + '--model' => PrunableTestModelWithPrunableRecords::class, + '--pretend' => true, + ]); + + $this->assertEquals(<<<'EOF' +3 [Illuminate\Tests\Database\PrunableTestModelWithPrunableRecords] records will be pruned. + +EOF, str_replace("\r", '', $output->fetch())); + + $this->assertEquals(5, PrunableTestModelWithPrunableRecords::count()); + } + protected function artisan($arguments) { $input = new ArrayInput($arguments); @@ -84,6 +122,9 @@ class PrunableTestModelWithPrunableRecords extends Model { use MassPrunable; + protected $table = 'prunables'; + protected $connection = 'default'; + public function pruneAll() { event(new ModelsPruned(static::class, 10)); @@ -91,6 +132,11 @@ public function pruneAll() return 20; } + + public function prunable() + { + return static::where('value', '>=', 3); + } } class PrunableTestModelWithoutPrunableRecords extends Model