›
›
›
  1. docs
  2. ›
  3. byrcsc/laravel-assignment
1.x
Browse documentationOpenClose

Getting started

  • Introduction
  • Installation and setup
  • Quick start

Core concepts

  • Assignments and slots
  • Assigning and offering
  • Selection policies
  • Scopes and rotation
  • Profiles
  • The queue
  • Offer cascades

Operations

  • Expiry and scheduling
  • Reading assignments
  • Notifications
  • Events and listeners
  • Concurrency guarantees

Reference

  • Configuration
  • API reference
  • Console commands
  • Exceptions
  • Testing
  • Troubleshooting

Getting started

  • Introduction
  • Installation and setup
  • Quick start

Core concepts

  • Assignments and slots
  • Assigning and offering
  • Selection policies
  • Scopes and rotation
  • Profiles
  • The queue
  • Offer cascades

Operations

  • Expiry and scheduling
  • Reading assignments
  • Notifications
  • Events and listeners
  • Concurrency guarantees

Reference

  • Configuration
  • API reference
  • Console commands
  • Exceptions
  • Testing
  • Troubleshooting

byrcsc/laravel-assignment · 1.x

Profiles.

A profile holds the candidates, policy, scope, and mode for one assignable model, so assignment takes no arguments.

The fluent builder needs a candidate list at the call site. That works in a controller. It fails in a queued job, a scheduled command, or the queue flush, because none of them has a chain to build.

A profile is a class that supplies the candidates, policy, scope, and mode for one assignable model. Once you register it, assignment takes no arguments:

$enquiry->autoAssign();
$callout->autoAssign('crew');

Write a profile

candidates() and policy() are required. The other methods have defaults.

use ByRcsc\LaravelAssignment\AssignmentProfile;
use ByRcsc\LaravelAssignment\Policies\RoundRobin;
use Illuminate\Database\Eloquent\Model;

final class EnquiryProfile extends AssignmentProfile
{
    public function candidates(Model $assignable, ?string $role): iterable
    {
        return Tradie::query()->where('available', true)->get();
    }

    public function policy(Model $assignable, ?string $role): string
    {
        return RoundRobin::class;
    }

    public function scope(Model $assignable, ?string $role): ?string
    {
        return 'trade:'.$assignable->trade;
    }
}

candidates() returns any iterable of persisted Eloquent models. policy() returns a class name, a policy instance, or a closure, which is the same set using() accepts.

Every method receives the assignable and the role, so one profile can serve several roles on the same model by branching on $role.

The contract types the assignable as Model. The engine does not know which model a profile was registered for. Narrow it yourself when you need the model's own properties, either with an instanceof check or by accepting the wider type and throwing an exception when the model is wrong.

Register it

// config/assignment.php
'profiles' => [
    App\Models\Enquiry::class => App\Assignment\EnquiryProfile::class,
    App\Models\Callout::class => App\Assignment\CalloutProfile::class,
],

The key is the assignable class, and the value is the profile class name. The container resolves profiles, so a profile can take constructor dependencies.

The package checks the class and then its parents, so a profile registered against a base class serves every subclass that has no profile of its own.

autoAssign() on a model with no registered profile throws NoProfile.

The optional methods

MethodDefaultControls
scope()nullThe rotation scope; null uses the derived one
mode()Mode::AssignWhether to assign outright or offer
offerTtl()nullSeconds an offer stands (at least 1), or null
queueWhenEmpty()trueQueue the assignable when nobody is available
queuePriority()0Its position in the queue, highest first

Offering from a profile

use ByRcsc\LaravelAssignment\Enums\Mode;

public function mode(Model $assignable, ?string $role): Mode
{
    return $role === 'crew' ? Mode::Offer : Mode::Assign;
}

public function offerTtl(Model $assignable, ?string $role): ?int
{
    return 120;
}

Only offers from a profile cascade. An offer created through the fluent builder has no cascade, so it ends when the assignee declines it or it expires. See offer cascades.

Queueing when nobody is available

public function queueWhenEmpty(Model $assignable, ?string $role): bool
{
    return true;
}

public function queuePriority(Model $assignable, ?string $role): int
{
    return $assignable->emergency ? 10 : 0;
}

With queueWhenEmpty() returning true, an autoAssign() that finds no candidates adds the assignable to the queue rather than doing nothing. Return false and autoAssign() returns null and writes nothing. See the queue.

What happens on autoAssign

  1. The package resolves the profile for the assignable's class.
  2. The package reads candidates(), scope(), policy(), and mode().
  3. In offer mode, the package generates a cascade id, so this offer and its successors belong to one cascade.
  4. The selection runs under the scope lock and writes the assignment.
  5. If the selection wrote nothing and queueWhenEmpty() is true, the package queues the assignable at queuePriority().

The return value is the assignment, or null when the policy selected nobody.

Calling it without the trait

The facade runs the same steps. Use it when you do not want to call through the model's trait:

use ByRcsc\LaravelAssignment\Facades\Assignment;

Assignment::autoAssign($enquiry);
Assignment::autoAssign($callout, 'crew');

What it does not do

  • Store profiles in the database. Profiles are classes that you register in config. Your application builds any admin-editable routing rules.
  • Fall back to a default profile. autoAssign() on an unregistered model throws NoProfile.
  • Cache anything. candidates() runs on every call. A queue flush minutes later therefore sees a tradie who has since become available.

What to read next

  • The queue for what happens when nobody is available.
  • Offer cascades for how a declined profile offer moves on.
  • Configuration for the registration key.
PreviousScopes and rotationNextThe queue
View source

On this page

  1. Write a profile
  2. Register it
  3. The optional methods
  4. Offering from a profile
  5. Queueing when nobody is available
  6. What happens on autoAssign
  7. Calling it without the trait
  8. What it does not do
  9. What to read next