›
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 rule that shapes everything else is that a slot holds at most one open assignment, and the database is what enforces it.
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 holds its slot while it stands. That is the point of offering: nobody else can be given the work while somebody is deciding 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, and the role-less slot is a distinct
slot rather than a wildcard. $callout->assignee() with no argument reads the
slot with no role, which in the example above is empty.
Roles are free-form strings. The package neither validates them nor keeps a list of the ones you use.
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.
Null values repeat freely in a unique index, so ended rows never collide, and
two open rows for the same slot cannot both exist. Two concurrent callers
racing for one slot end with one assignment and one SlotOccupied exception,
on MySQL, PostgreSQL, and SQLite alike.
slot is internal. It is hidden from the model's array and JSON output, and
nothing in the public API takes or returns it.
Assignments end, they are not deleted. 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 is one holder's whole story, and the sequence of rows is the assignable's.
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.