›
byrcsc/laravel-assignment · 1.x
A slot is one assignable and one role, and the database allows one open assignment in it.
An assignment binds one assignee to one assignable, optionally under a role. The main rule is that a slot holds at most one open assignment. The database enforces that rule.
An assignment is open when it is active, or when it is offered and its
expires_at has not passed.
| Status | Open? |
|---|---|
offered | Yes, until expires_at passes |
active | Yes |
ended | No |
An offer occupies its slot while it is open. The purpose of an offer is to stop anyone else from getting the work while the assignee decides whether to take it.
$assignment->isOpen(); // active, or offered and not past expiry
$assignment->isActive();
$assignment->isOffered();
$assignment->isEnded();
$assignment->isExpired(); // offered, has an expires_at, and it has passedLeave the role off and an assignable has one slot:
$enquiry->assign($tradie);
$enquiry->assignee(); // the TradiePass a role and each role is its own slot, so one callout holds two assignees at once:
$callout->assign($crew, role: 'crew');
$callout->assign($tradie, role: 'supervisor');
$callout->assignee('crew'); // the Crew
$callout->assignee('supervisor'); // the TradieEvery reader takes the same optional role. The slot with no role is a distinct
slot, not a wildcard. $callout->assignee() with no argument reads the slot
with no role. In the example above, that slot is empty.
Roles are free-form strings. The package keeps no list of the ones you use.
The one rule is that a role cannot be an empty string. Pass null for the slot
with no role, because '' throws InvalidArgumentException on every write
and every read.
The assignments table carries an internal slot column. While a row is open,
slot holds the role, or an empty string when there is no role. When the row
ends, slot becomes null. A unique index covers the assignable type, the
assignable id, and slot.
A unique index allows any number of null values, so ended rows never collide.
Two open rows for the same slot cannot both exist. When two concurrent callers
try to fill one slot, one gets the assignment and the other gets a
SlotOccupied exception. The behaviour is the same on MySQL, PostgreSQL, and
SQLite.
slot is internal. The model hides it from array and JSON output, and nothing
in the public API takes or returns it.
The package ends assignments and never deletes them. An ended row records when and why:
ended_reason | Written when |
|---|---|
unassigned | unassign() ended an active assignment |
reassigned | reassign() replaced this row with another |
declined | The assignee declined an offer |
expired | An offer passed its expires_at |
completed | complete() ended the work as finished |
Every row also carries offered_at, accepted_at, expires_at, ended_at,
and a polymorphic assigned_by. A null assigned_by means the engine created
the row rather than an actor you named.
$callout->assignments()->ended()->get(); // past holders, oldest firstThere is no separate transition table. A row records one holder from start to end. The sequence of rows records the assignable's full history.
The rows are a record, not an audit trail. They are ordinary Eloquent models with no append-only enforcement. Anything that can write to the database can change
ended_atorexpires_at. If you need attributable, tamper-evident history, listen to the events and write it yourself.