Skip to content

Actors

Actors decide who may run a transition or complete a task. One matching actor is enough.

->by(Actor::permission('orders.approve'), Actor::role('Purchasing'))
Actor Who
Actor::permission('orders.approve') users and API clients with the permission in the tenant (roles and policies)
Actor::role('Purchasing') users with the role of the tenant (name or UUID)
Actor::user($uuid) one user
Actor::field('requester_id') the user whose internal id is in the field of the record
Actor::creator() the user (or API client) who created the record
Actor::resolver('line-manager') users of a resolver of the application
Actor::sameAs('approve') the actors of another transition (which needs actors of its own)
Actor::slot('approver', default: …) configured per tenant; the default applies until a tenant sets it

Permissions named by permission actors appear in the role editor under the resource. Use them for “everybody in the purchasing department” kinds of rules that roles of the tenant grant.

Actor::field('budget_owner_id') matches the user whose internal id is stored in the field. Let users choose the person with a UserSelect field (active members of the tenant):

UserSelect::make('budget_owner_id')->label('Budget owner')->required(),

The creator is recorded when a record starts its workflow in the panel or through the API (a user or an API client). Records created elsewhere have no creator; Actor::creator() matches nobody there.

Anvil has no organisation model. Relations like “the manager of the requester” come from resolvers of the application. A resolver returns the internal ids of users in the current tenant:

use Anvil\Support\Record;
use Anvil\Workflow\WorkflowContext;
use Anvil\Workflow\WorkflowResolver;
final class LineManager implements WorkflowResolver
{
public function users(array|object $record, WorkflowContext $context): array
{
return array_filter([service('hr')->managerOf((int) Record::get($record, 'requester_id'))]);
}
}

Register it as a building block ($blocks->resolver('line-manager', new LineManager())). Resolvers are asked when a transition is offered or run and when tasks are created; keep them fast. Registered resolvers are offered to tenant administrators as actors of slots.

Actor::sameAs('approve') uses the actors of another transition, e.g. reject by the same people as approve. Nesting is limited to three levels.

Actor::slot('approver', default: Actor::resolver('line-manager'))

A slot is a named place for an actor that each tenant fills in its configuration: the default, a role of the tenant, the creator or a registered resolver. Slot names: lower case letters, digits and -, up to 40 characters. The same slot can be used by several transitions, tasks and deadlines.

  • Running transitions: users match all actors; API clients match permission actors and the creator actor for records they created.
  • Tasks and notifications go to users only; API clients are never candidates.
  • Substitutes with the override permission may run transitions they are not an actor of.