Weave Code
Code Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Laravel Rewind Laravel Package

avocet-shores/laravel-rewind

Full version control for Eloquent models: rewind, fast-forward, restore, diff, and query point-in-time state. Uses a hybrid engine (diffs + snapshots) with configurable intervals, thread-safe locking, batch revisions, queued writes, and pruning.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Steps

  1. Installation:

    composer require avocet-shores/laravel-rewind
    php artisan vendor:publish --provider="AvocetShores\LaravelRewind\LaravelRewindServiceProvider"
    php artisan migrate
    

    Run the migration to add the current_version column to your models.

  2. Enable Versioning: Add the Rewindable trait to your Eloquent model:

    use AvocetShores\LaravelRewind\Traits\Rewindable;
    
    class Post extends Model
    {
        use Rewindable;
    }
    
  3. First Use Case: Update a model and immediately test versioning:

    $post = Post::find(1);
    $post->update(['title' => 'Updated Title']);
    Rewind::rewind($post); // Revert to previous state
    

Where to Look First

  • Facade: AvocetShores\LaravelRewind\Facades\Rewind for core operations.
  • Model Trait: Rewindable for model integration.
  • Version Model: RewindVersion for querying history.
  • Config: config/rewind.php for customization.

Implementation Patterns

Core Workflow

  1. Versioning Models:

    // Automatically tracks changes
    $post->update(['title' => 'New Title']);
    
    // Manual version creation (if needed)
    $post->createVersion();
    
  2. Navigation:

    // Move backward/forward
    Rewind::rewind($post, 2);       // Go back 2 versions
    Rewind::fastForward($post);     // Move forward 1 version
    
    // Jump to a specific version
    Rewind::goTo($post, 5);
    
  3. State Restoration:

    // Preview without audit trail
    Rewind::goTo($post, 3);
    
    // Create a new version (audit-compliant)
    Rewind::restore($post, 3);
    
  4. Diffing and Inspection:

    // Get diff between versions
    $diff = Rewind::diff($post, 1, 5);
    
    // Replay history
    Rewind::replay($post, 1, 10, function ($version, $attributes) {
        // Process each version
    });
    

Integration Tips

  • State Transitions: Track critical fields (e.g., status) separately:

    class Order extends Model
    {
        use Rewindable;
        protected array $rewindStateFields = ['status'];
    }
    

    Query transitions:

    $order->versions()->whereStateBecame('status', 'shipped')->get();
    
  • Batch Versioning: Group related changes (e.g., order + items):

    $batchUuid = Rewind::batch(function () {
        $order->update(['status' => 'shipped']);
        $item->update(['shipped_at' => now()]);
    });
    
  • Exclude Fields:

    public static function excludedFromVersioning(): array
    {
        return ['password', 'api_token'];
    }
    
  • Metadata: Attach context to versions:

    Rewind::withMeta(['reason' => 'Bulk update', 'ticket' => 'JIRA-123']);
    $post->update(['title' => 'Updated']);
    

Common Patterns

  1. Preview Changes: Use goTo() to inspect old states without creating new versions.

  2. Audit Trails: Use restore() for compliance-critical changes.

  3. Performance:

    • For high-write models, enable queued versioning (listener_should_queue = true).
    • Adjust snapshot_interval (default: 10) to balance storage vs. reconstruction speed.
  4. Testing: Reset versions in tests:

    $post->versions()->delete();
    

Gotchas and Tips

Pitfalls

  1. Locking Conflicts:

    • Concurrent writes may fail due to cache locks. Handle timeouts via on_lock_timeout config (log, event, or throw).
    • Fix: Use throw for queued listeners to trigger retries.
  2. Snapshot Interval:

    • Too high (snapshot_interval) = slower reconstruction.
    • Too low = higher storage usage.
    • Tip: Monitor RewindVersion size and adjust (e.g., snapshot_interval = 20).
  3. Amend vs. Exclude:

    • amendCurrentVersion() folds changes into the current version (no new row).
    • excludedFromVersioning() removes fields entirely from history.
    • Gotcha: Amended fields still appear in diffs but may confuse users.
  4. State Transitions:

    • Only fields in $rewindStateFields are tracked as transitions.
    • Tip: Use stateHistory('field') to debug transition logic.
  5. Pruning:

    • Pruning converts the new oldest version to a snapshot. Ensure keep and days values don’t conflict.
    • Tip: Run --pretend first to preview deletions.

Debugging

  1. Version Reconstruction: If goTo() or diff() returns unexpected data:

    • Check snapshot_interval in config.
    • Verify no corrupted diffs with:
      Rewind::getVersionAttributes($post, $version);
      
  2. Lock Timeouts:

    • Enable throw in config to surface issues:
      'on_lock_timeout' => 'throw',
      
    • Check Laravel logs for LockTimeoutRewindException.
  3. Batch Queries:

    • Ensure batch_uuid is consistent across related models:
      RewindVersion::inBatch($batchUuid)->get();
      

Extension Points

  1. Custom Version Model: Extend RewindVersion for additional fields:

    class CustomRewindVersion extends RewindVersion
    {
        protected $casts = [
            'custom_field' => 'string',
        ];
    }
    

    Update config/rewind.php:

    'version_model' => App\Models\CustomRewindVersion::class,
    
  2. Event Listeners: Listen for version creation:

    RewindVersion::created(function ($version) {
        // Log or notify on critical changes
    });
    
  3. Queue Retries: Customize retry logic for queued versions:

    'queue' => [
        'retry_after' => 60, // seconds
        'max_attempts' => 3,
    ],
    

Performance Tips

  1. Indexing: Add indexes to RewindVersion for frequent queries:

    Schema::table('rewind_versions', function (Blueprint $table) {
        $table->index('model_type');
        $table->index('model_id');
        $table->index(['model_type', 'model_id', 'version']);
    });
    
  2. Pruning Schedule: Run pruning during off-peak hours:

    Schedule::command('rewind:prune --keep=50 --force')->dailyAt('2:00');
    
  3. Snapshot Optimization: For models with large attributes, increase snapshot_interval (e.g., 30).

Config Quirks

  1. Default Values:

    • max_versions: Global cap (per-model overrides take precedence).
    • snapshot_interval: Default 10; adjust based on model complexity.
  2. Queue Config:

    • If listener_should_queue = true, ensure your queue worker is running.
    • Monitor failed_jobs table for stuck jobs.
  3. State Fields:

    • Only fields in $rewindStateFields trigger transition queries.
    • Tip: Use whereStateChanged('field') to debug missing transitions.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
codraw/framework-extra-bundle
codraw/messenger
codraw/security
codraw/mailer
codraw/contracts
codraw/profiling
codraw/dependency-injection
codraw/tester
codraw/core
nexmo/api-specification
capell-app/block-library
axium/identity
cetria/laravel-dummy-models
cetria/reflection-helper
agropredict/sso-auth-bundle
evolvestudio/spam-protection
datacore/hub-sdk
develia/commons
cuci/prototurk-sdk
cuci/prototurk-sdk-symfony