›
byrcsc/laravel-hold · 1.x
Acquire, extend, release, and expire a hold on an Eloquent model.
This walkthrough reserves one Seat for one User. It assumes Laravel Hold is
installed and migrated.
Add Holdable to the resource:
use ByRcsc\LaravelHold\Concerns\Holdable;
class Seat extends Model
{
use Holdable;
}Add HasHolds to the holder when you want to read holds from that side:
use ByRcsc\LaravelHold\Concerns\HasHolds;
class User extends Authenticatable
{
use HasHolds;
}A Seat has one slot by default, so only one active hold can occupy it.
$hold = $seat->acquireHold(
$user,
expiresAt: now()->addMinutes(15),
metadata: ['reason' => 'checkout'],
);The method returns the new hold when a slot is available:
$seat->availableSlots(); // 0
$seat->isFullyHeld(); // true
$seat->activeHoldFor($user); // the new holdAnother holder cannot take the occupied slot:
$seat->acquireHold($otherUser); // nullUse acquireHoldOrFail() when refusal should throw
NoAvailableSlotsException instead of returning null.
use Carbon\CarbonInterval;
$hold->extend(CarbonInterval::minutes(5));The interval is added to the current expires_at value. Extending a 15-minute
hold by five minutes gives it a 20-minute window from acquisition.
Released, expired, and indefinite holds cannot be extended.
$hold->release(
by: $supportUser,
metadata: ['reason' => 'checkout cancelled'],
);Release records the time, optional actor, and metadata. The hold remains in the table as history, but no longer consumes capacity:
$hold->status; // HoldStatus::Released
$seat->fresh()->availableSlots(); // 1Calling release() again changes nothing.
$brief = $seat->acquireHold(
$user,
expiresAt: now()->addSeconds(2),
);
$brief->status; // HoldStatus::Active
$seat->availableSlots(); // 0
sleep(3);
$brief->status; // HoldStatus::Expired
$seat->availableSlots(); // 1No command frees the slot. Availability checks compare expires_at with the
current time. The optional hold:expire command records that the expiry was
announced and dispatches HoldExpired.