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

Filament Versionable Laravel Package

mansoor/filament-versionable

Filament plugin for managing Eloquent model revisions with Overtrue Laravel Versionable. View revision history, see diffs of what changed and who changed it, and restore any previous version from a dedicated Filament page.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Install the package:

    composer require mansoor/filament-versionable
    
  2. Publish migrations and config:

    php artisan vendor:publish --provider="Overtrue\LaravelVersionable\ServiceProvider"
    php artisan migrate
    
  3. Configure your model:

    use Overtrue\LaravelVersionable\Versionable;
    use Overtrue\LaravelVersionable\VersionStrategy;
    
    class Post extends Model
    {
        use Versionable;
    
        protected $versionable = ['title', 'content'];
        protected $versionStrategy = VersionStrategy::SNAPSHOT; // Critical for full attribute tracking
    }
    
  4. Add the RevisionsPage to your Filament Resource:

    namespace App\Filament\Resources\PostResource\Pages;
    
    use Mansoor\FilamentVersionable\RevisionsPage;
    
    class PostRevisions extends RevisionsPage
    {
        protected static string $resource = PostResource::class;
    }
    
  5. Register the page in your Resource:

    public static function getPages(): array
    {
        return [
            'revisions' => Pages\PostRevisions::route('/{record}/revisions'),
        ];
    }
    
  6. Add the RevisionsAction to your Edit/View pages:

    use Mansoor\FilamentVersionable\Page\RevisionsAction;
    
    protected function getHeaderActions(): array
    {
        return [
            RevisionsAction::make(),
        ];
    }
    

First Use Case

Scenario: You want to track changes to a blog post and allow admins to restore previous versions.

  1. Edit a Post in Filament.
  2. After saving, navigate to the Revisions tab (added via RevisionsAction).
  3. View the diff between versions.
  4. Use the Restore button to revert to a previous state.

Implementation Patterns

Core Workflow

  1. Model Configuration:

    • Define $versionable array to specify which attributes to track.
    • Use VersionStrategy::SNAPSHOT for full attribute snapshots (avoid DIFF due to reported bugs).
    • Example:
      protected $versionable = ['title', 'content', 'published_at'];
      
  2. Resource Integration:

    • Extend RevisionsPage for each resource needing versioning.
    • Register the page in getPages() with a route like /{record}/revisions.
    • Example:
      'revisions' => Pages\PostRevisions::route('/{record}/revisions'),
      
  3. UI Placement:

    • Header Actions: Add RevisionsAction::make() to Edit/View pages.
    • Table Actions: Add RevisionsAction::make() to table actions for list views.
    • Example:
      $table->actions([
          RevisionsAction::make(),
      ]);
      
  4. Customization:

    • Strip HTML Tags: Override shouldStripTags() in your RevisionsPage:
      public function shouldStripTags(): bool { return true; }
      
    • Publish Views: Customize the UI by publishing views:
      php artisan vendor:publish --tag="filament-versionable-views"
      

Advanced Patterns

  1. Conditional Versioning:

    • Dynamically set $versionable based on user roles or other logic:
      public function getVersionable(): array
      {
          return auth()->user()->isAdmin() ? ['title', 'content', 'meta_description'] : ['title'];
      }
      
  2. Soft-Deletes Integration:

    • Ensure your model uses SoftDeletes and configure versioning to ignore soft-deleted states:
      protected $versionable = ['title', 'content'];
      protected $ignoreVersionableOn = ['deleted_at'];
      
  3. Bulk Restore:

    • Create a custom action to restore multiple records to a specific version (requires manual implementation).
  4. Version Metadata:

    • Extend the Version model to add custom metadata (e.g., change_reason):
      use Overtrue\LaravelVersionable\Version;
      
      class Version extends \Overtrue\LaravelVersionable\Version
      {
          protected $casts = [
              'change_reason' => 'string',
          ];
      }
      
  5. Performance Optimization:

    • Limit the number of versions stored by overriding the Version model:
      protected static function booted()
      {
          static::addGlobalScope('limit_versions', function (Builder $builder) {
              $builder->orderBy('created_at', 'desc')->take(50);
          });
      }
      

Gotchas and Tips

Common Pitfalls

  1. VersionStrategy::DIFF Issues:

    • Avoid using VersionStrategy::DIFF due to reported bugs (e.g., missing changes or incorrect diffs).
    • Fix: Stick with VersionStrategy::SNAPSHOT for reliability.
  2. Missing Revisions Tab:

    • If the Revisions tab doesn’t appear, ensure:
      • The RevisionsPage is properly registered in getPages().
      • The model has at least one version (triggered by saving changes).
      • The RevisionsAction is added to the page’s header/actions.
  3. UUID Primary Keys:

    • If using UUIDs, ensure the RevisionsPage accepts UUIDs in showVersion():
      public function showVersion($version)
      {
          return parent::showVersion($version instanceof Uuid ? $version->toString() : $version);
      }
      
  4. HTML Diff Rendering:

    • Rich text fields (e.g., content) may break diffs. Use shouldStripTags():
      public function shouldStripTags(): bool { return true; }
      
  5. Migration Conflicts:

    • If migrations fail, check for existing versions table. Drop it manually if needed:
      php artisan migrate:fresh --env=testing
      

Debugging Tips

  1. Check Version Storage:

    • Verify versions are saved by querying the versions table:
      php artisan tinker
      >>> \App\Models\Post::find(1)->versions()->count();
      
  2. Log Version Changes:

    • Add a model observer to log version creation:
      use Overtrue\LaravelVersionable\Events\VersionCreated;
      
      VersionCreated::listen(function ($version) {
          \Log::info("Version created for {$version->model_type}: {$version->version}");
      });
      
  3. Diff Not Showing:

    • Ensure $versionable attributes are not excluded (e.g., by accessors/mutators). Use raw attributes:
      protected $versionable = ['title', 'content'];
      protected $appends = []; // Avoid appending non-versionable fields
      
  4. Restore Button Disabled:

    • The restore button may be disabled if:
      • The current version is the only version.
      • The user lacks permissions (check Filament’s canRestore policy).

Extension Points

  1. Custom Version Model:

    • Extend the Version model to add fields like ip_address or device_info:
      class Version extends \Overtrue\LaravelVersionable\Version
      {
          protected $fillable = ['ip_address', 'user_agent'];
      }
      
  2. Version Query Scopes:

    • Add scopes to filter versions (e.g., by date range):
      public function scopeRecent($query, $days = 30)
      {
          return $query->where('created_at', '>=', now()->subDays($days));
      }
      
  3. Custom Diff Renderer:

    • Override the diff template by publishing views and modifying: resources/views/vendor/filament-versionable/revisions/diff.blade.php.
  4. Event Listeners:

    • Listen to version events to trigger notifications or logs:
      use Overtrue\LaravelVersionable\Events\VersionCreated;
      
      VersionCreated::listen(function ($version) {
          // Send email or Slack notification
      });
      
  5. Filament Policy Integration:

    • Restrict access to revisions using Filament’s policies:
      public static function canAccessRevisions(): bool
      {
          return auth()->user()->can('manage_revisions');
      }
      

Configuration Quirks

  1. Theme Integration:

    • Ensure your Filament theme includes the plugin’s CSS:
      @import '../../../../vendor/mansoor/filament-versionable/resources/css/plugin.css';
      @source '../../../../vendor/mansoor/filament-versionable/resources/**/*.blade.php';
      
    • Fix: If styles don’t load, verify the theme path or use Filament’s addThemeStyle() method.
  2. Translation Keys:

    • Customize translations by publishing the language file:
      php artisan vendor:publish --tag="filament-versionable-translations"
      
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.
terminal42/code-quality-tools
codifyo/ts-generator-bundle
andydefer/laravel-cluster
testo/fiber
mintobit/jobqueue
a4sex/maintenance-bundle
a4sex/entity-date-update
a4sex/client-identifier
a4sex/base-utilites
a4sex/key-value-storage
a4sex/micro-status
chilldev/dependency-injection-extra
datinglibre/datinglibre-app-api
biberltd/corebundle
bricre/symfony-bundle-test
biberltd/logbundle
dominium/http-adapter-bundle
dominium/google-analytics
a4sex/auto-clean-entity
christhompsontldr/laravel-inky