cybercog/laravel-ban
Add ban management to any Laravel Eloquent model. Supports multiple bans per model with soft-deleted history, BanService helpers, query scopes, ban/unban events, middleware to block access for banned users, scheduling, and integrations like Nova.
composer require cybercog/laravel-ban.php artisan vendor:publish --provider="Cog\Laravel\Ban\Providers\BanServiceProvider" --tag="migrations" followed by php artisan migrate.Cog\Contracts\Ban\Bannable as BannableInterface and using the Cog\Laravel\Ban\Traits\Bannable trait.banned_at column to your bannable model’s table (e.g., users) if it doesn’t exist yet — use nullable() timestamp.$user->ban(['comment' => 'Terms violation']);
$user->unban();
$user->isBanned(); // bool
The first use case is typically banning users: prevent access to features or hide them from listings with User::withoutBanned()->get().
Route Protection:
Use ForbidBannedUser middleware on sensitive routes (e.g., /dashboard, /profile) to block banned models. For logout on ban, use LogsOutBannedUser. Register in app/Http/Kernel.php and apply to routes/groups.
Route::middleware('forbid-banned-user')->group(function () {
Route::get('/account', [AccountController::class, 'show']);
});
Admin Interfaces:
Leverage withBanned(), onlyBanned(), and withoutBanned() scopes to build admin dashboards that show banned/unbanned models. Combine with soft-deleted Bans history for auditing.
Temporary Bans & Scheduling:
Schedule ban:delete-expired command to auto-unban expired bans (e.g., everyMinute() in Kernel). Set expired_at at ban time:
$user->ban(['expired_at' => now()->addDay()]);
Custom Ban Reasoning:
Store context (e.g., comment, admin_id) in ban records:
$user->ban([
'comment' => 'Spamming chat',
'admin_id' => auth()->id(),
]);
Automated Filtering:
Override shouldApplyBannedAtScope() in your model to globally exclude banned records from queries unless explicitly requested (withBanned()).
Events for Auditing:
Listen to ModelWasBanned/ModelWasUnbanned for notifications (Slack, email) or audit logging.
Missing banned_at column:
Ban/unban operations will still function, but scope filtering (e.g., withoutBanned()) won’t work efficiently. Always ensure the column exists.
Soft-deleted Bans records:
Removed bans are not deleted — only soft-deleted. Use Ban::withTrashed() to view history or audit logs.
Polymorphic relationships:
The bans table uses bannable_type/bannable_id. Verify your model’s MorphTo type resolution in tests if using abstract models (e.g., Interface → Class mapping).
Middleware and cached responses:
If using HTTP caching or full-page caching, ensure banned users aren’t served cached pages. Use HTTP headers or bypass cache for authenticated requests.
Banning non-User models:
Works just as well for Teams, Organizations, etc. — ensure your Eloquent model implements the interface and has banned_at. Update bannable_type in tests by using MorphMap::alias() if needed.
Event handlers run after ban is persisted:
Use ModelWasBanned data for logging or side effects, but avoid modifying the model inside the listener (risk of recursion).
Laravel 13 compatibility:
This is confirmed in v4.11.0 — ensure you’re on at least PHP 8.2 (Laravel 13 requirement), as legacy PHP versions dropped in v4.8.
Testing gotcha:
When unit-testing bannable models, use refresh() on models after ban()/unban() to reload banned_at state; trait modifies the model but doesn’t auto-refresh banned_at in memory.
How can I help you explore Laravel packages today?