PHPackages                             mtvs/eloquent-approval - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Database &amp; ORM](/categories/database)
4. /
5. mtvs/eloquent-approval

ActiveLibrary[Database &amp; ORM](/categories/database)

mtvs/eloquent-approval
======================

Approval process for Laravel Eloquent models.

v5.2.0(3y ago)14620.9k↓15%13[1 PRs](https://github.com/mtvs/eloquent-approval/pulls)1MITPHPCI passing

Since Dec 4Pushed 2y ago2 watchersCompare

[ Source](https://github.com/mtvs/eloquent-approval)[ Packagist](https://packagist.org/packages/mtvs/eloquent-approval)[ RSS](/packages/mtvs-eloquent-approval/feed)WikiDiscussions master Synced 1mo ago

READMEChangelogDependencies (5)Versions (30)Used By (1)

[![Build Status](https://github.com/mtvs/eloquent-approval/actions/workflows/build.yml/badge.svg)](https://github.com/mtvs/eloquent-approval/actions/workflows/build.yml/badge.svg)

Eloquent Approval
=================

[](#eloquent-approval)

Approval process for Laravel's Eloquent models.

[![eloquent-approval-preview](https://user-images.githubusercontent.com/8286154/172069783-52fd5b91-e032-4c1a-9094-9611abe4e3c8.png)](https://user-images.githubusercontent.com/8286154/172069783-52fd5b91-e032-4c1a-9094-9611abe4e3c8.png)

Why we need content approval in our apps
----------------------------------------

[](#why-we-need-content-approval-in-our-apps)

Unless you're comfortable with unacceptable content, spam and any other violations that may appear in what the users post, you need to include some sort of content approval in your app.

Why approval process with three states
--------------------------------------

[](#why-approval-process-with-three-states)

Although it's possible to approve a model by using a boolean field but a field that has three possible values: pending, approved and rejected gives us more power. It differentiates between the models waiting for the decision and the rejected ones and also makes it clear for the user if their content gets rejected.

How it works
------------

[](#how-it-works)

After the setup, when new entities are being created, they are marked as *pending*. Then their status can be changed to *approved* or *rejected*.

Also, when an update occurs that modifies attributes that require approval the entity becomes *suspended* again.

By default the approval scope is applied on every query and filters out the *pending* and *rejected* entities, so only *approved* entities are included. You can include the entities that aren't *approved* by explicitly specifying it.

Install
-------

[](#install)

```
$ composer require mtvs/eloquent-approval
```

Setup
-----

[](#setup)

### Registering the service provider

[](#registering-the-service-provider)

By default the service provider is registered automatically by Laravel package discovery otherwise you need to register it in your `config\app.php`

```
Mtvs\EloquentApproval\ApprovalServiceProvider::class
```

### Database

[](#database)

The following method adds two columns to the schema, one to store the *approval status* named `approval_status` and another to store the *timestamp* at which the last status update is occurred named `approval_at`.

```
$table->approvals()
```

You can change the default column names but then you need to specify them on the model too.

### Model

[](#model)

Add `Approvable` trait to the model

```
use Illuminate\Database\Eloquent\Model;
use Mtvs\EloquentApproval\Approvable;

class Entity extends Model
{
    use Approvable;
}
```

If you want to change the default column names you need to specify them by adding class constants to your model

```
use Illuminate\Database\Eloquent\Model;
use Mtvs\EloquentApproval\Approvable;

class Entity extends Model
{
    use Approvable;

    const APPROVAL_STATUS = 'custom_approval_status';
    const APPROVAL_AT = 'custom_approval_at';
}
```

> Add `approval_at` to the model `$dates` list to get `Carbon` instances when accessing it.

#### Approval Required Attributes

[](#approval-required-attributes)

When an update occurs that modifies attributes that require approval, the entity becomes *suspended* again.

```
$entity->update($attributes); // an update with approval required modification

$entity->isPending(); // true
```

> Note that this happens only when you perform the *update* on `Model` object itself not by using a query `Builder` instance.

By default all attributes require approval.

```
/**
 * @return array
 */
public function approvalRequired()
{
    return ['*'];
}

/**
 * @return array
 */
public function approvalNotRequired()
{
    return [];
}
```

You can override them to have a custom set of approval required attributes.

They work like `$fillable` and `$guarded` in the Eloquent. `approvalRequired()` returns the *black list* while `approvalNotRequired()` returns the *white list*.

Usage
-----

[](#usage)

Newly created entities are marked as *pending* and by default excluded from queries on the model.

```
Entity::create(); // #1 pending

Entity::all(); // []

Entity::find(1); // null
```

### Including all the entities

[](#including-all-the-entities)

```
Entity::anyApprovalStatus()->get(); // retrieving all

Entity::anyApprovalStatus()->find(1); // retrieving one

Entity::anyApprovalStatus()->delete(); // deleting all
```

If you want to disable the approval scope totally on every query, you can set the `approvalScopeDisabled` on the model.

```
use Illuminate\Database\Eloquent\Model;
use Mtvs\EloquentApproval\Approvable;

class Entity extends Model
{
    use Approvable;

    public $approvalScopeDisabled = true;
}
```

### Limiting to only a specific status

[](#limiting-to-only-a-specific-status)

```
Entity::onlyPending()->get(); // retrieving only pending entities
Entity::onlyRejected()->get(); // retrieving only rejected entities
Entity::onlyApproved()->get(); // retrieving only approved entities
```

### Updating the status

[](#updating-the-status)

#### On model objects

[](#on-model-objects)

You can update the status of an entity by using provided methods on the `Model`object.

```
$entity->approve(); // returns bool if the entity exists otherwise null
$entity->reject(); // returns bool if the entity exists otherwise null
$entity->suspend(); // returns bool if the entity exists otherwise null
```

#### On `Builder` objects

[](#on-builder-objects)

You can update the status of more than one entity by using provided methods on `Builder`objects.

```
Entity::whereIn('id', $updateIds)->approve(); // returns number of updated
Entity::whereIn('id', $updateIds)->reject(); // returns number of updated
Entity::whereIn('id', $updateIds)->suspend(); // returns number of updated
```

#### Approval Timestamp

[](#approval-timestamp)

When you change the approval status of an entity its `approval_at` column updates. Before the first approval action on an entity its`approval_at` is `null`.

### Check the status of an entity

[](#check-the-status-of-an-entity)

You can check the status of an entity using provided methods on `Model` objects.

```
$entity->isApproved(); // returns bool if entity exists otherwise null
$entity->isRejected(); // returns bool if entity exists otherwise null
$entity->isPending(); // returns bool if entity exists otherwise null
```

### Approval Events

[](#approval-events)

There are some model events that are dispatched before and after each approval action.

ActionBeforeAfterapproveapprovingapprovedsuspendsuspendingsuspendedrejectrejectingrejectedAlso, there is a general event named `approvalChanged` that is dispatched whenever the approval status is changed regardless of the actual status.

You can hook to them by calling the provided `static` methods, which are named after them, and passing your callbacks. Or by registring observers with methods with the same names.

```
use Illuminate\Database\Eloquent\Model;
use Mtvs\EloquentApproval\Approvable;

class Entity extends Model
{
    use Approvable;

    protected static function boot()
    {
        parent::boot();

        static::approving(function ($entity) {
            // You can halt the process by returning false
        });

        static::approved(function ($entity) {
            // $entity has been approved
        });

        // or:

        static::observe(ApprovalObserver::class);
    }
}

class ApprovalObserver
{
    public function approving($entity)
    {
        // You can halt the process by returning false
    }

    public function approved($entity)
    {
        // $entity has been approved
    }
}
```

[Eloquent model events](https://laravel.com/docs/eloquent#events) can also be mapped to your application event classes.

Duplicate Approvals
-------------------

[](#duplicate-approvals)

Trying to set the approval status to the current value is ignored, i.e.: no event will be dispatched and the approval timestamp won't be updated. In this case the approval method returns `false`.

The Model Factory
-----------------

[](#the-model-factory)

Import the `ApprovalFactoryStates` to be able to use the approval states when using the model factory.

```
    namespace Database\Factories;

    use Illuminate\Database\Eloquent\Factories\Factory;
    use Mtvs\EloquentApproval\ApprovalFactoryStates;

    class EntityFactory extends Factory
    {
        use ApprovalFactoryStates;

        public function definition()
        {
            //
        }
    }
```

```
    Entity::factory()->approved()->create();
    Entity::factory()->rejected()->create();
    Entity::factory()->suspended()->create();
```

Handling Approval HTTP Requests
-------------------------------

[](#handling-approval-http-requests)

You can import the `HandlesApproval` in a controller to perform the approval operations on a model. It contains an abstract method which has to be implemented to return the model's class name.

```
    namespace App\Http\Controllers\Admin;

    use App\Http\Controllers\Controller;
    use App\Models\Entity;
    use Mtvs\EloquentApproval\HandlesApproval;

    class EntitiesController extends Controller
    {
        use HandlesApproval;

        protected function model()
        {
            return Entity::class;
        }
    }
```

The trait's `performApproval()` does the approval and the request should be routed to this method. It has the `key` and `request` parameters which are passed to it by the router.

When do the routing, don't forget to apply the `auth` and `can` middlewares for authentication and authourization.

```
    Route::post(
        'admin/enitiy/{key}/approval',
        'Admin\EntitiesController@performApproval'
    )->middleware(['auth', 'can:perform-approval'])
```

The request must have a `approval_status` key with one of the possible values: `approved`, `pending`, `rejected`.

Frontend Components
-------------------

[](#frontend-components)

There are also some UI components here written for Vue.js and Bootstrap that you can use. First install them using the `approval:ui` artisan command and then register them in your app.js file.

### Approval Buttons Component

[](#approval-buttons-component)

Call `` and pass the `current-status` and the `approval-url`props to be able to make HTTP requests to set the approval status.

It emits the `approval-changed` event when an approval action happens. The payload of the event is an object with the new `approval_status` and `approval_at` values. Use the event to modify the corresponding keys on the `entity` that in turn should change the `current-status` prop on the following cycle.

### Approval Status Component

[](#approval-status-component)

Call `` and pass the `value` prop to show the current status.

Inspirations
------------

[](#inspirations)

When I was searching for an existing package for approval functionality on eloquent models I encountered [hootlex/laravel-moderation](https://github.com/hootlex/laravel-moderation)even though I decided to write my own package I got some helpful inspirations from that one.

I also wrote different parts of the code following the way that similar parts of [Eloquent](https://github.com/laravel/framework/tree/master/src/Illuminate/Database/Eloquent) itself is written.

###  Health Score

43

—

FairBetter than 91% of packages

Maintenance20

Infrequent updates — may be unmaintained

Popularity43

Moderate usage in the ecosystem

Community18

Small or concentrated contributor base

Maturity74

Established project with proven stability

 Bus Factor1

Top contributor holds 98.1% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~70 days

Recently: every ~63 days

Total

28

Last Release

1186d ago

Major Versions

v1.7.1 → v2.0.02021-07-25

v2.0.0 → v3.0.02022-02-20

v3.0.1 → v4.0.02022-04-21

v3.0.2 → v4.0.12022-06-01

v4.x-dev → v5.0.02022-06-08

PHP version history (4 changes)v1.0.0-beta.1PHP ^5.6 || ^7.0

v1.0.1PHP ^7.0

v1.4.0PHP ^7.1

v1.7.1PHP ^7.1|^8.0

### Community

Maintainers

![](https://www.gravatar.com/avatar/f02aa2b87486bfd83077bcc587ccc5891ddf49d1dfe834e2ac749d81537b2cce?d=identicon)[mtvs](/maintainers/mtvs)

---

Top Contributors

[![mtvs](https://avatars.githubusercontent.com/u/8286154?v=4)](https://github.com/mtvs "mtvs (102 commits)")[![rickmills](https://avatars.githubusercontent.com/u/103707?v=4)](https://github.com/rickmills "rickmills (1 commits)")[![roerlemans](https://avatars.githubusercontent.com/u/14876955?v=4)](https://github.com/roerlemans "roerlemans (1 commits)")

---

Tags

approvalapproval-processeloquenteloquent-modelslaravellaravel-packagelaraveleloquentapproval

###  Code Quality

TestsPHPUnit

### Embed Badge

![Health badge](/badges/mtvs-eloquent-approval/health.svg)

```
[![Health](https://phpackages.com/badges/mtvs-eloquent-approval/health.svg)](https://phpackages.com/packages/mtvs-eloquent-approval)
```

###  Alternatives

[cviebrock/eloquent-sluggable

Easy creation of slugs for your Eloquent models in Laravel

4.0k13.6M253](/packages/cviebrock-eloquent-sluggable)[tucker-eric/eloquentfilter

An Eloquent way to filter Eloquent Models

1.8k4.8M26](/packages/tucker-eric-eloquentfilter)[watson/validating

Eloquent model validating trait.

9723.3M47](/packages/watson-validating)[cybercog/laravel-ban

Laravel Ban simplify blocking and banning Eloquent models.

1.1k651.8k11](/packages/cybercog-laravel-ban)[cybercog/laravel-love

Make Laravel Eloquent models reactable with any type of emotions in a minutes!

1.2k302.7k1](/packages/cybercog-laravel-love)[cviebrock/eloquent-taggable

Easy ability to tag your Eloquent models in Laravel.

567694.8k3](/packages/cviebrock-eloquent-taggable)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
