Download the PHP package fazzinipierluigi/just-a-gate without Composer
On this page you can find all versions of the php package fazzinipierluigi/just-a-gate. It is possible to download/install these versions without Composer. Possible dependencies are resolved automatically.
Download fazzinipierluigi/just-a-gate
More information about fazzinipierluigi/just-a-gate
Files in fazzinipierluigi/just-a-gate
Package just-a-gate
Short Description A package that introduces a simple but very flexible and powerful ACL
License MIT
Homepage https://github.com/fazzinipierluigi/just-a-gate
Informations about the package just-a-gate
Just A Gate
A simple, flexible, and powerful ACL (Access Control List) system for Laravel 10/11/12.
Roles are assigned to users. Permissions are assigned to roles. A middleware auto-checks permissions based on the route's controller action. A fluent PHP API and a Facade cover every operation without writing SQL.
Table of Contents
- Requirements
- Installation
- Configuration
- Database Schema
- Quick Start
- Artisan Commands
- Protecting Routes — Middleware
- Authorizable Trait
- Role Model
- Permission Model
- JustAGate Facade
- Blade Directives
- Livewire Integration
- Testing
- Security
- License
Requirements
| Dependency | Version |
|---|---|
| PHP | ^8.1 |
| Laravel | ^10.0 \| ^11.0 \| ^12.0 \| ^13.0 |
illuminate/support |
^10.0 \| ^11.0 \| ^12.0 \| ^13.0 |
laravel/prompts |
^0.3 |
Note on PHP version — Laravel 10/11/12 require PHP 8.1/8.2; Laravel 13 requires PHP 8.3. The package runtime is compatible with PHP 8.1+. Your actual minimum PHP version is determined by the Laravel version you install.
Installation
1. Require the package
2. Add the Authorizable trait to your User model
Note — The trait overrides Laravel's built-in
can()/cannot()methods and replaces Gate/Policy resolution with a lightweight DB-backed permission check. Do not use this package alongside Laravel Policies on the same User model.
3. Publish the configuration file
This creates config/acl.php in your application.
4. Initialize the package
This command:
- Runs the four package migrations (creates
roles,permissions,permission_role,role_usertables). - Creates the built-in Administrator role (
slug: admin,is_admin: true,is_system: true).
Configuration
File: config/acl.php
Database Schema
Tables
Relationships
- A user can have many roles.
- A role can have many permissions.
- A role can belong to many users.
- A permission can belong to many roles.
Quick Start
Artisan Commands
permission:init
Initializes the package on first use.
- Runs pending package migrations.
- Creates the
adminrole if it does not exist.
permission:create
Creates a single permission.
| Argument | Type | Required | Description |
|---|---|---|---|
key |
string | No | Dot-notation key, e.g. post.index. Interactive prompt if omitted. |
name |
string | No | Human-readable display name. |
Exit codes: 0 = success, 1 = key already exists.
permission:assign
Assigns a permission to a role.
| Argument | Type | Required | Description |
|---|---|---|---|
key |
string | No | Permission key. Interactive select if omitted. |
role |
string | No | Role slug. Interactive select if omitted. |
Exit codes: 0 = success, 1 = not found or already assigned.
permission:import
Bulk-imports permissions from routes, config, and roles. Intended to be run after deploying route or config changes.
What it does (in order):
- Creates permissions from
config('acl.additional'). - Scans all routes protected by the
aclmiddleware and creates one permission per route using the key derivation formula. - If
config('acl.role_user_creation')istrue, createsuser.create.role_{slug}for every existing role. - If
config('acl.clean_permission')istrue, deletes permissions that are no longer present in steps 1–3. - Applies name translations from
config('acl.translate'). - Auto-assigns permissions to roles from
config('acl.assign').
Protecting Routes — Middleware
Applying the middleware
The middleware alias defaults to 'acl'. Override it in config/acl.php under 'middleware'.
Permission key derivation
The middleware (and permission:import) derives the required permission key from the route's controller action using this algorithm:
| Controller action | Derived permission key |
|---|---|
PostController@index |
post.index |
PostController@store |
post.store |
PostController@destroy |
post.destroy |
UserController@show |
user.show |
Unauthenticated users
Warning — The middleware does not redirect unauthenticated users. It calls
Auth::user()->can(...), which will throw aTypeErrorif no user is authenticated. Always placeauthmiddleware beforeaclon any route that requires authentication.
Authorizable Trait
Namespace: Fazzinipierluigi\JustAGate\Traits\Authorizable
Add this trait to any Eloquent model that represents an authenticated user.
Properties (internal cache)
| Property | Type | Description |
|---|---|---|
$justgate_authorizations |
?array |
Per-instance cache of resolved permission keys. null = not yet loaded. |
$just_gate_is_admin |
bool |
Per-instance flag set when the user holds an is_admin role. |
Cache is instance-scoped — two User instances never share state.
roles()
Eloquent relationship returning all roles assigned to the user.
can(string $ability, mixed $arguments = []): bool
Returns true if the user holds a permission with the given key, or if the user has an is_admin role.
Caching: on first call, all permissions for all roles are loaded and stored in the instance. Subsequent calls are in-memory only with no DB queries.
Admin shortcut: if any of the user's roles has is_admin = true, can() returns true immediately for any ability, and the admin flag is cached so no further DB lookups occur.
cannot(string $ability, mixed $arguments = []): bool
Inverse of can().
clearPermissionCache(): void
Resets the instance-level permission cache and unloads the roles Eloquent relation.
Call this after changing a user's roles programmatically within the same request.
assignRole(Role|string|int ...$roles): static
Attaches one or more roles to the user. Accepts Role instances, slug strings, or IDs. Idempotent (duplicate assignments are ignored). Clears the permission cache automatically. Returns $this for chaining.
removeRole(Role|string|int ...$roles): static
Detaches one or more roles from the user. Clears the permission cache automatically. Returns $this for chaining.
syncRoles(array $roles): static
Replaces all of the user's roles with the given set. Pass an empty array to remove all roles. Clears the permission cache automatically. Returns $this for chaining.
hasRole(Role|string $role): bool
Returns true if the user has the specified role. Accepts a Role instance or a slug string.
hasAnyRole(Role|string ...$roles): bool
Returns true if the user has at least one of the given roles.
hasAllRoles(Role|string ...$roles): bool
Returns true if the user has every given role. Returns false for an empty argument list.
getRoles(): Collection
Returns the Collection of Role models currently assigned to the user (uses Eloquent relation cache).
Role Model
Namespace: Fazzinipierluigi\JustAGate\Models\Role
Table: roles
Properties
| Property | Type | Default | Description |
|---|---|---|---|
id |
int |
— | Auto-increment primary key |
name |
string |
— | Human-readable label, e.g. "Editor" |
slug |
string |
— | Unique code identifier used in all API calls, e.g. "editor" |
is_admin |
bool |
false |
When true, users with this role pass every can() check |
is_system |
bool |
false |
Marks built-in roles (informational; no automatic behavior) |
is_admin and is_system are cast to bool automatically.
Creating roles
permissions()
Eloquent relationship returning all permissions assigned to this role.
users()
Eloquent relationship returning all users that have this role.
givePermission(Permission|string ...$permissions): static
Attaches one or more permissions to the role. Accepts Permission instances or key strings. Idempotent. Unsets the permissions relation cache. Returns $this for chaining.
revokePermission(Permission|string ...$permissions): static
Detaches one or more permissions from the role. Returns $this for chaining.
syncPermissions(array $permissions): static
Replaces all of the role's permissions with the given set. Returns $this for chaining.
hasPermission(string $key): bool
Returns true if this role has the permission identified by $key.
Method chaining example
Permission Model
Namespace: Fazzinipierluigi\JustAGate\Models\Permission
Table: permissions
Properties
| Property | Type | Default | Description |
|---|---|---|---|
id |
int |
— | Auto-increment primary key |
key |
string |
— | Dot-notation identifier, always lowercase, e.g. "post.index" |
name |
string\|null |
null |
Human-readable label |
description |
string\|null |
null |
Extended description |
Creating permissions
findByKey(mixed $key): ?Permission (static)
Returns the Permission with the given key, or null if not found or if $key is not a non-empty string.
roles()
Eloquent relationship returning all roles that have this permission assigned.
JustAGate Facade
Facade class: Fazzinipierluigi\JustAGate\Facades\JustAGate
Alias: JustAGate (registered automatically via Laravel's package auto-discovery)
Service class: Fazzinipierluigi\JustAGate\JustAGate (bound as singleton 'just_a_gate')
The Facade provides a central, static-style API for every ACL operation without needing to inject models or use the trait directly.
Role management
createRole(string $name, string $slug, bool $isAdmin = false, bool $isSystem = false): Role
findRole(string $slug): ?Role
allRoles(): Collection
deleteRole(Role|string $role): bool
Permission management
createPermission(string $key, ?string $name = null, ?string $description = null): Permission
Lowercases $key automatically.
findPermission(string $key): ?Permission
allPermissions(): Collection
deletePermission(Permission|string $permission): bool
User ↔ Role
assignRole(Model $user, Role|string ...$roles): void
removeRole(Model $user, Role|string ...$roles): void
syncRoles(Model $user, array $roles): void
Role ↔ Permission
givePermission(Role|string $role, Permission|string ...$permissions): void
revokePermission(Role|string $role, Permission|string ...$permissions): void
syncPermissions(Role|string $role, array $permissions): void
Checks
userCan(Model $user, string $ability): bool
userHasRole(Model $user, Role|string $role): bool
roleHasPermission(Role|string $role, string $key): bool
Discovery
usersWithRole(Role|string $role): Collection
Returns all users that have the given role.
rolesForPermission(Permission|string $permission): Collection
Returns all roles that have the given permission assigned.
Blade Directives
The package registers a @can / @endcan Blade directive backed by the package's permission system.
Note — The directive calls
Auth::user()->can($ability). If no user is authenticated, it will throw aTypeError. Guard the view with@authwhen the user may not be logged in.
Livewire Integration
Livewire 3 routes all component updates through a single /livewire/update endpoint, making route-based ACL middleware ineffective. Just A Gate solves this with the #[RequiresPermission] PHP attribute and a Livewire 3 ComponentHook that enforces it automatically.
How it works
- The hook is registered automatically when
livewire/livewireis installed — no extra configuration needed. - Class-level
#[RequiresPermission]→ checked on every lifecycle (initial mount + all subsequent AJAX updates). - Method-level
#[RequiresPermission]→ checked only when that specific Livewire action is dispatched. - Returns
HTTP 403when the user is unauthenticated or lacks the required permission.
Setup
No additional setup is required. Install Livewire and the hook self-registers:
Class-level permission (protect the entire component)
The user must hold the specified permission to mount and interact with the component at all.
Method-level permission (protect individual actions)
The component is publicly visible, but specific actions require extra permissions.
Combining class-level and method-level
Both checks apply independently. A user must pass the class check on every request, and the method check when calling a specific action.
Full-page Livewire components (routed components)
For components mounted via a route, you can combine both the route middleware and the attribute for defense in depth:
The acl middleware checks on initial HTTP load. The #[RequiresPermission] attribute re-checks on every Livewire AJAX update. This prevents a user whose role changes mid-session from continuing to interact with the component.
Attribute reference
Namespace: Fazzinipierluigi\JustAGate\Attributes\RequiresPermission
| Target | Behavior |
|---|---|
TARGET_CLASS |
Checked on every Livewire lifecycle (mount + updates) via boot() |
TARGET_METHOD |
Checked only when the attributed method is dispatched via call() |
Hook reference
Class: Fazzinipierluigi\JustAGate\Livewire\AclComponentHook
Extends: Livewire\ComponentHook
Registered: automatically via JustAGateServiceProvider when class_exists(\Livewire\Livewire::class)
| Hook | Trigger | What it checks |
|---|---|---|
boot() |
Every Livewire request for this component | #[RequiresPermission] on the class |
call() |
Before a Livewire action method executes | #[RequiresPermission] on the method |
Testing
The test suite uses an in-memory SQLite database and covers:
Authorizabletrait:can(),cannot(), caching, static isolation, all role-management methods.AclCheckmiddleware: authenticated/unauthenticated requests, permission pass-through, admin bypass.Rolemodel: CRUD,givePermission,revokePermission,syncPermissions,hasPermission, cascading deletes.Permissionmodel: CRUD,findByKey, inverseroles()relationship, cascading deletes.JustAGateFacade: all 18 methods, Facade resolution.
Security
If you discover a security-related issue please email [email protected] rather than using the public issue tracker.
Credits
- Pierluigi Fazzini
- All Contributors
License
MIT. See LICENSE for details.
All versions of just-a-gate with dependencies
illuminate/support Version ^10.0|^11.0|^12.0|^13.0
laravel/prompts Version ^0.3