Quick start
This is the smallest working Warrant setup: one schema, one rule, one resolver,
and the checks that use them. We’ll gate a Document model so a user can only
view and update their own rows.
1. Define a schema
Section titled “1. Define a schema”A schema declares the vocabulary for one resource — the abilities that exist and the conditions a rule may test. It doesn’t decide anything; it just teaches each condition how to emit SQL.
namespace App\Warrant;
use App\Models\Document;use Illuminate\Contracts\Database\Query\Builder;use Warrant\Ability;use Warrant\Schema\Conditions\TargetedConditionContext;use Warrant\Schema\WarrantSchema;use Warrant\TargetedCondition;
class DocumentSchema extends WarrantSchema{ public const model = Document::class;
#[Ability] public const VIEW = 'view'; #[Ability] public const UPDATE = 'update';
// A targeted condition narrows WHICH rows the user matches. // The method name `isSelf` becomes the rule name `is_self`. #[TargetedCondition] public function isSelf(TargetedConditionContext $c): Builder { return $c->query->whereRaw( 'documents.user_id = ?', [$c->user->getAuthIdentifier()], ); }}2. Write a rule
Section titled “2. Write a rule”Rules are plain strings in Warrant’s rule language. This one grants view and update on the user’s own rows:
if is_self they can view, update3. Write a resolver
Section titled “3. Write a resolver”The resolver is the glue between your access model and Warrant. At request time it returns the rules that apply to the current user for a given resource. Warrant ships no default — this small class is required.
namespace App\Warrant;
use Warrant\RuleResolutionContext;use Warrant\RuleResolver;use Warrant\RuleSyntaxTree\WarrantRuleSet;
class DatabaseRuleResolver implements RuleResolver{ public function resolve(RuleResolutionContext $context): WarrantRuleSet { // In a real app you'd look these rules up per user/role/tenant. // Here we return the same rule for everyone, for the documents schema. return WarrantRuleSet::fromSyntax( $context->schemaKey, 'if is_self they can view, update', ); }}4. Wire it up
Section titled “4. Wire it up”Point Warrant at the resolver and register the schema in config/warrant.php:
return [ 'rule_resolver' => App\Warrant\DatabaseRuleResolver::class, 'schemas' => [App\Warrant\DocumentSchema::class],];Add the trait to the model and tell it which schema governs it:
use Illuminate\Database\Eloquent\Model;use Warrant\HasWarrantSchema;
class Document extends Model{ use HasWarrantSchema;
public function warrantSchema(): string { return \App\Warrant\DocumentSchema::class; }}5. Ask the three questions
Section titled “5. Ask the three questions”All three trace back to that one rule:
// "Which documents can the current user update?" — a WHERE clause, paginates.$editable = Document::query()->hasAbility('update')->paginate();
// "What can they do to each row?" — one computed column, one query.$rows = Document::query()->selectAbilities()->get();$rows->first()->abilities; // e.g. ['view', 'update']
// "Can they update this specific one?" — a scoped EXISTS.Document::userHasAbilities('update', $document); // boolThat’s the whole loop. From here:
- Core concepts — how the pieces fit together.
- Schemas — abilities, conditions, and context keys in depth.
- The rule language — the full DSL.
- Checking access — every way to ask a question.
