Weave 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

Eloquent Approval Laravel Package

mtvs/eloquent-approval

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Installation:

    composer require mtvs/eloquent-approval
    

    Publish the migration and config:

    php artisan vendor:publish --provider="Mtvs\EloquentApproval\EloquentApprovalServiceProvider"
    php artisan migrate
    
  2. Apply to a Model: Use the Approvable trait in your Eloquent model:

    use Mtvs\EloquentApproval\Traits\Approvable;
    
    class Post extends Model
    {
        use Approvable;
    }
    

    This adds status (pending/approved/rejected/suspended) and approved_at fields.

  3. First Use Case: Create a new record—it defaults to pending:

    $post = Post::create(['title' => 'Draft Post']);
    // $post->status === 'pending'
    

Implementation Patterns

Core Workflows

  1. Approval States:

    • Pending: New records or after updates to approved attributes.
    • Approved: Manually approved via:
      $post->approve(); // Sets status to 'approved', updates `approved_at`
      
    • Rejected: Manually rejected:
      $post->reject(); // Sets status to 'rejected'
      
    • Suspended: Automatically triggered on updates to approved attributes (configurable via approvedAttributes).
  2. Query Scoping:

    • Default scope filters out pending/rejected records. Override with:
      Post::withStatus('pending')->get(); // Explicitly include non-approved
      Post::withoutStatusScope()->get();  // Disable scope entirely
      
  3. Mass Actions:

    • Approve/reject multiple records:
      Post::where('user_id', 1)->approve();
      Post::where('title', 'like', '%draft%')->reject();
      
  4. Event Listeners:

    • Listen for status changes:
      Post::approved(function ($post) {
          // Send notification, etc.
      });
      

Integration Tips

  • Custom Attributes: Configure approvedAttributes in your model to auto-suspend on updates:
    protected $approvedAttributes = ['title', 'content'];
    
  • Soft Deletes: Works seamlessly with SoftDeletes trait. Use withTrashed() to include deleted records in queries.
  • API Responses: Filter responses in API controllers:
    return Post::approved()->get(['title', 'approved_at']);
    

Gotchas and Tips

Pitfalls

  1. Default Scope Overrides:

    • Forgetting to use withoutStatusScope() when querying pending/rejected records.
    • Fix: Always explicitly specify status if deviating from default behavior.
  2. Auto-Suspend on Updates:

    • Updates to approvedAttributes trigger suspended state, even if no changes were made to those fields.
    • Fix: Manually check for changes before updating:
      if ($post->isDirty('title')) {
          $post->update(['title' => 'New Title']);
      }
      
  3. Race Conditions:

    • Concurrent approval/rejection actions may cause inconsistencies.
    • Fix: Use database transactions:
      DB::transaction(function () use ($post) {
          $post->approve();
          // Other related updates
      });
      
  4. Model Caching:

    • Cached models may not reflect status changes. Use fresh() to reload:
      $post->approve();
      $post = $post->fresh(); // Ensure latest status
      

Debugging

  • Check Status:
    dd($post->status); // 'pending'|'approved'|'rejected'|'suspended'
    
  • Log Queries: Enable Laravel query logging to debug scope issues:
    DB::enableQueryLog();
    Post::all();
    dd(DB::getQueryLog());
    

Extension Points

  1. Custom Statuses: Extend the status field by overriding the getStatusAttribute method:

    public function getStatusAttribute($value) {
        return $value === 'pending' ? 'under_review' : $value;
    }
    
  2. Custom Approval Logic: Override approve()/reject() methods to add pre/post actions:

    public function approve() {
        $this->fireModelEvent('approving');
        parent::approve();
        $this->fireModelEvent('approved');
    }
    
  3. Global Config: Override default settings in config/eloquent-approval.php:

    'default_status' => 'pending',
    'approved_attributes' => ['title', 'content'],
    
  4. Policy Integration: Use Laravel Policies to restrict who can approve/reject:

    public function approve(Post $post) {
        return $this->user()->isAdmin();
    }
    
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.
mehedimi/laravel-amp-mail
happones/laravel-vue-i18n-generator
jwerd/inertia-table
siberfx/flysystem-wasabi
hollyit/token-replace
ippanelcom/laravel-sdk
adachsoft/changelog-linter
adachsoft/collection
payerurl/telegrambot-crypto-payment-instant-payout
dskripchenko/laravel-hybrid-search
riorizkyrainey/lara-ced
mehedimi/static-vel
zharp/zharp
nonsapiens/bigquery-model-sync
lgu-bayambang-ict-office/lgu-laravel-development-standards
andydefer/laravel-support
se7enxweb/flysystem
lampwick/laravel
jeslage/statamic-emojis
micahdshackelford/rmap-laravel