diff --git a/CHANGELOG.md b/CHANGELOG.md index fe44cbfb8..3841b715c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -22,6 +22,7 @@ All notable changes to this project will be documented in this file. - Fix Query on `whereDate`, `whereDay`, `whereMonth`, `whereYear`, `whereTime` to use MongoDB operators [#2570](https://github.com/mongodb/laravel-mongodb/pull/2376) by [@Davpyu](https://github.com/Davpyu) and [@GromNaN](https://github.com/GromNaN). - `Model::unset()` does not persist the change. Call `Model::save()` to persist the change [#2578](https://github.com/mongodb/laravel-mongodb/pull/2578) by [@GromNaN](https://github.com/GromNaN). - Support delete one document with `Query\Builder::limit(1)->delete()` [#2591](https://github.com/mongodb/laravel-mongodb/pull/2591) by [@GromNaN](https://github.com/GromNaN) +- Add trait `MongoDB\Laravel\Eloquent\MassPrunable` to replace the Eloquent trait on MongoDB models [#2598](https://github.com/mongodb/laravel-mongodb/pull/2598) by [@GromNaN](https://github.com/GromNaN) ## [3.9.2] - 2022-09-01 diff --git a/README.md b/README.md index d7a505bd1..e5e599cfd 100644 --- a/README.md +++ b/README.md @@ -44,6 +44,7 @@ It is compatible with Laravel 10.x. For older versions of Laravel, please refer - [Cross-Database Relationships](#cross-database-relationships) - [Authentication](#authentication) - [Queues](#queues) + - [Prunable](#prunable) - [Upgrading](#upgrading) - [Upgrading from version 2 to 3](#upgrading-from-version-2-to-3) - [Security contact information](#security-contact-information) @@ -1189,14 +1190,35 @@ Add the service provider in `config/app.php`: MongoDB\Laravel\MongodbQueueServiceProvider::class, ``` +### Prunable + +`Prunable` and `MassPrunable` traits are Laravel features to automatically remove models from your database. You can use +`Illuminate\Database\Eloquent\Prunable` trait to remove models one by one. If you want to remove models in bulk, you need +to use the `MongoDB\Laravel\Eloquent\MassPrunable` trait instead: it will be more performant but can break links with +other documents as it does not load the models. + + +```php +use MongoDB\Laravel\Eloquent\Model; +use MongoDB\Laravel\Eloquent\MassPrunable; + +class Book extends Model +{ + use MassPrunable; +} +``` + Upgrading --------- #### Upgrading from version 3 to 4 Change project name in composer.json to `mongodb/laravel` and run `composer update`. + Change namespace from `Jenssegers\Mongodb` to `MongoDB\Laravel` in your models and config. +Replace `Illuminate\Database\Eloquent\MassPrunable` with `MongoDB\Laravel\Eloquent\MassPrunable` in your models. + ## Security contact information To report a security vulnerability, follow [these steps](https://tidelift.com/security). diff --git a/src/Eloquent/MassPrunable.php b/src/Eloquent/MassPrunable.php new file mode 100644 index 000000000..df8839d5d --- /dev/null +++ b/src/Eloquent/MassPrunable.php @@ -0,0 +1,28 @@ +prunable(); + $total = in_array(SoftDeletes::class, class_uses_recursive(get_class($this))) + ? $query->forceDelete() + : $query->delete(); + + event(new ModelsPruned(static::class, $total)); + + return $total; + } +} diff --git a/tests/Eloquent/MassPrunableTest.php b/tests/Eloquent/MassPrunableTest.php new file mode 100644 index 000000000..3426a2443 --- /dev/null +++ b/tests/Eloquent/MassPrunableTest.php @@ -0,0 +1,63 @@ +assertTrue($this->isPrunable(User::class)); + + User::insert([ + ['name' => 'John Doe', 'age' => 35], + ['name' => 'Jane Doe', 'age' => 32], + ['name' => 'Tomy Doe', 'age' => 11], + ]); + + $model = new User(); + $total = $model->pruneAll(); + $this->assertEquals(2, $total); + $this->assertEquals(1, User::count()); + } + + public function testPruneSoftDelete(): void + { + $this->assertTrue($this->isPrunable(Soft::class)); + + Soft::insert([ + ['name' => 'John Doe'], + ['name' => 'Jane Doe'], + ]); + + $model = new Soft(); + $total = $model->pruneAll(); + $this->assertEquals(2, $total); + $this->assertEquals(0, Soft::count()); + $this->assertEquals(0, Soft::withTrashed()->count()); + } + + /** + * @see PruneCommand::isPrunable() + */ + protected function isPrunable($model) + { + $uses = class_uses_recursive($model); + + return in_array(Prunable::class, $uses) || in_array(MassPrunable::class, $uses); + } +} diff --git a/tests/Models/Soft.php b/tests/Models/Soft.php index aec3a0bb9..7a5d25704 100644 --- a/tests/Models/Soft.php +++ b/tests/Models/Soft.php @@ -4,6 +4,8 @@ namespace MongoDB\Laravel\Tests\Models; +use MongoDB\Laravel\Eloquent\Builder; +use MongoDB\Laravel\Eloquent\MassPrunable; use MongoDB\Laravel\Eloquent\Model as Eloquent; use MongoDB\Laravel\Eloquent\SoftDeletes; @@ -15,9 +17,15 @@ class Soft extends Eloquent { use SoftDeletes; + use MassPrunable; protected $connection = 'mongodb'; protected $collection = 'soft'; protected static $unguarded = true; protected $casts = ['deleted_at' => 'datetime']; + + public function prunable(): Builder + { + return $this->newQuery(); + } } diff --git a/tests/Models/User.php b/tests/Models/User.php index f1d373fab..57319f84a 100644 --- a/tests/Models/User.php +++ b/tests/Models/User.php @@ -12,7 +12,9 @@ use Illuminate\Database\Eloquent\Casts\Attribute; use Illuminate\Notifications\Notifiable; use Illuminate\Support\Str; +use MongoDB\Laravel\Eloquent\Builder; use MongoDB\Laravel\Eloquent\HybridRelations; +use MongoDB\Laravel\Eloquent\MassPrunable; use MongoDB\Laravel\Eloquent\Model as Eloquent; /** @@ -35,6 +37,7 @@ class User extends Eloquent implements AuthenticatableContract, CanResetPassword use CanResetPassword; use HybridRelations; use Notifiable; + use MassPrunable; protected $connection = 'mongodb'; protected $casts = [ @@ -106,4 +109,9 @@ protected function username(): Attribute set: fn ($value) => Str::slug($value) ); } + + public function prunable(): Builder + { + return $this->where('age', '>', 18); + } }