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

Approval Laravel Package

cjmellor/approval

Laravel package to stage and review model changes before they’re persisted. It stores pending/new or amended data (approve/reject states) so you can build your own approval workflow. Includes migrations and configurable states/tables.

View on GitHub
Deep Wiki
Context7

Technical Evaluation

Architecture Fit

  • Polymorphic Approval System: The package leverages Laravel’s polymorphic relationships to store approval states for any model, making it highly flexible for systems requiring workflow validation (e.g., content moderation, financial transactions, or multi-tiered review processes).
  • Event-Driven Design: Events (ModelApproved, ModelRejected, ApprovalExpired) align well with Laravel’s ecosystem, enabling seamless integration with queues, notifications, or custom business logic.
  • State Management: Uses an ApprovalStatus enum for type safety and extensibility, supporting both default (pending, approved, rejected) and custom states. This reduces boilerplate for state transitions.
  • Separation of Concerns: The package decouples storage of pending data from approval logic, allowing teams to implement custom approval workflows (e.g., email notifications, admin dashboards) without modifying the core package.

Integration Feasibility

  • Laravel Native: Built for Laravel 11/12/13, with zero external dependencies beyond Laravel core. Composer integration is trivial (composer require cjmellor/approval).
  • Database Schema: Publishes a single approvals table with polymorphic fields (approvalable_type, approvalable_id), requiring minimal migration effort. Schema changes in v2.x are documented in UPGRADE.md.
  • Model Integration: Adds a MustBeApproved trait to models, with optional configuration (e.g., approvalAttributes to whitelist fields). No need for base class inheritance.
  • Query Scopes: Provides fluent methods (approved(), rejected(), pending()) and custom state queries, reducing custom Eloquent logic.

Technical Risk

  • Performance Overhead:
    • Dirty Data Capture: For models with many attributes or frequent updates, storing new_data/original_data as JSON may impact database size and query performance. Mitigation: Use approvalAttributes to limit tracked fields.
    • Polymorphic Queries: Joins on approvals table could slow down queries if not optimized (e.g., indexing approvalable_type + approvalable_id).
  • State Transition Logic: Custom workflows (e.g., "needs_revision") require manual implementation. The package provides hooks (events, setState()), but complex state machines may need additional layers.
  • Expiration Handling: Time-based actions (e.g., auto-reject) require a scheduled job (approval:process-expired). Misconfiguration could lead to missed expirations or duplicate processing.
  • Rollback Behavior: Default rollback bypasses re-approval unless explicitly configured (rollback(bypass: false)). This could lead to unintended data persistence if not handled carefully.

Key Questions

  1. Workflow Complexity:
    • Does the team need simple binary approvals (pending/approved/rejected), or complex multi-step workflows (e.g., "draft" → "review" → "published")? If the latter, additional packages (e.g., spatie/laravel-activitylog + custom states) may be needed.
  2. Data Sensitivity:
    • Are new_data/original_data JSON fields a concern for GDPR/compliance? If so, consider encrypting sensitive fields or using Laravel’s encrypt cast.
  3. Concurrency:
    • How will concurrent edits be handled? The package doesn’t natively support optimistic locking for approvals; teams may need to implement lockForUpdate() or similar.
  4. Testing Strategy:
    • How will approval workflows be tested? The package includes unit tests, but end-to-end testing (e.g., event listeners, scheduled jobs) requires additional setup.
  5. Legacy Systems:
    • If integrating with existing approval systems, how will data migration from old systems to the approvals table be handled?

Integration Approach

Stack Fit

  • Laravel Ecosystem: Optimized for Laravel’s Eloquent ORM, events, and queues. Works seamlessly with:
    • Queues: Dispatch approval events to async workers (e.g., ModelApproved → send email).
    • Notifications: Trigger Notifiable events for state changes.
    • APIs: Return approval status in API responses (e.g., GET /posts/{id}{ "status": "pending" }).
  • Frontend Integration:
    • Admin Panels: Use the ApprovalStateScope to build dashboards (e.g., "Pending Posts" list).
    • User Flows: Show approval status in UI (e.g., "Your submission is under review").
  • Third-Party Extensions:
    • Activity Logs: Pair with spatie/laravel-activitylog to audit approval changes.
    • Webhooks: Use ModelApproved events to trigger external webhooks (e.g., Slack alerts).

Migration Path

  1. Pilot Phase:
    • Start with a single model (e.g., Post) to test the trait, scopes, and events.
    • Validate JSON storage of new_data/original_data for your use case.
  2. Schema Migration:
    • Publish and run migrations (php artisan vendor:publish --tag="approval-migrations").
    • Add indexes to approvals table for performance:
      CREATE INDEX approvals_approvalable_idx ON approvals(approvalable_type, approvalable_id);
      CREATE INDEX approvals_state_idx ON approvals(state);
      
  3. Configuration:
    • Publish config (php artisan vendor:publish --tag="approval-config") and customize:
      • Foreign keys (e.g., author_id instead of user_id).
      • Custom states (e.g., in_review, needs_info).
  4. Workflow Implementation:
    • Implement approval logic (e.g., admin dashboard to approve()/reject()).
    • Set up expiration handling (e.g., expiresIn(hours: 24)->thenReject()).
  5. Event Listeners:
    • Register listeners for critical events (e.g., ModelApproved → notify user).
    • Example:
      // app/Listeners/ApprovePostListener.php
      public function handle(ModelApproved $event) {
          if ($event->approval->approvalable_type === Post::class) {
              Post::find($event->approval->approvalable_id)
                  ->user
                  ->notify(new PostApprovedNotification());
          }
      }
      

Compatibility

  • Laravel Versions: Supports Laravel 11–13. For older versions, use v1.x (but note breaking changes in v2.x).
  • PHP Versions: Requires PHP 8.1+. Test compatibility with your PHP version.
  • Database: Works with MySQL, PostgreSQL, SQLite (via Laravel’s JSON support). Avoid SQL Server if using JSON columns extensively.
  • Dependencies: No conflicts with common Laravel packages (e.g., laravel/breeze, spatie/laravel-permission).

Sequencing

  1. Core Integration:
    • Add MustBeApproved trait to models.
    • Configure approvalAttributes if needed.
  2. Database:
    • Run migrations.
    • Add indexes (post-migration).
  3. Workflow Logic:
    • Build approval UI (e.g., admin panel).
    • Implement event listeners.
  4. Expiration:
    • Schedule the approval:process-expired command (e.g., every 5 minutes).
  5. Testing:
    • Unit tests for model traits and scopes.
    • Integration tests for workflows (e.g., "create → approve → notify user").
  6. Monitoring:
    • Log ApprovalExpired events to track missed expirations.
    • Monitor approvals table growth (archive old records if needed).

Operational Impact

Maintenance

  • Package Updates:
    • Monitor for breaking changes (e.g., v2.x’s enum updates). Use composer why-not cjmellor/approval to check for outdated versions.
    • Test updates in staging before production.
  • Schema Changes:
    • Future versions may add columns (e.g., new fields for custom states). Plan for backward-compatible migrations.
  • Custom Logic:
    • Approval workflows (e.g., custom states, rollback rules) require manual maintenance. Document these in your codebase.

Support

  • Debugging:
    • Use the approvals table to audit state transitions. Example query:
      SELECT * FROM approvals
      WHERE approvalable_type = 'App\Models\Post'
      ORDER BY created_at DESC
      LIMIT 10;
      
    • Check event logs for ModelApproved/ModelRejected entries.
  • Common Issues:
    • Missing Foreign Keys: Ensure models include the configured foreign key (e.g., user_id) during creation.
    • JSON Errors: Validate new_data/original_data serialization (e.g., avoid circular references in model attributes).
    • Expiration Failures: Verify the approval:process-expired command runs (check Laravel scheduler logs).

Scaling

  • Database Load:
    • Reads: Scopes (approved(), pending()) are efficient with proper indexing.
    • Writes: Approval creation adds a row per model update. For high-volume systems:
      • Batch
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.
davejamesmiller/laravel-breadcrumbs
artisanry/parsedown
bower-asset/punycode
bower-asset/inputmask
bower-asset/jquery
bower-asset/yii2-pjax
laravel/nova
spatie/laravel-mailcoach
spatie/laravel-superseeder
laravel/liferaft
nst/json-test-suite
danielmiessler/sec-lists
jackalope/jackalope-transport
twbs/bootstrap4
php-http/client-implementation
phpcr/phpcr-implementation
cucumber/gherkin-monorepo
haydenpierce/class-finder
psr/simple-cache-implementation
uri-template/tests