1. Go to this page and download the library: Download elpandape/bouncer library. Choose the download type require.
2. Extract the ZIP file and open the index.php.
3. Add this code to the index.php.
<?php
require_once('vendor/autoload.php');
/* Start to develop here. Best regards https://php-download.com/ */
elpandape / bouncer example snippets
use ElPandaPe\Bouncer\Concerns\HasRolesAndPermissions;
class User extends Authenticatable
{
use HasRolesAndPermissions;
}
Bouncer::allow($user)->to('edit', Post::class); // grant, at any granularity
Bouncer::forbid($user)->to('edit', $secretPost); // an explicit denial always wins
Bouncer::assign('editor')->on($org)->to($user); // a role, scoped to one model
$user->can('edit', $post); // it is Laravel's Gate
Post::whereCan($user, 'edit')->paginate(); // which rows, as a query scope
Bouncer::explain($user, 'edit', $post); // why, row by row
$user->can('edit-site'); // simple permission
$user->can('edit', $post); // one instance
$user->can('edit', Post::class); // the whole class
Gate::authorize('edit', $post); // throws on deny
@can('edit', $post) ... @endcan // Blade, as always
use ElPandaPe\Bouncer\Facades\Bouncer;
Bouncer::allow($user)->to('ban-users'); // simple permission
Bouncer::allow($user)->to('edit', Post::class); // every post
Bouncer::allow($user)->to('edit', $post); // one post
Bouncer::allow($user)->everything(); // wildcard
Bouncer::allow($user)->toOwn(Post::class); // only what they own
Bouncer::allowEveryone()->to('browse'); // everyone
Bouncer::assign('admin')->to($user); // roles, created on the fly
Bouncer::allow('admin')->to('audit'); // grant to a role by name
Bouncer::sync($user)->roles(['editor', 'writer']); // declarative sync
Bouncer::allow($user)->toOwn(Post::class); // any action on owned posts
Bouncer::allow($user)->toOwn(Post::class, ['edit']); // only these actions
Bouncer::allow($user)->toOwnEverything();
Bouncer::ownedVia('author_id'); // global attribute
Bouncer::ownedVia(Post::class, 'writer_id'); // per class
Bouncer::ownedVia(fn ($post, $user) => $post->team_id === $user->team_id);
Bouncer::allow($user)->toOwn(Post::class);
Bouncer::forbid($user)->toOwn(Post::class, 'delete'); // owners still can't delete
Bouncer::assign('editor')->on($orgOne)->to($user); // editor only inside orgOne
Bouncer::assign('editor')->on($orgTwo)->to($user); // same role, second context
Bouncer::retract('editor')->on($orgOne)->from($user); // leave one; without on(), all
Bouncer::restrictedVia(Post::class, 'organization_id'); // membership by FK
Bouncer::restrictedVia(fn ($entity, $context) => ...); // or a closure
Bouncer::assign('admin')->on($project)->to($user);
$user->can('manage', $project); // true: the entity IS the context
$user->can('edit', $taskInProject); // true: task->project_id points at it
Bouncer::tenant()->to($tenantId); // everything now scoped to this tenant
Bouncer::tenant()->onceTo(9, fn () => ...); // temporary, exception-safe
Bouncer::tenant()->onlyRelations(); // keep the permission catalog global
Bouncer::tenant()->dontScopeRoleGrants();
use ElPandaPe\Bouncer\Concerns\QueriesByPermission;
Post::whereCan($user, 'view')->latest()->paginate();
$why = Bouncer::explain($user, 'edit', $post);
$why->allowed(); // bool
$why->cause; // Cause::ForbiddenViaRole, Cause::GrantedDirectly, …
$why->permission; // the decisive catalog row
$why->role; // the role that carried it, when one did
(string) $why; // "Explicitly forbidden by permission [edit] via role [banned]."
Event::listen(PermissionGranted::class, function (PermissionGranted $event) {
audit('granted', $event->authority, $event->permissions->pluck('name'));
});
// config/bouncer.php — a real store with a TTL:
'cache' => [
'enabled' => true,
'store' => 'default',
'prefix' => 'bouncer',
'expiration_time' => DateInterval::createFromDateString('24 hours'),
],
Bouncer::refresh(); // invalidate everything: an O(1) version bump
Bouncer::refreshFor($user); // drop one authority's payload
Bouncer::disallow($user)->to('publish'); // the next check is already correct
// Script verdicts without touching tables; unscripted checks fall to your policies.
$fake = Bouncer::fake();
$fake->allow('edit-site')->forbid('delete');
$fake->assertChecked('edit-site');
$fake->assertGranted('edit-site');
$fake->assertForbidden('delete');
$fake->assertNothingChecked();
// Or arrange real rows tersely with the trait:
use ElPandaPe\Bouncer\Testing\WithPermissions;
$this->allowUser($user, 'view', Document::class);
$this->assignRoles($user, 'admin');
Route::get('/admin', ...)->middleware('bouncer.role:admin,editor'); // any of
Route::put('/site', ...)->middleware('bouncer.permission:edit-site'); // all of
use ElPandaPe\Bouncer\Concerns\HasRolesAndPermissions;
class User extends Authenticatable
{
use HasRolesAndPermissions;
}
// ✅ Do — point the config at your model, keep the concern:
// config/bouncer.php
'models' => ['role' => App\Models\Role::class],
// app/Models/Role.php
class Role extends Model
{
use ElPandaPe\Bouncer\Models\Concerns\IsRole;
}
// ❌ Don't — don't hardcode package classes in relations or checks;
// resolve them via config so swapped models keep working everywhere.
$user->roles()->attach(ElPandaPe\Bouncer\Models\Role::first());
Gate::forUser($tenantUser)->allows('edit', $post);
Bouncer::explain($tenantUser, 'edit', $post); // diagnosis takes any authority
// In your User model or an observer:
protected static function booted(): void
{
static::created(fn (User $user) => Bouncer::assign('member')->to($user));
}