laravel-enso / lockable-models
Lockable models dependency for Laravel Enso
Requires
- php: ^8.3
- laravel-enso/core: ^12.0
- laravel-enso/helpers: ^12.0
- laravel-enso/migrator: ^2.0
- laravel-enso/users: ^2.0
- laravel/framework: ^13.0
README
Description
Lockable Models provides short-lived edit locks for Eloquent models.
It is meant for collaborative backoffice flows where a record should be protected from concurrent edits while a user is working on it. The package offers a base lockable model, a base lock model, middleware that prevents actions on already locked models, and a terminate middleware that releases successful edit locks automatically.
Locks are user-aware, expire automatically after a configurable number of minutes, and allow the locking user to continue working on the same record while blocking everyone else.
The package depends on laravel-enso/users for lock ownership and display identity. It does not depend on people directly; the lock message uses the user model's public display API.
Installation
Install the package:
composer require laravel-enso/lockable-models
If needed, publish the config:
php artisan vendor:publish --tag=lockable-models-config
Default configuration:
return [ 'lock_duration' => 5, ];
To use the package, your implementation typically needs:
- a model extending
LockableModel - a related lock model extending
ModelLock - a one-to-one table for storing the current lock
- the request middleware pair on routes that edit the model
Features
- Creates user-specific temporary locks for editable models.
- Prevents concurrent actions when another user holds a non-expired lock.
- Allows the same user to continue editing an already locked model.
- Automatically expires stale locks after the configured duration.
- Releases locks automatically after successful requests.
- Provides reusable abstract models for both the lockable record and the lock record.
Usage
Create a lockable model by extending the base class:
use LaravelEnso\LockableModels\Models\LockableModel; class Order extends LockableModel { }
Create a related lock model:
use LaravelEnso\LockableModels\Models\ModelLock; class OrderLock extends ModelLock { }
Protect editing routes with the middleware pair:
Route::middleware([ PreventActionOnLockedModels::class, UnlocksModelOnTerminate::class, ])->group(function () { // edit routes });
Manually acquire and release a lock:
$order->lockFor($user); $order->unlockFor($user);
::: warning Note
UnlocksModelOnTerminate only releases locks when the response status is 200.
If a request fails or returns a different success status, the lock remains active until it is explicitly released or it expires. :::
API
Models
LaravelEnso\LockableModels\Models\LockableModel
Public methods:
lock()lockFor(User $user): voidunlockFor(User $user): voidlockForMinutes(): int
LaravelEnso\LockableModels\Models\ModelLock
Public methods:
expired(): boolallowed(User $user): booluser(): BelongsToscopeIsExpired(Builder $query): Builder
Middleware
PreventActionOnLockedModelsUnlocksModelOnTerminate
Behavior:
- detects route parameters that are instances of
LockableModel - blocks the request if a valid lock belongs to another user
- acquires the lock for the current user before handling the request
- releases the lock on terminate for successful
200responses
Exceptions
LaravelEnso\LockableModels\Exceptions\ModelLockException
Current lock failure message:
Locked by: :user
Depends On
Required Enso packages:
Framework dependency:
Contributions
are welcome. Pull requests are great, but issues are good too.
Thank you to all the people who already contributed to Enso!