androsamp/filament-resource-lock
To begin using androsamp/filament-resource-lock, follow these minimal steps:
Install the Package
composer require androsamp/filament-resource-lock
php artisan filament-resource-lock:install
php artisan migrate
This publishes the config, migrations, and assets, and injects the Echo script into your bootstrap.js.
Enable Locking on a Model
Add the HasResourceLocks trait to your Eloquent model:
use Androsamp\FilamentResourceLock\Concerns\HasResourceLocks;
class Customer extends Model
{
use HasResourceLocks;
}
Integrate Locking into an Edit Page
Add the InteractsWithResourceLock trait to your EditRecord page:
use Androsamp\FilamentResourceLock\Concerns\InteractsWithResourceLock;
class EditCustomer extends EditRecord
{
use InteractsWithResourceLock;
}
Display Lock Status in Tables
Add the ResourceLockColumn to your table columns:
use Androsamp\FilamentResourceLock\Resources\Columns\ResourceLockColumn;
public static function table(Table $table): Table
{
return $table->columns([
ResourceLockColumn::make(),
// ... other columns
]);
}
First Use Case: Test locking by opening a record in two browser tabs. The second tab should show a lock indicator and disable form actions until the lock is released.
Lock Acquisition
When a user opens an EditRecord page, the package automatically attempts to acquire a lock on the record. If another user holds the lock, the UI shows the lock owner and disables form actions.
Lock Management
ttl_seconds (configurable).'update_driver' => 'broadcast' in the config.Collaboration Actions
permission.ask_to_unblock), a locked-out user can request the lock owner to release it.Audit History (Optional)
Enable auditing in the config (audit.enabled = true) to track changes. Add the HasResourceAudit trait to your EditRecord page and include the audit action in getHeaderActions():
use Androsamp\FilamentResourceLock\Concerns\HasResourceAudit;
class EditProduct extends EditRecord
{
use InteractsWithResourceLock, HasResourceAudit;
protected function getHeaderActions(): array
{
return [
$this->getAuditHistoryAction(),
// ... other actions
];
}
}
Custom Fields in Audit Diffs
Extend the HasAuditDiffPreview trait for custom fields to render diffs properly:
use Androsamp\FilamentResourceLock\Forms\Concerns\HasAuditDiffPreview;
class CustomField extends Field
{
use HasAuditDiffPreview;
protected function setUp(): void
{
$this->auditDiffPreviewUsing(function ($state) {
return '<p class="text-sm">' . e($state) . '</p>';
});
}
}
Override save() for Audit Compatibility
If you override save() in your EditRecord page, ensure you call the audit sync methods:
public function save(bool $shouldRedirect = true): void
{
$this->syncResourceAuditBeforeSave();
parent::save($shouldRedirect);
$this->syncResourceAuditAfterSave();
}
Broadcast Configuration
For broadcast mode, ensure your bootstrap.js includes the Echo script published by the package and configure Laravel’s broadcasting driver (e.g., Reverb, Pusher). Update the config:
'update_driver' => 'broadcast',
'transports' => [
'broadcast' => [
'channel_prefix' => 'filament-resource-lock',
'event' => 'filament-resource-lock-updated',
'renew_interval_seconds' => 5,
],
],
Permissions Customize permissions in the config to control who can request unlocks or save-and-unlock:
'permission' => [
'save_and_unlock' => [
'enabled' => true,
'permission' => 'custom.permission.save_and_unlock',
],
'ask_to_unblock' => [
'enabled' => false, // Disable if not needed
],
],
Soft Release Route
The package registers a signed route (filament-resource-lock.release) for handling lock release during tab closure. Ensure APP_URL is correctly set to avoid validation issues.
Overriding save() Without Audit Sync
If you override the save() method in your EditRecord page without calling syncResourceAuditBeforeSave() and syncResourceAuditAfterSave(), audit history will not work. Always wrap your custom save logic with these calls:
public function save(): void
{
$this->syncResourceAuditBeforeSave();
// Custom save logic here
$this->syncResourceAuditAfterSave();
}
Broadcast Mode Without Echo Setup
If you enable broadcast mode ('update_driver' => 'broadcast') but forget to configure Laravel broadcasting (e.g., missing .env settings for BROADCAST_DRIVER) or publish the Echo script, lock updates will fail silently. Verify:
resources/js/filament-resource-lock/echo.js) is included in your bootstrap.js.window.Echo object is available globally.Lock TTL Too Short
If ttl_seconds in the config is too short (e.g., < 10), users may experience frequent lock expirations during editing, leading to frustration. Test with a value like 30 for interactive workflows.
Audit Table Bloat
The audit feature stores snapshots of record states. If max_entries_per_resource is set too high (or omitted), the resource_lock_audits table may grow uncontrollably. Monitor table size and adjust the limit:
'audit' => [
'max_entries_per_resource' => 100, // Limit to 100 entries per resource
],
Permission Policy Conflicts
If you define custom permissions (e.g., 'permission' => 'custom.save_and_unlock') but the user lacks the corresponding gate/policy, the action will be disabled. Test permissions thoroughly:
Gate::define('custom.save_and_unlock', function ($user) {
return $user->can('manage_customers');
});
Soft Release Route Issues
The signed route (filament-resource-lock.release) may fail if APP_URL is misconfigured (e.g., http vs https, or incorrect domain). Test the route manually:
php artisan route:list | grep "filament-resource-lock.release"
Ensure the URL generated by the route matches your app’s base URL.
Livewire Heartbeat Conflicts If you’re using other Livewire components with custom heartbeat intervals, conflicts may arise. Ensure the package’s heartbeat (default: every 10 seconds) aligns with your app’s needs. Adjust in the config:
'heartbeat_interval_seconds' => 15,
Check Lock Status
Inspect the resource_locks table directly to verify lock records:
SELECT * FROM resource_locks WHERE resource_id = [ID];
Look for locked_at, expires_at, and user_id fields.
Enable Broadcast Logging For broadcast mode, enable Laravel Echo logging to debug connection issues:
'logging' => [
'enabled' => true,
'channel' => 'private-filament-resource-lock',
],
Check Laravel logs for Echo events like filament-resource-lock-updated.
Audit Diff Rendering
If custom field diffs don’t render, verify the auditDiffPreviewUsing callback returns valid HTML. Use browser dev tools to inspect the rendered diff modal.
Permission Debugging
Use Laravel’s authorize() method to debug permission issues:
if (auth()->user()->can('filament-resource-lock.save_and_unlock')) {
// Action allowed
}
Soft Release Grace Period If locks aren’t releasing properly on tab close, adjust `release
How can I help you explore Laravel packages today?