PHPackages                             spatie/laravel-model-status - 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. spatie/laravel-model-status

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

spatie/laravel-model-status
===========================

A package to enable assigning statuses to Eloquent Models

1.20.0(2mo ago)1.1k1.7M—4.7%8416MITPHPPHP ^8.2CI passing

Since Feb 6Pushed 2mo ago14 watchersCompare

[ Source](https://github.com/spatie/laravel-model-status)[ Packagist](https://packagist.org/packages/spatie/laravel-model-status)[ Docs](https://github.com/spatie/laravel-model-status)[ Fund](https://spatie.be/open-source/support-us)[ RSS](/packages/spatie-laravel-model-status/feed)WikiDiscussions main Synced 1mo ago

READMEChangelog (10)Dependencies (3)Versions (41)Used By (16)

Assign statuses to Eloquent models
==================================

[](#assign-statuses-to-eloquent-models)

[![Latest Version on Packagist](https://camo.githubusercontent.com/d19d97d838b2db7cd8e69f5181360458e49c2c9cb413565c25a72b8d29a32972/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f7370617469652f6c61726176656c2d6d6f64656c2d7374617475732e7376673f7374796c653d666c61742d737175617265)](https://packagist.org/packages/spatie/laravel-model-status)[![GitHub Workflow Status](https://camo.githubusercontent.com/8848cfd403c633b8aac89bec16ae3320809ebb44eb47301571ee0101b7bc2ded/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f616374696f6e732f776f726b666c6f772f7374617475732f7370617469652f6c61726176656c2d6d6f64656c2d7374617475732f72756e2d74657374732e796d6c3f6272616e63683d6d61696e266c6162656c3d7465737473267374796c653d666c61742d737175617265)](https://camo.githubusercontent.com/8848cfd403c633b8aac89bec16ae3320809ebb44eb47301571ee0101b7bc2ded/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f616374696f6e732f776f726b666c6f772f7374617475732f7370617469652f6c61726176656c2d6d6f64656c2d7374617475732f72756e2d74657374732e796d6c3f6272616e63683d6d61696e266c6162656c3d7465737473267374796c653d666c61742d737175617265)[![Check & fix styling](https://github.com/spatie/laravel-model-status/workflows/Check%20&%20fix%20styling/badge.svg)](https://github.com/spatie/laravel-model-status/workflows/Check%20&%20fix%20styling/badge.svg)[![Total Downloads](https://camo.githubusercontent.com/cb8a964063be2251a72c59516dead183ef5e8aa09ea75d5edbc783439b1845d9/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f64742f7370617469652f6c61726176656c2d6d6f64656c2d7374617475732e7376673f7374796c653d666c61742d737175617265)](https://packagist.org/packages/spatie/laravel-model-status)

Imagine you want to have an Eloquent model hold a status. It's easily solved by just adding a `status` field to that model and be done with it. But in case you need a history of status changes or need to store some extra info on why a status changed, just adding a single field won't cut it.

This package provides a `HasStatuses` trait that, once installed on a model, allows you to do things like this:

```
// set a status
$model->setStatus('pending', 'needs verification');

// set a status using an enum
$model->setStatus(UserStatus::pending);

// set another status
$model->setStatus('accepted');

// specify a reason
$model->setStatus('rejected', 'My rejection reason');

// get the current status
$model->status(); // returns an instance of \Spatie\ModelStatus\Status

// get the previous status
$latestPendingStatus = $model->latestStatus('pending');

$latestPendingStatus->reason; // returns 'needs verification'
```

Support us
----------

[](#support-us)

[![](https://camo.githubusercontent.com/637c578ee0cf25b9ffcea6dd5ac652e6a2239353390c473ce9d8b6f8fdaedf29/68747470733a2f2f6769746875622d6164732e73332e65752d63656e7472616c2d312e616d617a6f6e6177732e636f6d2f6c61726176656c2d6d6f64656c2d7374617475732e6a70673f743d31)](https://spatie.be/github-ad-click/laravel-model-status)

We invest a lot of resources into creating [best in class open source packages](https://spatie.be/open-source). You can support us by [buying one of our paid products](https://spatie.be/open-source/support-us).

We highly appreciate you sending us a postcard from your hometown, mentioning which of our package(s) you are using. You'll find our address on [our contact page](https://spatie.be/about-us). We publish all received postcards on [our virtual postcard wall](https://spatie.be/open-source/postcards).

Installation
------------

[](#installation)

You can install the package via composer:

```
composer require spatie/laravel-model-status
```

You must publish the migration with:

```
php artisan vendor:publish --provider="Spatie\ModelStatus\ModelStatusServiceProvider" --tag="migrations"
```

Migrate the `statuses` table:

```
php artisan migrate
```

Optionally you can publish the config-file with:

```
php artisan vendor:publish --provider="Spatie\ModelStatus\ModelStatusServiceProvider" --tag="config"
```

This is the contents of the file which will be published at `config/model-status.php`

```
return [

    /*
     * The class name of the status model that holds all statuses.
     *
     * The model must be or extend `Spatie\ModelStatus\Status`.
     */
    'status_model' => Spatie\ModelStatus\Status::class,

    /*
     * The name of the column which holds the ID of the model related to the statuses.
     *
     * You can change this value if you have set a different name in the migration for the statuses table.
     */
    'model_primary_key_attribute' => 'model_id',

];
```

Usage
-----

[](#usage)

Add the `HasStatuses` trait to a model you like to use statuses on.

```
use Spatie\ModelStatus\HasStatuses;

class YourEloquentModel extends Model
{
    use HasStatuses;
}
```

### Set a new status

[](#set-a-new-status)

You can set a new status like this:

```
$model->setStatus('status-name');
```

A reason for the status change can be passed as a second argument.

```
$model->setStatus('status-name', 'optional reason');
```

`setStatus` and `forceSetStatus` also accept enums:

```
enum UserStatus: string
{
    case pending = 'pending';
    case accepted = 'accepted';
}

$model->setStatus(UserStatus::pending);
```

Backed enums are stored using their value. Unit enums are stored using their case name.

### Restrict statuses to an enum

[](#restrict-statuses-to-an-enum)

You can restrict which statuses a model accepts by overriding the `statusEnumClass` method:

```
class YourEloquentModel extends Model
{
    use HasStatuses;

    public function statusEnumClass(): ?string
    {
        return UserStatus::class;
    }
}
```

When `statusEnumClass()` returns an enum class, `setStatus(...)` only accepts statuses that belong to that enum. `forceSetStatus(...)` always bypasses this validation.

### Retrieving statuses

[](#retrieving-statuses)

You can get the current status of model:

```
$model->status; // returns a string with the name of the latest status

$model->status(); // returns the latest instance of `Spatie\ModelStatus\Status`

$model->latestStatus(); // equivalent to `$model->status()`

$model->statusEnum(); // returns the latest enum case when statusEnumClass() is configured, otherwise null
```

`statusEnum()` also returns `null` when there is no status yet, or when the latest stored status does not map to the configured enum.

You can also get latest status of a given name:

```
$model->latestStatus('pending'); // returns an instance of `Spatie\ModelStatus\Status` that has the name `pending`
```

Get all available status names for the model.

```
$statusNames = $model->getStatusNames(); // returns a collection of all available status names.
```

The following examples will return statusses of type `status 1` or `status 2`, whichever is latest.

```
$lastStatus = $model->latestStatus(['status 1', 'status 2']);

// or alternatively...
$lastStatus = $model->latestStatus('status 1', 'status 2');
```

All associated statuses of a model can be retrieved like this:

```
$allStatuses = $model->statuses;
```

This will check if the model has status:

```
$model->setStatus('status1');

$isStatusExist = $model->hasStatus('status1'); // return true
$isStatusExist = $model->hasStatus('status2'); // return false
```

### Retrieving models with a given latest state

[](#retrieving-models-with-a-given-latest-state)

The `currentStatus` scope will return models that have a status with the given name.

```
$allPendingModels = Model::currentStatus('pending');

//or array of statuses
$allPendingModels = Model::currentStatus(['pending', 'initiated']);
$allPendingModels = Model::currentStatus('pending', 'initiated');
```

### Retrieving models without a given state

[](#retrieving-models-without-a-given-state)

The `otherCurrentStatus` scope will return all models that do not have a status with the given name, including any model that does not have any statuses associated with them.

```
$allNonPendingModels = Model::otherCurrentStatus('pending');
```

You can also provide an array of status names to exclude from the query.

```
$allNonInitiatedOrPendingModels = Model::otherCurrentStatus(['initiated', 'pending']);

// or alternatively...
$allNonInitiatedOrPendingModels = Model::otherCurrentStatus('initiated', 'pending');
```

### Validating a status before setting it

[](#validating-a-status-before-setting-it)

You can add custom validation when setting a status by overwriting the `isValidStatus` method:

```
public function isValidStatus(string $name, ?string $reason = null): bool
{
    ...

    if (! $condition) {
        return false;
    }

    return true;
}
```

If `isValidStatus` returns `false` a `Spatie\ModelStatus\Exceptions\InvalidStatus` exception will be thrown.

You may bypass validation with the `forceSetStatus` method:

```
$model->forceSetStatus('invalid-status-name');
```

### Check if status has been assigned

[](#check-if-status-has-been-assigned)

You can check if a specific status has been set on the model at any time by using the `hasEverHadStatus` method:

```
$model->hasEverHadStatus('status 1');
```

### Check if status has never been assigned

[](#check-if-status-has-never-been-assigned)

You can check if a specific status has never been set on the model at any time by using the `hasNeverHadStatus` method:

```
$model->hasNeverHadStatus('status 1');
```

### Delete status from model

[](#delete-status-from-model)

You can delete any given status that has been set on the model at any time by using the `deleteStatus` method:

Delete single status from model:

```
$model->deleteStatus('status 1');
```

Delete multiple statuses from model at once:

```
$model->deleteStatus(['status 1', 'status 2']);
```

### Events

[](#events)

The`Spatie\ModelStatus\Events\StatusUpdated` event will be dispatched when the status is updated.

```
namespace Spatie\ModelStatus\Events;

use Illuminate\Database\Eloquent\Model;
use Spatie\ModelStatus\Status;

class StatusUpdated
{
    /** @var \Spatie\ModelStatus\Status|null */
    public $oldStatus;

    /** @var \Spatie\ModelStatus\Status */
    public $newStatus;

    /** @var \Illuminate\Database\Eloquent\Model */
    public $model;

    public function __construct(?Status $oldStatus, Status $newStatus, Model $model)
    {
        $this->oldStatus = $oldStatus;

        $this->newStatus = $newStatus;

        $this->model = $model;
    }
}
```

### Custom model and migration

[](#custom-model-and-migration)

You can change the model used by specifying a class name in the `status_model` key of the `model-status` config file.

You can change the column name used in the status table (`model_id` by default) when using a custom migration where you changed that. In that case, simply change the `model_primary_key_attribute` key of the `model-status` config file.

### Testing

[](#testing)

This package contains integration tests that are powered by [orchestral/testbench](https://github.com/orchestral/testbench).

You can run all tests with:

```
composer test
```

### Changelog

[](#changelog)

Please see [CHANGELOG](CHANGELOG.md) for more information what has changed recently.

Contributing
------------

[](#contributing)

Please see [CONTRIBUTING](https://github.com/spatie/.github/blob/main/CONTRIBUTING.md) for details.

### Security

[](#security)

If you've found a bug regarding security please mail  instead of using the issue tracker.

Credits
-------

[](#credits)

- [Thomas Verhelst](https://github.com/TVke)
- [Freek Van der Herten](https://github.com/freekmurze)
- [All Contributors](../../contributors)

License
-------

[](#license)

The MIT License (MIT). Please see [License File](LICENSE.md) for more information.

###  Health Score

73

—

ExcellentBetter than 100% of packages

Maintenance83

Actively maintained with recent releases

Popularity65

Solid adoption and visibility

Community41

Growing community involvement

Maturity88

Battle-tested with a long release history

 Bus Factor1

Top contributor holds 54.2% 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 ~75 days

Recently: every ~165 days

Total

40

Last Release

86d ago

Major Versions

0.0.1 → 1.0.02018-02-07

PHP version history (6 changes)0.0.1PHP ^7.1

1.7.0PHP ^7.2

1.10.2PHP ^7.2|^8.0

1.11.0PHP ^8.0

1.11.1PHP ^8.0|^8.1

1.15.0PHP ^8.2

### Community

Maintainers

![](https://avatars.githubusercontent.com/u/7535935?v=4)[Spatie](/maintainers/spatie)[@spatie](https://github.com/spatie)

---

Top Contributors

[![freekmurze](https://avatars.githubusercontent.com/u/483853?v=4)](https://github.com/freekmurze "freekmurze (148 commits)")[![vpratfr](https://avatars.githubusercontent.com/u/2526465?v=4)](https://github.com/vpratfr "vpratfr (23 commits)")[![TVke](https://avatars.githubusercontent.com/u/15680337?v=4)](https://github.com/TVke "TVke (14 commits)")[![alexmanase](https://avatars.githubusercontent.com/u/10696975?v=4)](https://github.com/alexmanase "alexmanase (12 commits)")[![laravel-shift](https://avatars.githubusercontent.com/u/15991828?v=4)](https://github.com/laravel-shift "laravel-shift (10 commits)")[![AdrianMrn](https://avatars.githubusercontent.com/u/12762044?v=4)](https://github.com/AdrianMrn "AdrianMrn (7 commits)")[![patinthehat](https://avatars.githubusercontent.com/u/5508707?v=4)](https://github.com/patinthehat "patinthehat (7 commits)")[![AlexVanderbist](https://avatars.githubusercontent.com/u/6287961?v=4)](https://github.com/AlexVanderbist "AlexVanderbist (5 commits)")[![lostincode](https://avatars.githubusercontent.com/u/565885?v=4)](https://github.com/lostincode "lostincode (5 commits)")[![pascalbaljet](https://avatars.githubusercontent.com/u/8403149?v=4)](https://github.com/pascalbaljet "pascalbaljet (4 commits)")[![rubenvanassche](https://avatars.githubusercontent.com/u/619804?v=4)](https://github.com/rubenvanassche "rubenvanassche (4 commits)")[![sebastiandedeyne](https://avatars.githubusercontent.com/u/1561079?v=4)](https://github.com/sebastiandedeyne "sebastiandedeyne (4 commits)")[![alfreddagenais](https://avatars.githubusercontent.com/u/5769264?v=4)](https://github.com/alfreddagenais "alfreddagenais (3 commits)")[![alhelwany](https://avatars.githubusercontent.com/u/115778766?v=4)](https://github.com/alhelwany "alhelwany (3 commits)")[![YazeedAlsaif](https://avatars.githubusercontent.com/u/3579831?v=4)](https://github.com/YazeedAlsaif "YazeedAlsaif (3 commits)")[![therouv](https://avatars.githubusercontent.com/u/393419?v=4)](https://github.com/therouv "therouv (3 commits)")[![brendt](https://avatars.githubusercontent.com/u/6905297?v=4)](https://github.com/brendt "brendt (3 commits)")[![M1crogravity](https://avatars.githubusercontent.com/u/47523539?v=4)](https://github.com/M1crogravity "M1crogravity (2 commits)")[![polmtn](https://avatars.githubusercontent.com/u/58864942?v=4)](https://github.com/polmtn "polmtn (2 commits)")[![Rizky92](https://avatars.githubusercontent.com/u/18244409?v=4)](https://github.com/Rizky92 "Rizky92 (1 commits)")

---

Tags

eloquentlaravelmodelphpstatusspatielaravel-status

###  Code Quality

TestsPest

### Embed Badge

![Health badge](/badges/spatie-laravel-model-status/health.svg)

```
[![Health](https://phpackages.com/badges/spatie-laravel-model-status/health.svg)](https://phpackages.com/packages/spatie-laravel-model-status)
```

###  Alternatives

[spatie/laravel-backup

A Laravel package to backup your application

6.0k21.8M191](/packages/spatie-laravel-backup)[spatie/laravel-medialibrary

Associate files with Eloquent models

6.1k37.7M472](/packages/spatie-laravel-medialibrary)[spatie/laravel-sluggable

Generate slugs when saving Eloquent models

1.6k11.5M223](/packages/spatie-laravel-sluggable)[spatie/laravel-translatable

A trait to make an Eloquent model hold translations

2.4k23.0M413](/packages/spatie-laravel-translatable)[spatie/laravel-db-snapshots

Quickly dump and load databases

1.2k2.8M20](/packages/spatie-laravel-db-snapshots)[spatie/laravel-schemaless-attributes

Add schemaless attributes to Eloquent models

1.1k8.7M62](/packages/spatie-laravel-schemaless-attributes)

PHPackages © 2026

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