Permissions
Every resource brings its own permissions, named by its slug. They are listed in the role editor (Access → Roles) and checked on every page and every request of the endpoint.
| Permission | Allows |
|---|---|
<slug>.view |
navigation entry, list and detail pages, selects and counts of the records |
<slug>.create |
create page and saving new records |
<slug>.update |
edit page, saving changes, attachments, actions and relation actions by default |
<slug>.delete |
deleting single and selected records |
<slug>.history |
the change history on the detail page |
<slug>.export |
exports, only with $exportable = true |
Resources and pages are denied by default: a role sees nothing until it is
given permissions. Own permissions of actions (e.g. orders.approve) are
listed in the role editor when they are in Config\Anvil::$permissions.
Checks
Section titled “Checks”| Method | Checks | Used for |
|---|---|---|
canViewAny($gate) |
<slug>.view |
navigation, list, global search, selects |
canView($gate, $record) |
<slug>.view with policy |
detail page, list rows, search hits, links |
canCreate($gate) |
<slug>.create |
create button and saving |
canUpdate($gate, $record) |
<slug>.update with policy, not locked by a workflow |
edit page, saving, attachments |
canDelete($gate, $record) |
<slug>.delete with policy, not locked by a workflow |
delete button and deleting |
canViewHistory($gate, $record) |
showsHistory() and <slug>.history with policy |
history section |
canExport($gate) |
$exportable and <slug>.export |
export button |
Override a check for a special rule; call the parent so the permission stays:
public function canDelete(Gate $gate, ?object $record = null): bool{ // Paid invoices are never deleted. return parent::canDelete($gate, $record) && ($record?->paid_at ?? null) === null;}A check that fails on a page answers 403 (“no access”, audit event
access.denied); a button that would fail is not shown.
Policies
Section titled “Policies”Record level rules – “only the owner may edit”, “only open requests” – are policies. They apply to the detail page, saving, deleting, actions, lists, selects, counts and the global search alike: a record a policy hides is not listed anywhere.
Scope instead of permission
Section titled “Scope instead of permission”Rows a user should never see belong into scopeQuery() (see
Loading and saving): they are
not found at all (404), are not counted and cannot be selected. Policies
decide about records that exist for the user but may not be opened or
changed.
Workflows
Section titled “Workflows”With a workflow, records in a locked state cannot be updated
or deleted (isLocked()); only transitions change them. Transitions have
permissions of their own.