avocet-shores/laravel-rewind
Full version control for Eloquent models: rewind, fast-forward, restore, diff, and query point-in-time state. Uses hybrid diffs + snapshots for efficient storage and fast reconstruction, with locking for safe concurrent writes, batching, queues, and pruning.
Installation:
composer require avocet-shores/laravel-rewind
php artisan vendor:publish --provider="AvocetShores\LaravelRewind\LaravelRewindServiceProvider"
php artisan migrate
Enable Versioning:
Add the Rewindable trait to your Eloquent model:
use AvocetShores\LaravelRewind\Traits\Rewindable;
class Post extends Model {
use Rewindable;
}
Add Version Column:
php artisan rewind:add-version
php artisan migrate
Track and Rewind Changes:
$post = Post::find(1);
$post->update(['title' => 'Updated Title']);
Rewind::rewind($post); // Revert to previous version
Basic Version Navigation:
Rewind::goTo($post, 3); // Jump to version 3
Rewind::rewind($post); // Move back 1 version
Rewind::fastForward($post); // Move forward 1 version
State Restoration:
Rewind::restore($post, 2); // Create new version from v2's state
Batch Versioning:
Rewind::batch(function () {
$order->update(['status' => 'shipped']);
$item->update(['shipped_at' => now()]);
});
Queue Version Creation (for high-traffic models):
// config/rewind.php
'listener_should_queue' => true,
State Field Tracking:
class Order extends Model {
use Rewindable;
protected array $rewindStateFields = ['status', 'payment_status'];
}
Exclude Sensitive Fields:
public static function excludedFromVersioning(): array {
return ['password', 'api_token'];
}
Audit Logs: Query version history with scopes:
$post->versions()->whereStateBecame('status', 'published')->get();
Time-Travel Queries:
$oldAttributes = Rewind::versionAt($post, Carbon::yesterday());
Diff Analysis:
$diff = Rewind::diff($post, 1, 5);
if ($diff->changed) {
// Handle changes
}
Lock Timeouts:
LockTimeoutRewindException. Configure handling in config/rewind.php:
'on_lock_timeout' => 'event', // Options: 'log', 'event', 'throw'
Snapshot Interval:
snapshot_interval) = slower reconstruction.Amend vs. Exclude:
amendCurrentVersion() for fields you want sometimes tracked.excludedFromVersioning() for fields never to track.Check Version Reconstruction:
$attributes = Rewind::getVersionAttributes($post, 7);
// Debug missing fields if diffs are incomplete
Batch UUID Mismatch:
Custom Version Model:
Extend RewindVersion to add columns/scopes:
// config/rewind.php
'version_model' => App\Models\CustomRewindVersion::class,
Event Listeners:
Listen for RewindVersionLockTimeout or RewindVersionCreated events.
Pruning Logic:
Override prune() in your custom version model for custom cleanup rules.
Snapshot Interval Tuning:
Monitor rewind_versions table size vs. query performance to adjust snapshot_interval.
Queued Versioning:
For bulk operations, use Rewind::batch() to group versions and reduce lock contention.
State Transitions:
amendCurrentVersion() mode. Use initVersion() for baseline snapshots.Pruning Behavior:
--pretend first.Diff Directionality:
Rewind::diff($model, 5, 1) reverses old/new values. Use ->isEmpty() to verify.
How can I help you explore Laravel packages today?