From e83ebaaf901aa307f3131328a004b6c59a489f1b Mon Sep 17 00:00:00 2001 From: Pe Ell Date: Tue, 21 Mar 2017 02:11:47 +0300 Subject: [PATCH] Add BannedAtScope (#5) Add BannedAtScope --- CHANGELOG.md | 11 ++ README.md | 46 ++++++++ src/Scopes/BannedAtScope.php | 99 +++++++++++++++++ ...HasBannedAt.php => HasBannedAtHelpers.php} | 28 ++++- src/Traits/HasBannedAtScope.php | 32 ++++++ src/Traits/HasBans.php | 40 +------ src/Traits/HasBansRelation.php | 32 ++++++ .../Models/UserWithBannedAtScopeApplied.php | 30 ++++++ tests/unit/Scopes/BannedAtScopeTest.php | 100 ++++++++++++++++++ 9 files changed, 379 insertions(+), 39 deletions(-) create mode 100644 src/Scopes/BannedAtScope.php rename src/Traits/{HasBannedAt.php => HasBannedAtHelpers.php} (64%) create mode 100644 src/Traits/HasBannedAtScope.php create mode 100644 src/Traits/HasBansRelation.php create mode 100644 tests/stubs/Models/UserWithBannedAtScopeApplied.php create mode 100644 tests/unit/Scopes/BannedAtScopeTest.php diff --git a/CHANGELOG.md b/CHANGELOG.md index b4632c6..f8164bd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,16 @@ All notable changes to `laravel-ban` will be documented in this file. +## [2.1.0] - 2017-03-21 + +### Added + +- `withBanned`, `withoutBanned`, `onlyBanned` scopes added to all bannable models + +### Changed + +- `HasBans` is a collection of traits `HasBannedAtHelpers`, `HasBannedAtScope`, `HasBansRelation` now. + ## [2.0.1] - 2017-03-19 ### Changed @@ -19,5 +29,6 @@ All notable changes to `laravel-ban` will be documented in this file. - Initial release +[2.1.0]: https://github.com/cybercog/laravel-ban/compare/2.0.1...2.1.0 [2.0.1]: https://github.com/cybercog/laravel-ban/compare/2.0.0...2.0.1 [2.0.0]: https://github.com/cybercog/laravel-ban/compare/1.0.0...2.0.0 diff --git a/README.md b/README.md index f0afd2b..4671258 100644 --- a/README.md +++ b/README.md @@ -21,6 +21,7 @@ Use case is not limited to User model, any Eloquent model could be banned: Organ - [Prepare bannable model](#prepare-bannable-model) - [Prepare bannable model database table](#prepare-bannable-model-database-table) - [Available methods](#available-methods) + - [Scopes](#scopes) - [Events](#events) - [Middleware](#middleware) - [Scheduling](#scheduling) @@ -186,6 +187,51 @@ $user->isNotBanned(); app(\Cog\Ban\Services\BanService::class)->deleteExpiredBans(); ``` +### Scopes + +#### Get all models which are not banned + +```php +$users = User::withoutBanned()->get(); +``` + +#### Get banned and not banned models + +```php +$users = User::withBanned()->get(); +``` + +#### Get only banned models + +```php +$users = User::onlyBanned()->get(); +``` + +#### Scope auto-apply + +To apply query scopes all the time you can define `shouldApplyBannedAtScope` method in bannable model. If method returns `true` all banned models will be hidden by default. + +```php +use Cog\Ban\Contracts\HasBans as HasBansContract; +use Cog\Ban\Traits\HasBans; +use Illuminate\Foundation\Auth\User as Authenticatable; + +class User extends Authenticatable implements HasBansContract +{ + use HasBans; + + /** + * Determine if BannedAtScope should be applied by default. + * + * @return bool + */ + public function shouldApplyBannedAtScope() + { + return true; + } +} +``` + ### Events If entity is banned `\Cog\Ban\Events\ModelWasBanned` event is fired. diff --git a/src/Scopes/BannedAtScope.php b/src/Scopes/BannedAtScope.php new file mode 100644 index 0000000..d8ff571 --- /dev/null +++ b/src/Scopes/BannedAtScope.php @@ -0,0 +1,99 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Cog\Ban\Scopes; + +use Illuminate\Database\Eloquent\Builder; +use Illuminate\Database\Eloquent\Model; +use Illuminate\Database\Eloquent\Scope; + +/** + * Class BannedAtScope. + * + * @package Cog\Ban\Scopes + */ +class BannedAtScope implements Scope +{ + /** + * All of the extensions to be added to the builder. + * + * @var array + */ + protected $extensions = ['WithBanned', 'WithoutBanned', 'OnlyBanned']; + + /** + * Apply the scope to a given Eloquent query builder. + * + * @param \Illuminate\Database\Eloquent\Builder $builder + * @param \Illuminate\Database\Eloquent\Model $model + * @return \Illuminate\Database\Eloquent\Builder + */ + public function apply(Builder $builder, Model $model) + { + if (method_exists($model, 'shouldApplyBannedAtScope') && $model->shouldApplyBannedAtScope()) { + return $builder->whereNull('banned_at'); + } + + return $builder; + } + + /** + * Extend the query builder with the needed functions. + * + * @param \Illuminate\Database\Eloquent\Builder $builder + * @return void + */ + public function extend(Builder $builder) + { + foreach ($this->extensions as $extension) { + $this->{"add{$extension}"}($builder); + } + } + + /** + * Add the `withBanned` extension to the builder. + * + * @param \Illuminate\Database\Eloquent\Builder $builder + * @return void + */ + protected function addWithBanned(Builder $builder) + { + $builder->macro('withBanned', function (Builder $builder) { + return $builder->withoutGlobalScope($this); + }); + } + + /** + * Add the `withoutBanned` extension to the builder. + * + * @param \Illuminate\Database\Eloquent\Builder $builder + * @return void + */ + protected function addWithoutBanned(Builder $builder) + { + $builder->macro('withoutBanned', function (Builder $builder) { + return $builder->withoutGlobalScope($this)->whereNull('banned_at'); + }); + } + + /** + * Add the `onlyBanned` extension to the builder. + * + * @param \Illuminate\Database\Eloquent\Builder $builder + * @return void + */ + protected function addOnlyBanned(Builder $builder) + { + $builder->macro('onlyBanned', function (Builder $builder) { + return $builder->withoutGlobalScope($this)->whereNotNull('banned_at'); + }); + } +} diff --git a/src/Traits/HasBannedAt.php b/src/Traits/HasBannedAtHelpers.php similarity index 64% rename from src/Traits/HasBannedAt.php rename to src/Traits/HasBannedAtHelpers.php index 8d7115d..d825c7c 100644 --- a/src/Traits/HasBannedAt.php +++ b/src/Traits/HasBannedAtHelpers.php @@ -12,13 +12,14 @@ namespace Cog\Ban\Traits; use Carbon\Carbon; +use Cog\Ban\Contracts\BanService as BanServiceContract; /** - * Class HasBannedAt. + * Class HasBannedAtHelpers. * * @package Cog\Ban\Traits */ -trait HasBannedAt +trait HasBannedAtHelpers { /** * Set banned flag. @@ -63,4 +64,27 @@ public function isNotBanned() { return !$this->isBanned(); } + + /** + * Ban model. + * + * @param null|array $attributes + * @return \Cog\Ban\Contracts\Ban + */ + public function ban(array $attributes = []) + { + $ban = app(BanServiceContract::class)->ban($this, $attributes); + + return $ban; + } + + /** + * Remove ban from model. + * + * @return void + */ + public function unban() + { + app(BanServiceContract::class)->unban($this); + } } diff --git a/src/Traits/HasBannedAtScope.php b/src/Traits/HasBannedAtScope.php new file mode 100644 index 0000000..1041681 --- /dev/null +++ b/src/Traits/HasBannedAtScope.php @@ -0,0 +1,32 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Cog\Ban\Traits; + +use Cog\Ban\Scopes\BannedAtScope; + +/** + * Class HasBannedAtScope. + * + * @package Cog\Ban\Traits + */ +trait HasBannedAtScope +{ + /** + * Boot the HasBannedAtScope trait for a model. + * + * @return void + */ + public static function bootHasBannedAtScope() + { + static::addGlobalScope(new BannedAtScope); + } +} diff --git a/src/Traits/HasBans.php b/src/Traits/HasBans.php index 135adb1..8939198 100644 --- a/src/Traits/HasBans.php +++ b/src/Traits/HasBans.php @@ -11,9 +11,6 @@ namespace Cog\Ban\Traits; -use Cog\Ban\Contracts\Ban as BanContract; -use Cog\Ban\Contracts\BanService as BanServiceContract; - /** * Class HasBans. * @@ -21,38 +18,7 @@ */ trait HasBans { - use HasBannedAt; - - /** - * Entity Bans. - * - * @return \Illuminate\Database\Eloquent\Relations\MorphMany - */ - public function bans() - { - return $this->morphMany(app(BanContract::class), 'owned_by'); - } - - /** - * Ban model. - * - * @param null|array $attributes - * @return \Cog\Ban\Contracts\Ban - */ - public function ban(array $attributes = []) - { - $ban = app(BanServiceContract::class)->ban($this, $attributes); - - return $ban; - } - - /** - * Remove ban from model. - * - * @return void - */ - public function unban() - { - app(BanServiceContract::class)->unban($this); - } + use HasBannedAtHelpers, + HasBannedAtScope, + HasBansRelation; } diff --git a/src/Traits/HasBansRelation.php b/src/Traits/HasBansRelation.php new file mode 100644 index 0000000..d6e0ce4 --- /dev/null +++ b/src/Traits/HasBansRelation.php @@ -0,0 +1,32 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Cog\Ban\Traits; + +use Cog\Ban\Contracts\Ban as BanContract; + +/** + * Class HasBansRelation. + * + * @package Cog\Ban\Traits + */ +trait HasBansRelation +{ + /** + * Entity Bans. + * + * @return \Illuminate\Database\Eloquent\Relations\MorphMany + */ + public function bans() + { + return $this->morphMany(app(BanContract::class), 'owned_by'); + } +} diff --git a/tests/stubs/Models/UserWithBannedAtScopeApplied.php b/tests/stubs/Models/UserWithBannedAtScopeApplied.php new file mode 100644 index 0000000..54f68fe --- /dev/null +++ b/tests/stubs/Models/UserWithBannedAtScopeApplied.php @@ -0,0 +1,30 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Cog\Ban\Tests\Stubs\Models; + +/** + * Class UserWithBannedAtScopeApplied. + * + * @package Cog\Ban\Tests\Stubs\Models + */ +class UserWithBannedAtScopeApplied extends User +{ + /** + * Determine which BannedAtScope should be applied by default. + * + * @return bool + */ + public function shouldApplyBannedAtScope() + { + return true; + } +} diff --git a/tests/unit/Scopes/BannedAtScopeTest.php b/tests/unit/Scopes/BannedAtScopeTest.php new file mode 100644 index 0000000..fa1e3e1 --- /dev/null +++ b/tests/unit/Scopes/BannedAtScopeTest.php @@ -0,0 +1,100 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Cog\Ban\Tests\Unit\Scopes; + +use Carbon\Carbon; +use Cog\Ban\Tests\Stubs\Models\User; +use Cog\Ban\Tests\Stubs\Models\UserWithBannedAtScopeApplied; +use Cog\Ban\Tests\TestCase; + +/** + * Class BannedAtScopeTest. + * + * @package Cog\Ban\Tests\Unit\Scopes + */ +class BannedAtScopeTest extends TestCase +{ + /** @test */ + public function it_can_get_all_models_by_default() + { + factory(User::class, 2)->create([ + 'banned_at' => Carbon::now()->subDay(), + ]); + + factory(User::class, 3)->create([ + 'banned_at' => null, + ]); + + $entities = User::all(); + $this->assertCount(5, $entities); + } + + /** @test */ + public function it_can_get_models_without_banned() + { + factory(User::class, 2)->create([ + 'banned_at' => Carbon::now()->subDay(), + ]); + factory(User::class, 3)->create([ + 'banned_at' => null, + ]); + + $entities = User::withoutBanned()->get(); + + $this->assertCount(3, $entities); + } + + /** @test */ + public function it_can_get_models_with_banned() + { + factory(User::class, 2)->create([ + 'banned_at' => Carbon::now()->subDay(), + ]); + factory(User::class, 3)->create([ + 'banned_at' => null, + ]); + + $entities = User::withBanned()->get(); + + $this->assertCount(5, $entities); + } + + /** @test */ + public function it_can_get_only_banned_models() + { + factory(User::class, 2)->create([ + 'banned_at' => Carbon::now()->subDay(), + ]); + factory(User::class, 3)->create([ + 'banned_at' => null, + ]); + + $entities = User::onlyBanned()->get(); + + $this->assertCount(2, $entities); + } + + /** @test */ + public function it_can_auto_apply_banned_at_default_scope() + { + factory(User::class, 3)->create([ + 'banned_at' => Carbon::now()->subDay(), + ]); + factory(User::class, 2)->create([ + 'banned_at' => null, + ]); + + $entities = UserWithBannedAtScopeApplied::all(); + + $this->assertCount(2, $entities); + } +}