Skip to content

Commit

Permalink
implement enum based statuses
Browse files Browse the repository at this point in the history
  • Loading branch information
alhelwany committed Apr 21, 2024
1 parent 27b69f8 commit b20d72c
Show file tree
Hide file tree
Showing 12 changed files with 302 additions and 190 deletions.
84 changes: 50 additions & 34 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,19 +11,22 @@ This package provides a `HasStatuses` trait that, once installed on a model, all

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

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

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

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

//get the current status
$model->status; //returns an instance of the status enum

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

$latestPendingStatus->reason; // returns 'needs verification'
```
Expand Down Expand Up @@ -84,14 +87,31 @@ return [

## Usage

Add the `HasStatuses` trait to a model you like to use statuses on.
Create The Enum that holds all of your available statuses for the model. \
The enum must be string backed

```php
enum ModelStatusEnum: string
{
case PENDING = "pending";
case APPROVED = "approved";
case REJECTED = "rejected";
}
```

Add the `HasStatuses` trait to a model you like to use statuses on and implement the abstract function getStatusEnumClass. Inside, you must return the class name of the enum you desire to use with this model.

```php
use Spatie\ModelStatus\HasStatuses;

class YourEloquentModel extends Model
{
use HasStatuses;

public static function getStatusEnumClass(): string
{
return ModelStatusEnum::class;
}
}
```

Expand All @@ -100,45 +120,41 @@ class YourEloquentModel extends Model
You can set a new status like this:

```php
$model->setStatus('status-name');
$model->setStatus(ModelStatusEnum::PENDING);
```

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

```php
$model->setStatus('status-name', 'optional reason');
$model->setStatus(ModelStatusEnum::APPROVED, 'optional reason');
```

### Retrieving statuses

You can get the current status of model:

```php
$model->status; // returns a string with the name of the latest status
$model->status; // returns an enum instance of the latest status assigned to the model

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

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

You can also get latest status of a given name:
You can also get latest status of a given value:

```php
$model->latestStatus('pending'); // returns an instance of `Spatie\ModelStatus\Status` that has the name `pending`
$model->latestStatus(ModelStatusEnum::APPROVED); // returns an instance of `Spatie\ModelStatus\Status` that has the value `approved`
```
Get all available status names for the model.

```php
$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.
The following examples will return statusses of type APPROVED or REJECTED, whichever is latest.

```php
$lastStatus = $model->latestStatus(['status 1', 'status 2']);
$lastStatus = $model->latestStatus([ModelStatusEnum::APPROVED, ModelStatusEnum::REJECTED]);

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

All associated statuses of a model can be retrieved like this:
Expand All @@ -149,45 +165,45 @@ $allStatuses = $model->statuses;
This will check if the model has status:

```php
$model->setStatus('status1');
$model->setStatus(ModelStatusEnum::APPROVED);

$isStatusExist = $model->hasStatus('status1'); // return true
$isStatusExist = $model->hasStatus('status2'); // return false
$isStatusExist = $model->hasStatus(ModelStatusEnum::APPROVED); // return true
$isStatusExist = $model->hasStatus(ModelStatusEnum::REJECTED); // return false
```
### Retrieving models with a given latest state

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

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

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

### Retrieving models without a given state
### Retrieving models without a given status

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.

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

You can also provide an array of status names to exclude from the query.
```php
$allNonInitiatedOrPendingModels = Model::otherCurrentStatus(['initiated', 'pending']);
$allNonPendingOrRejectedModels = Model::otherCurrentStatus([ModelStatusEnum::PENDING, ModelStatusEnum::REJECTED]);

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

### Validating a status before setting it

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

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

Expand All @@ -204,15 +220,15 @@ If `isValidStatus` returns `false` a `Spatie\ModelStatus\Exceptions\InvalidStatu
You may bypass validation with the `forceSetStatus` method:

```php
$model->forceSetStatus('invalid-status-name');
$model->forceSetStatus(ModelStatusEnum::PENDING);
```

### 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:

```php
$model->hasEverHadStatus('status 1');
$model->hasEverHadStatus(ModelStatusEnum::APPROVED);
```

### Delete status from model
Expand All @@ -222,13 +238,13 @@ You can delete any given status that has been set on the model at any time by us
Delete single status from model:

```php
$model->deleteStatus('status 1');
$model->deleteStatus(ModelStatusEnum::REJECTED);
```

Delete multiple statuses from model at once:

```php
$model->deleteStatus(['status 1', 'status 2']);
$model->deleteStatus([ModelStatusEnum::PENDING, ModelStatusEnum::REJECTED]);
```

### Events
Expand Down
13 changes: 13 additions & 0 deletions src/Exceptions/InvalidEnumClass.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<?php

namespace Spatie\ModelStatus\Exceptions;

use Exception;

class InvalidEnumClass extends Exception
{
public static function create(string $statusEnum): self
{
return new self("The status is not of type $statusEnum");
}
}
13 changes: 13 additions & 0 deletions src/Exceptions/InvalidEnumType.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<?php

namespace Spatie\ModelStatus\Exceptions;

use Exception;

class InvalidEnumType extends Exception
{
public static function create(string $statusEnumClass): self
{
return new self("Enum `{$statusEnumClass}` must be a string backed Enum");
}
}
Loading

0 comments on commit b20d72c

Please sign in to comment.