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 Approval Laravel Package

wezlo/filament-approval

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Installation

    composer require wezlo/filament-approval
    php artisan vendor:publish --tag=filament-approval-migrations
    php artisan migrate
    

    Verify the approvals, approval_actions, and approval_notifications tables exist.

  2. First Use Case: Basic Approval Chain Add the HasApprovals trait to your Eloquent model:

    use Wezlo\FilamentApproval\Traits\HasApprovals;
    
    class Invoice extends Model
    {
        use HasApprovals;
    }
    

    Publish the config and views:

    php artisan vendor:publish --tag=filament-approval-config
    php artisan vendor:publish --tag=filament-approval-views
    
  3. Define an Approval Flow Create a Filament resource for your model (e.g., InvoiceResource). In the resource’s getRelations() method, include:

    public static function getRelations(): array
    {
        return [
            ApprovalRelationManager::make(),
        ];
    }
    

    Access the Approval Workflow tab in the Filament admin panel to configure your first approval chain.


Implementation Patterns

Core Workflows

  1. Single Approver Flow

    • Use the Single Approver chain type in the Filament UI.
    • Define a static approver (e.g., "Finance Manager") or dynamic resolver (e.g., User::where('role', 'finance')->first()).
    • Example resolver in config/filament-approval.php:
      'resolvers' => [
          'finance' => function ($record) {
              return User::where('role', 'finance')->first();
          },
      ],
      
  2. Sequential Approval Chain

    • Configure a Sequential chain with multiple steps (e.g., "Team Lead" → "Department Head" → "Director").
    • Use the Next Approver resolver to auto-progress:
      'next_approver' => function ($record, $currentApprover) {
          return User::where('department', $record->department)
              ->where('role', 'department_head')
              ->first();
      },
      
  3. Parallel Approval

    • Set up a Parallel chain for multi-stakeholder approvals (e.g., "Legal" and "Compliance").
    • All approvers must act before the workflow completes.
  4. Dynamic Approval Assignment

    • Override the default resolver in your model:
      public function getApprovalResolvers(): array
      {
          return [
              'legal' => function ($record) {
                  return User::where('email', 'legal@company.com')->first();
              },
          ];
      }
      

Integration Tips

  • Filament Resource Integration Add the ApprovalStatusBadge column to your resource table:

    public static function getTableColumns(): array
    {
        return [
            ApprovalStatusBadge::make(),
            // ... other columns
        ];
    }
    
  • Infolist for Quick Status Check Display approval status in the model’s detail view:

    public static function getInfolists(): array
    {
        return [
            'default' => [
                ApprovalStatusSection::make(),
                // ... other sections
            ],
        ];
    }
    
  • Notifications Customize notification triggers in config/filament-approval.php:

    'notifications' => [
        'requested' => true,
        'approved' => true,
        'rejected' => true,
        'escalated' => true,
        'sla_warning' => true,
    ],
    
  • SLA and Escalation Configure SLAs per approval step in the Filament UI (e.g., "24 hours for Team Lead"). Define escalation actions (e.g., auto-reject after 48 hours):

    'escalation' => [
        'auto_reject_after_hours' => 48,
    ],
    
  • Delegation Allow approvers to delegate via the Filament UI or programmatically:

    $approval->delegateTo(User::find(123));
    
  • Audit Trail Access the full history via the ApprovalRelationManager:

    $record->approvals()->with('actions')->latest()->get();
    

Gotchas and Tips

Pitfalls

  1. Migration Conflicts

    • If you’ve customized the notifications table, merge the published migrations carefully. The package expects standard notification columns (type, data, etc.).
    • Fix: Use php artisan migrate --pretend to preview conflicts before applying.
  2. Resolver Caching

    • Dynamic resolvers (e.g., next_approver) are called on every action. Cache results if resolvers are expensive:
      'next_approver' => function ($record, $currentApprover) {
          return Cache::remember("next_approver_{$record->id}", now()->addHours(1), function () {
              return User::where(...)->first();
          });
      },
      
  3. SLA Processing

    • The RunSlaChecks command must run periodically (e.g., via Laravel’s scheduler):
      * * * * * php artisan approval:sla-check
      
    • Gotcha: If the command fails silently, check storage/logs/laravel.log for resolver errors.
  4. Polymorphic Model Issues

    • Ensure your model’s approvals() relation is correctly defined:
      public function approvals()
      {
          return $this->morphMany(Approval::class, 'approvable');
      }
      
    • Debug: Run php artisan route:list | grep approval to verify webhook routes.
  5. Filament Plugin Isolation

    • The package auto-registers a Filament plugin. If you have multiple panels, configure the panel group in config/filament-approval.php:
      'panel_group' => 'admin', // or 'tenant', etc.
      

Debugging

  1. Approval State Transitions

    • Log transitions to track unexpected states:
      Approval::observe(ApprovalObserver::class);
      
    • Add a custom observer:
      namespace App\Observers;
      use Wezlo\FilamentApproval\Models\Approval;
      
      class ApprovalObserver
      {
          public function saved(Approval $approval)
          {
              \Log::info("Approval {$approval->id} transitioned to {$approval->status}");
          }
      }
      
  2. Resolver Failures

    • Wrap resolvers in try-catch to avoid breaking the workflow:
      'resolver' => function ($record) {
          try {
              return User::where(...)->firstOrFail();
          } catch (\Exception $e) {
              \Log::error("Resolver failed for {$record->id}: " . $e->getMessage());
              return null; // Fallback to next resolver or reject
          }
      },
      
  3. SLA Not Triggering

    • Verify the created_at and updated_at timestamps on approvals and approval_actions tables.
    • Test: Manually set updated_at to a past date and re-run the SLA command.

Extension Points

  1. Custom Approval Actions

    • Extend the ApprovalAction model or create a custom action type:
      namespace App\Models;
      use Wezlo\FilamentApproval\Models\ApprovalAction;
      
      class CustomApprovalAction extends ApprovalAction
      {
          protected $table = 'custom_approval_actions';
      }
      
    • Register in config/filament-approval.php:
      'action_models' => [
          \App\Models\CustomApprovalAction::class,
      ],
      
  2. Custom Notifications

    • Override the notification logic by publishing the views and extending the ApprovalNotification class:
      php artisan vendor:publish --tag=filament-approval-views
      
    • Create a custom notification channel:
      namespace App\Notifications;
      use Wezlo\FilamentApproval\Notifications\ApprovalNotification;
      
      class CustomApprovalNotification extends ApprovalNotification
      {
          public function via($notifiable)
          {
              return ['database', 'mail']; // Add Slack, etc.
          }
      }
      
    • Bind it in config/filament-approval.php:
      'notification_class' => \App\Notifications\CustomApprovalNotification::class,
      
  3. Custom UI Components

    • Override the Filament widgets or relation manager by publishing assets:
      php artisan vendor:publish --tag=filament-approval-assets
      
    • Extend the ApprovalRelationManager:
      namespace App\Filament\Resources;
      use Wezlo\FilamentApproval\Filament\Resources\ApprovalRelationManager;
      
      class CustomApprovalRelationManager
      
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.
milito/query-filter
apiboxsym/user-bundle
apiboxsym/health-check-bundle
jayeshmepani/jpl-moshier-ephemeris-php
elnasnato/laraliveui
labrodev/rest-sdk
sampaui/sampaui
babelqueue/php-sdk
facebook/capi-param-builder-php
babelqueue/symfony
hamzi/corewatch
minionfactory/raw-hydrator
hexters/coinpayment
rjcodes/rjcms
act-training/laravel-permissions-manager
alimarchal/laravel-chart-of-accounts
babenkoivan/elastic-scout-driver
mkwebdesign/filament-watchdog-v5
renatomarinho/laravel-page-speed
zedmagdy/filament-business-hours