Skip to content

Middleware API

Reference for Warrant\WarrantMiddleware. Conceptual coverage is in Route middleware.

The $target throughout is either a schema key (capability / no-model check) or a route parameter name bound to a model (targeted check).

public static function string(
string $target,
string|array $abilities,
AbilityMatchMode $matchMode = AbilityMatchMode::ALL,
): string;

Produces a warrant:... middleware string, e.g. warrant:documents,view. The match-mode segment (any / all) is inserted only when $matchMode isn’t the default ALL:

WarrantMiddleware::string('document', 'view');
// -> "warrant:document,view"
WarrantMiddleware::string('document', ['view', 'approve'], AbilityMatchMode::ANY);
// -> "warrant:document,any,view,approve"
public static function guard(
string $target,
string|array $abilities,
Closure $routes,
AbilityMatchMode $matchMode = AbilityMatchMode::ALL,
): void;
WarrantMiddleware::guard('documents', 'view', function () {
Route::get('/documents', [DocumentController::class, 'index']);
});

Each takes the target and an optional route-group closure. With a closure they guard the group; without one they return the middleware string.

public static function canView(string $target, ?Closure $routes = null): ?string;
public static function canCreate(string $target, ?Closure $routes = null): ?string;
public static function canUpdate(string $target, ?Closure $routes = null): ?string;
public static function canDelete(string $target, ?Closure $routes = null): ?string;
public static function canArchive(string $target, ?Closure $routes = null): ?string;
public static function canManage(string $target, ?Closure $routes = null): ?string;

canViewcanArchive map to the matching StandardAbilities constant. canManage uses the literal ability 'manage', which is not a standard ability — declare it on the schema yourself.

Guards backed by the reachability system — a purely structural check that runs no conditions and no SQL. Each returns the middleware string when called without a $routes closure, or guards the group when given one.

public static function couldEver(
string $target,
string|array $abilities,
?Closure $routes = null,
AbilityMatchMode $matchMode = AbilityMatchMode::ALL,
): ?string; // passes when reachability !== NEVER
public static function always(
string $target,
string|array $abilities,
?Closure $routes = null,
AbilityMatchMode $matchMode = AbilityMatchMode::ALL,
): ?string; // passes when reachability === ALWAYS
public static function never(
string $target,
string|array $abilities,
?Closure $routes = null,
AbilityMatchMode $matchMode = AbilityMatchMode::ALL,
): ?string; // passes when reachability === NEVER

The aliases are warrant.could-ever, warrant.always, and warrant.never, each with an .any variant for AbilityMatchMode::ANY (e.g. warrant.could-ever.any).

These guards are target-free: $target is a schema key or a schema/model class, never a route parameter. The schema is resolved by key only (it throws if the target isn’t a key), and the middleware abort(403)s when the reachability predicate fails. See Reachability.

public function handle(
Request $request,
Closure $next,
string $target,
string $matchModeOrFirstAbility,
string ...$remainingAbilities,
): Response;

At request time it:

  1. Resolves $target as a schema key first.
  2. Failing that, treats it as a route parameter name, resolves it to a model instance, and finds the schema from the model’s class.
  3. Reads the segment after the target: all / any is the match mode; anything else is the first ability.
  4. Calls userHasAbilities and abort(403) if unauthenticated or unauthorized.
Condition Exception
No abilities supplied InvalidArgumentException“requires at least one ability.”
Route parameter isn’t a model instance InvalidArgumentException“must resolve to a model instance.”
Target resolves to no schema InvalidArgumentException“Unable to resolve access control schema for […]”
Unauthenticated / unauthorized HTTP 403