Installation:
composer require mtvs/eloquent-approval
Publish the migration and config:
php artisan vendor:publish --provider="Mtvs\EloquentApproval\EloquentApprovalServiceProvider"
php artisan migrate
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.
First Use Case:
Create a new record—it defaults to pending:
$post = Post::create(['title' => 'Draft Post']);
// $post->status === 'pending'
Approval States:
$post->approve(); // Sets status to 'approved', updates `approved_at`
$post->reject(); // Sets status to 'rejected'
approvedAttributes).Query Scoping:
pending/rejected records. Override with:
Post::withStatus('pending')->get(); // Explicitly include non-approved
Post::withoutStatusScope()->get(); // Disable scope entirely
Mass Actions:
Post::where('user_id', 1)->approve();
Post::where('title', 'like', '%draft%')->reject();
Event Listeners:
Post::approved(function ($post) {
// Send notification, etc.
});
approvedAttributes in your model to auto-suspend on updates:
protected $approvedAttributes = ['title', 'content'];
SoftDeletes trait. Use withTrashed() to include deleted records in queries.return Post::approved()->get(['title', 'approved_at']);
Default Scope Overrides:
withoutStatusScope() when querying pending/rejected records.Auto-Suspend on Updates:
approvedAttributes trigger suspended state, even if no changes were made to those fields.if ($post->isDirty('title')) {
$post->update(['title' => 'New Title']);
}
Race Conditions:
DB::transaction(function () use ($post) {
$post->approve();
// Other related updates
});
Model Caching:
fresh() to reload:
$post->approve();
$post = $post->fresh(); // Ensure latest status
dd($post->status); // 'pending'|'approved'|'rejected'|'suspended'
DB::enableQueryLog();
Post::all();
dd(DB::getQueryLog());
Custom Statuses:
Extend the status field by overriding the getStatusAttribute method:
public function getStatusAttribute($value) {
return $value === 'pending' ? 'under_review' : $value;
}
Custom Approval Logic:
Override approve()/reject() methods to add pre/post actions:
public function approve() {
$this->fireModelEvent('approving');
parent::approve();
$this->fireModelEvent('approved');
}
Global Config:
Override default settings in config/eloquent-approval.php:
'default_status' => 'pending',
'approved_attributes' => ['title', 'content'],
Policy Integration: Use Laravel Policies to restrict who can approve/reject:
public function approve(Post $post) {
return $this->user()->isAdmin();
}
How can I help you explore Laravel packages today?