DI and actions
There are three equivalent entry points, and you choose. The facade is the shortest and the recommended default. The manager — RoundlyConsulting\Permissions\PermissionsManager, the facade root — has the same API as an explicit constructor dependency with no static calls. Actions are single-purpose classes with an execute() method, for composing into your own actions, jobs and commands.
Inject the manager
use RoundlyConsulting\Permissions\PermissionsManager;
final class OnboardEditor
{
public function __construct(private PermissionsManager $permissions) {}
public function handle(User $user): void
{
$this->permissions->for($user)->assignRole($this->permissions->role('editor'));
}
}Permissions::fake() binds the fake into the container as well, so a manager injected after the fake is created is the fake — its writes are recorded like facade calls.
Call an action
Every catalog and grant write resolves one action from the container, so a container override of an action applies to the facade, the manager and the traits alike. All actions live in RoundlyConsulting\Permissions\Actions:
use RoundlyConsulting\Permissions\Actions\GrantRoles;
use RoundlyConsulting\Permissions\Actions\SyncFromEnum;
use RoundlyConsulting\Permissions\Enums\GrantMode;
use RoundlyConsulting\Permissions\Facades\Permissions;
app(GrantRoles::class)->execute($user, ['editor'], GrantMode::Additive);
app(SyncFromEnum::class)->execute(PostPermission::class, Permissions::permissionModel());Facade method → action
| Facade method | Action | execute() |
|---|---|---|
role() | FindOrCreateRole | (string|BackedEnum $name): Role |
permission() | FindOrCreatePermission | (string|BackedEnum $name): Permission |
for()->assignRole() / syncRoles() | GrantRoles | (Model $holder, iterable $roles, GrantMode $mode): void |
for()->removeRole() | RemoveRoles | (Model $holder, iterable $roles): void |
for()->givePermissionTo() / syncPermissions() | GrantPermissions | (Model $holder, iterable $permissions, GrantMode $mode): void |
for()->revokePermissionTo() | RevokePermissions | (Model $holder, iterable $permissions): void |
for()->forgetAllAuthorization() | ForgetAuthorization | (Model $holder): void |
syncFrom() / syncRolesFrom() | SyncFromEnum | (string $enum, string $model): SyncResult |
pruneOrphans() | PruneOrphans | (): int |
GrantMode::Additive never detaches existing grants; GrantMode::Authoritative makes the given set the complete set. SyncFromEnum takes the model class to create rows as — pass Permissions::permissionModel() or Permissions::roleModel() — and returns a SyncResult with created, existing and changed(). Calling an action directly bypasses the manager, so the fake does not record it.
Config resolvers
The static resolvers on RoundlyConsulting\Permissions\Support\PermissionRegistrar — rolesTable(), permissionsTable(), permissionRoleTable(), modelRolesTable(), modelPermissionsTable(), keyType(), roleModel() and permissionModel() — are public too: the published migrations call them, and so can your own migrations or raw queries. See Custom models & tables.
Show your open-source love
This package is free and MIT-licensed. If it saves you time, a one-off donation or a Patreon membership keeps it maintained, tested and documented.
More ways to support, including cryptoBy donating, you agree to our donation terms.
Want this built into your product?
We integrate our packages into custom Laravel and AI builds. Tell us what you're working on and we'll reply within 48 hours.