Status lifecycle
Status is a guarded state machine. Legal transitions persist and fire AppointmentStatusChanged; illegal ones throw InvalidStatusTransitionException; moving to the current status is a silent no-op:
use RoundlyConsulting\Appointments\Enums\Status;
use RoundlyConsulting\Appointments\Facades\Appointments;
Appointments::for($appointment)->confirm(); // pending → confirmed
Appointments::for($appointment)->cancel(); // pending/confirmed → cancelled
Appointments::for($appointment)->complete(); // confirmed → completed
Appointments::for($appointment)->decline(); // pending → declined
Appointments::for($appointment)->markNoShow(); // confirmed → no_show
Appointments::for($appointment)->transition(Status::Confirmed); // the generic form
// the same shortcuts on the model — they go through the facade's manager too
$appointment->confirm();
$appointment->transitionTo(Status::Confirmed);Allowed transitions
| Status | Value | Colour | Can move to |
|---|---|---|---|
Status::Pending | pending | amber | confirmed, declined, cancelled |
Status::Confirmed | confirmed | blue | completed, cancelled, no_show |
Status::Cancelled | cancelled | gray | — (final) |
Status::Completed | completed | green | — (final) |
Status::Declined | declined | red | — (final) |
Status::NoShow | no_show | orange | — (final) |
The handle’s shortcuts and the model’s confirm(), cancel(), complete(), decline(), markNoShow() and transitionTo() all end in Appointments::for($appointment)->transition() on the manager, which runs TransitionAppointmentAction — so Appointments::fake() records them wherever they are called.
Inspecting the machine
Ask the enum what’s possible — handy for showing only the buttons that make sense:
use RoundlyConsulting\Appointments\Enums\Status;
$appointment->status; // Status enum (cast)
$appointment->status->transitions(); // e.g. [Status::Completed, Status::Cancelled, Status::NoShow]
$appointment->status->canTransitionTo(Status::Pending); // false
$appointment->status->isFinal(); // true for cancelled, completed, declined, no_show
Status::default(); // Status::PendingHandling illegal moves
use RoundlyConsulting\Appointments\Exceptions\InvalidStatusTransitionException;
try {
$appointment->complete(); // still pending
} catch (InvalidStatusTransitionException $e) {
$e->from; // Status::Pending
$e->to; // Status::Completed
$e->getMessage(); // Cannot transition appointment status from "pending" to "completed".
}Labels, colours and options
Status, ParticipantRole and Frequency carry the enums-for-laravel Helpers trait, so they come ready for UI and validation. color() is specific to Status:
use RoundlyConsulting\Appointments\Enums\Status;
$appointment->status->label(); // "Confirmed" (from the enums Helpers trait)
$appointment->status->color(); // a colour token for UI badges, e.g. "blue"
Status::values(); // Collection: 'pending', 'confirmed', …
Status::labels(); // Collection: "Pending", "Confirmed", …
Status::options(); // value/label/name option DTOs for a <select>
Status::validationRule(); // "in:pending,confirmed,cancelled,completed,declined,no_show"label() passes the headlined value through Laravel’s __() — Pending, Confirmed, No Show — so you translate labels with a JSON translation file such as lang/sk.json:
{
"Pending": "Čaká na potvrdenie",
"Confirmed": "Potvrdený",
"No Show": "Neprítomnosť"
}Show your open-source love
This package is free and MIT-licensed. If it saves you time, a one-off donation or a Patreon membership keeps it maintained, tested and documented.
More ways to support, including cryptoBy donating, you agree to our donation terms.
Want this built into your product?
We integrate our packages into custom Laravel and AI builds. Tell us what you're working on and we'll reply within 48 hours.