PHPackages                             soylentgreenstudio/laravel-enum-states - 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. soylentgreenstudio/laravel-enum-states

ActiveLibrary

soylentgreenstudio/laravel-enum-states
======================================

A state machine library for Laravel using native PHP 8.1 Backed Enums as the single source of truth.

v1.2.2(1mo ago)44↑2900%MITPHPPHP ^8.1

Since Mar 16Pushed 1mo agoCompare

[ Source](https://github.com/soylentgreenstudio/laravel-enum-states)[ Packagist](https://packagist.org/packages/soylentgreenstudio/laravel-enum-states)[ RSS](/packages/soylentgreenstudio-laravel-enum-states/feed)WikiDiscussions main Synced 1mo ago

READMEChangelogDependencies (4)Versions (7)Used By (0)

soylentgreenstudio/laravel-enum-states
======================================

[](#soylentgreenstudiolaravel-enum-states)

[![License: MIT](https://camo.githubusercontent.com/08cef40a9105b6526ca22088bc514fbfdbc9aac1ddbf8d4e6c750e3a88a44dca/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f4c6963656e73652d4d49542d626c75652e737667)](LICENSE.md)[![Laravel](https://camo.githubusercontent.com/8d05621a93ebe2a005d07b66cf72e6bd6af781566fb702daba60710d39c9c0a9/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f4c61726176656c2d31302e782d2d31322e782d7265642e737667)](https://laravel.com)[![PHP](https://camo.githubusercontent.com/fb7c72456e13f7d5ecf8486e29d02a2e6775aaf4d18622a63529976b0ed0740e/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f5048502d382e312532422d707572706c652e737667)](https://www.php.net)

**A state machine library for Laravel using native PHP 8.1 Backed Enums as the single source of truth.**

Declare states, transitions, guards, and hooks via PHP Attributes directly on your Enum — no separate state classes, no config files, no boilerplate.

Table of Contents
-----------------

[](#table-of-contents)

- [Quick Start](#quick-start)
- [Features](#features)
- [Installation](#installation)
- [Architecture](#architecture)
- [Enum Definition](#enum-definition)
- [Model Setup](#model-setup)
- [Transitioning States](#transitioning-states)
- [Guards](#guards)
- [Hooks](#hooks)
- [Transition History](#transition-history)
- [Query Scopes](#query-scopes)
- [Events](#events)
- [Artisan Commands](#artisan-commands)
- [Async Hooks](#async-hooks)
- [Testing](#testing)
- [Comparison with Alternatives](#comparison-with-alternatives)
- [API Reference](#api-reference)
- [License](#license)

Quick Start
-----------

[](#quick-start)

```
composer require soylentgreenstudio/laravel-enum-states
php artisan vendor:publish --provider="SoylentGreenStudio\EnumStates\EnumStatesServiceProvider"
php artisan migrate
```

```
// 1. Define your enum with attributes
enum OrderStatus: string
{
    #[InitialState]
    #[Transition(to: [self::Processing, self::Cancelled])]
    case Pending = 'pending';

    #[Transition(to: [self::Shipped, self::Cancelled])]
    case Processing = 'processing';

    #[FinalState]
    case Shipped = 'shipped';

    #[FinalState]
    case Cancelled = 'cancelled';
}

// 2. Add the trait to your model — that's it
class Order extends Model
{
    use HasStateMachines;

    protected $casts = [
        'status' => OrderStatus::class,
    ];
}

// 3. Transition states
$order->transitionTo(OrderStatus::Processing);
$order->transitionTo(OrderStatus::Shipped, ['tracking' => 'ABC123']);

// 4. Check if transition is allowed (never throws)
$order->canTransitionTo(OrderStatus::Cancelled); // bool

// 5. Query by state
Order::whereState('status', OrderStatus::Pending)->get();

// 6. View transition history
$order->stateHistory('status');
```

Features
--------

[](#features)

FeatureDescription**Enum-driven**States and transitions declared via PHP Attributes on Backed Enums**Zero config**Trait auto-detects state machine fields from `$casts` — no registration needed**Guards**Control whether a transition is allowed via `TransitionGuard` contract**Hooks**Run logic before/after transition via `TransitionHook` contract**Transition history**Every transition recorded in `state_transitions` table with metadata**Query scopes**`whereState`, `whereNotState`, `whereStateIn` — filter models by state**Events**`TransitionStarted`, `TransitionCompleted`, `TransitionFailed` fired automatically**Multiple state machines**One model can have multiple state fields, each independent**DB transactions**Transitions are wrapped in `DB::transaction()` — hooks and state update are atomic**Initial / Final states**Mark states with `#[InitialState]` and `#[FinalState]` attributes**Metadata**Pass arbitrary data with each transition — stored in history as JSON**Async hooks**Dispatch hooks to queues via `AsyncTransitionHook` — fire-and-forget before, post-commit after**Artisan commands**`enum-states:graph`, `make:enum-state`, `make:transition-guard` for visualization and scaffolding**Container resolution**Guards and hooks are resolved via Laravel's service container — inject dependencies freelyInstallation
------------

[](#installation)

### Requirements

[](#requirements)

- PHP 8.1+
- Laravel 10.x — 12.x

### Install

[](#install)

```
composer require soylentgreenstudio/laravel-enum-states
```

### Publish and run migration

[](#publish-and-run-migration)

```
php artisan vendor:publish --provider="SoylentGreenStudio\EnumStates\EnumStatesServiceProvider"
php artisan migrate
```

This creates the `state_transitions` table used for transition history.

Architecture
------------

[](#architecture)

### Transition lifecycle

[](#transition-lifecycle)

```
$order->transitionTo(OrderStatus::Processing, $metadata)
  └─ StateMachineManager::transition()
      ├─ 1. Check current state is not #[FinalState]  → FinalStateException
      ├─ 2. Find matching #[Transition] attribute      → InvalidTransitionException
      ├─ 3. Resolve and run Guard via app()->make()    → InvalidTransitionException
      ├─ 4. Fire TransitionStarted event
      └─ 5. DB::transaction()
            ├─ Run `before` hook
            ├─ Update model field + save
            ├─ Write record to state_transitions table
            └─ Run `after` hook
      ├─ 6. Fire TransitionCompleted event
      └─ On exception: Fire TransitionFailed event, re-throw

```

### How auto-detection works

[](#how-auto-detection-works)

The `HasStateMachines` trait inspects the model's `$casts` array on first access:

1. For each cast that points to a `BackedEnum` class
2. Check if any case on that enum has `#[Transition]`, `#[InitialState]`, or `#[FinalState]` attributes
3. Register those fields as managed state machines

No manual field registration required.

### Database schema

[](#database-schema)

The `state_transitions` table stores full transition history:

ColumnTypeDescription`id`bigintPrimary key`model_type`stringMorphable model class`model_id`bigintMorphable model ID`field`stringField name (e.g. `status`)`from`stringPrevious state value`to`stringNew state value`metadata`json, nullableArbitrary data passed with the transition`transitioned_at`timestampWhen the transition occurred`created_at`timestampRecord creation timeEnum Definition
---------------

[](#enum-definition)

Define your states as a PHP 8.1 Backed Enum. Use attributes to declare the state machine behavior:

```
use SoylentGreenStudio\EnumStates\Attributes\InitialState;
use SoylentGreenStudio\EnumStates\Attributes\FinalState;
use SoylentGreenStudio\EnumStates\Attributes\Transition;

enum OrderStatus: string
{
    #[InitialState]
    #[Transition(
        to: [self::Processing, self::Cancelled],
        guard: HasItemsInStock::class,
        after: SendOrderConfirmation::class,
    )]
    case Pending = 'pending';

    #[Transition(
        to: [self::Shipped, self::Cancelled],
        before: ValidateShippingAddress::class,
    )]
    case Processing = 'processing';

    #[FinalState]
    case Shipped = 'shipped';

    #[FinalState]
    case Cancelled = 'cancelled';
}
```

### Attribute reference

[](#attribute-reference)

AttributeTargetDescription`#[InitialState]`Enum caseMarks the default/starting state`#[FinalState]`Enum caseMarks a terminal state — no transitions allowed from it`#[Transition]`Enum case (repeatable)Declares allowed transitions from this state### Transition attribute parameters

[](#transition-attribute-parameters)

ParameterTypeDefaultDescription`to``array`requiredArray of enum cases this state can transition to`guard``?string``null`FQCN of a `TransitionGuard` implementation`before``?string``null`FQCN of a `TransitionHook` or `AsyncTransitionHook` — runs before persisting`after``?string``null`FQCN of a `TransitionHook` or `AsyncTransitionHook` — runs after persistingThe `#[Transition]` attribute is repeatable — you can define multiple transition groups on a single case with different guards/hooks:

```
#[Transition(to: [self::Approved], guard: ManagerApproval::class)]
#[Transition(to: [self::Rejected], guard: CanReject::class)]
case Pending = 'pending';
```

Model Setup
-----------

[](#model-setup)

Add the `HasStateMachines` trait and cast your state fields to the enum:

```
use SoylentGreenStudio\EnumStates\Traits\HasStateMachines;

class Order extends Model
{
    use HasStateMachines;

    protected $casts = [
        'status'         => OrderStatus::class,
        'payment_status' => PaymentStatus::class,
    ];
}
```

That's it. The trait auto-detects which cast fields are Backed Enums with state machine attributes. No `getStateMachineFields()` method needed.

Transitioning States
--------------------

[](#transitioning-states)

### Basic transition

[](#basic-transition)

```
$order->transitionTo(OrderStatus::Processing);
```

### With metadata

[](#with-metadata)

Metadata is stored in the transition history record:

```
$order->transitionTo(OrderStatus::Processing, [
    'reason'  => 'Payment confirmed',
    'user_id' => auth()->id(),
]);
```

### Explicit field name

[](#explicit-field-name)

When a model has multiple state machines, specify the field:

```
$order->transitionTo('payment_status', PaymentStatus::Paid, $metadata);
```

### Check before transitioning

[](#check-before-transitioning)

Returns `bool`, never throws:

```
if ($order->canTransitionTo(OrderStatus::Shipped)) {
    $order->transitionTo(OrderStatus::Shipped);
}
```

### Exception handling

[](#exception-handling)

ExceptionWhen`FinalStateException`Transitioning from a state marked `#[FinalState]``InvalidTransitionException`No `#[Transition]` allows the requested state change`InvalidTransitionException`Guard returned `false`Guards
------

[](#guards)

Guards control whether a transition is allowed. Implement the `TransitionGuard` contract:

```
use SoylentGreenStudio\EnumStates\Contracts\TransitionGuard;

class HasItemsInStock implements TransitionGuard
{
    public function allow(Model $model, array $metadata): bool
    {
        return $model->items()->where('in_stock', true)->exists();
    }
}
```

Guards are resolved via the Laravel service container — you can inject any dependencies via the constructor.

If a guard returns `false`, `transitionTo()` throws `InvalidTransitionException`.

### Guard with dependency injection

[](#guard-with-dependency-injection)

```
class HasSufficientBalance implements TransitionGuard
{
    public function __construct(
        private PaymentGateway $gateway,
    ) {}

    public function allow(Model $model, array $metadata): bool
    {
        return $this->gateway->getBalance($model->user_id) >= $model->total;
    }
}
```

Hooks
-----

[](#hooks)

Hooks run logic before or after a transition. Implement the `TransitionHook` contract:

```
use SoylentGreenStudio\EnumStates\Contracts\TransitionHook;

class SendOrderConfirmation implements TransitionHook
{
    public function handle(Model $model, mixed $from, mixed $to, array $metadata): void
    {
        Mail::to($model->user)->send(new OrderConfirmed($model));
    }
}
```

### Before vs After

[](#before-vs-after)

TypeWhen it runsOn exception`before`Before model is saved, inside DB transactionTransition is rolled back`after`After model is saved, inside same DB transactionTransition is rolled backBoth hooks receive the model, the `$from` and `$to` enum cases, and the metadata array.

### Hook with dependency injection

[](#hook-with-dependency-injection)

```
class NotifySlack implements TransitionHook
{
    public function __construct(
        private SlackClient $slack,
    ) {}

    public function handle(Model $model, mixed $from, mixed $to, array $metadata): void
    {
        $this->slack->send("Order #{$model->id} changed from {$from->name} to {$to->name}");
    }
}
```

Transition History
------------------

[](#transition-history)

Every transition is recorded in the `state_transitions` table:

```
// History for a specific field
$order->stateHistory('status');
// => Collection of StateTransition models

// History for all state machine fields
$order->stateHistory();
```

Each `StateTransition` record contains:

```
$transition->from;              // 'pending'
$transition->to;                // 'processing'
$transition->field;             // 'status'
$transition->metadata;          // ['reason' => 'Payment confirmed'] or null
$transition->transitioned_at;   // Carbon instance
$transition->created_at;        // Carbon instance
```

Query Scopes
------------

[](#query-scopes)

The `HasStateMachines` trait adds query scopes for filtering models by state:

```
// Exact match
Order::whereState('status', OrderStatus::Pending)->get();

// Exclude a state
Order::whereNotState('status', OrderStatus::Cancelled)->get();

// Match multiple states
Order::whereStateIn('status', [
    OrderStatus::Pending,
    OrderStatus::Processing,
])->get();
```

Events
------

[](#events)

Three events are fired automatically during each transition:

EventWhenPayload`TransitionStarted`Before DB transaction begins`$model`, `$field`, `$from`, `$to`, `$metadata``TransitionCompleted`After DB transaction commits`$model`, `$field`, `$from`, `$to`, `$metadata``TransitionFailed`On any exception (then re-thrown)`$model`, `$field`, `$from`, `$to`, `$exception`### Listening to events

[](#listening-to-events)

```
// In EventServiceProvider or via Event::listen()
use SoylentGreenStudio\EnumStates\Events\TransitionCompleted;

Event::listen(TransitionCompleted::class, function (TransitionCompleted $event) {
    Log::info("Order #{$event->model->id}: {$event->field} changed", [
        'from' => $event->from->value,
        'to'   => $event->to->value,
        'meta' => $event->metadata,
    ]);
});
```

Artisan Commands
----------------

[](#artisan-commands)

### Visualize State Graph

[](#visualize-state-graph)

```
php artisan enum-states:graph "App\Enums\OrderStatus"
```

Output:

```
OrderStatus State Graph
========================
[Initial] Pending
  → Processing (guard: HasItemsInStock)
  → Cancelled
Processing
  → Shipped (before: ValidateShippingAddress)
  → Cancelled
[Final] Shipped
[Final] Cancelled

```

Generate a Mermaid diagram for documentation:

```
php artisan enum-states:graph "App\Enums\OrderStatus" --format=mermaid
```

Output:

```
stateDiagram-v2
    [*] --> Pending
    Pending --> Processing : guard: HasItemsInStock
    Pending --> Cancelled
    Processing --> Shipped : before: ValidateShippingAddress
    Processing --> Cancelled
    Shipped --> [*]
    Cancelled --> [*]

```

### Generate Enum State

[](#generate-enum-state)

Scaffold a new enum with state machine attributes:

```
php artisan make:enum-state OrderStatus
```

Creates `app/Enums/OrderStatus.php` with `#[InitialState]`, `#[FinalState]`, and `#[Transition]` boilerplate.

### Generate Transition Guard

[](#generate-transition-guard)

Scaffold a new guard class:

```
php artisan make:transition-guard HasItemsInStock
```

Creates `app/Guards/HasItemsInStock.php` implementing `TransitionGuard`.

Async Hooks
-----------

[](#async-hooks)

For hooks that don't need to block the transition, implement the `AsyncTransitionHook` contract. Async hooks are dispatched as queued jobs instead of running synchronously.

```
use SoylentGreenStudio\EnumStates\Contracts\AsyncTransitionHook;

class SendShipmentNotification implements AsyncTransitionHook
{
    public function handle(Model $model, mixed $from, mixed $to, array $metadata): void
    {
        Mail::to($model->user)->send(new OrderShipped($model));
    }

    public function queue(): ?string
    {
        return 'notifications'; // or null for default queue
    }
}
```

Use it the same way as synchronous hooks in the `#[Transition]` attribute:

```
#[Transition(
    to: [self::Shipped],
    before: ValidateShippingAddress::class,    // sync — runs inside transaction
    after: SendShipmentNotification::class,     // async — dispatched to queue
)]
case Processing = 'processing';
```

### Behavior

[](#behavior)

Hook type`TransitionHook` (sync)`AsyncTransitionHook` (async)`before`Runs inside DB transaction, blocks transitionFire-and-forget: dispatched to queue, does not block`after`Runs inside DB transaction, can roll backDispatched after successful commit- **Sync hooks** continue to work exactly as before (full backward compatibility)
- **Async before hooks** are dispatched to the queue at the before-hook point but do not block the transition
- **Async after hooks** are dispatched only after the DB transaction commits successfully
- The internal `ProcessTransitionHook` job wraps the async hook execution

### AsyncTransitionHook contract

[](#asynctransitionhook-contract)

```
interface AsyncTransitionHook
{
    public function handle(Model $model, mixed $from, mixed $to, array $metadata): void;
    public function queue(): ?string; // queue name or null for default
}
```

Testing
-------

[](#testing)

```
composer test
```

The package uses [Pest](https://pestphp.com/) + [Orchestra Testbench](https://github.com/orchestral/testbench).

### Test coverage

[](#test-coverage)

SuiteCovers`TransitionTest`Happy path transitions, disallowed transitions, final state enforcement, auto-detection`GuardTest`Guard blocking, guard allowing, `canTransitionTo` with guards`HookTest`Before/after hook execution order, rollback on hook exception`HistoryTest`History recording, metadata storage, multi-field independence`ScopeTest``whereState`, `whereNotState`, `whereStateIn``EventTest``TransitionStarted`, `TransitionCompleted`, metadata in events`AsyncHookTest`Async hook dispatch, named queues, post-commit dispatch, backward compatibility`CommandTest`Graph command (text/mermaid), generator commands, error handlingComparison with Alternatives
----------------------------

[](#comparison-with-alternatives)

### vs. spatie/laravel-model-states

[](#vs-spatielaravel-model-states)

Aspectspatie/laravel-model-stateslaravel-enum-states**State definition**Separate PHP classes per stateNative PHP Backed Enum cases**Transitions**Separate `Transition` classes or `$transitions` array`#[Transition]` attributes on enum cases**Configuration**`$states` config in model + state classes`$casts` only — auto-detected from enum attributes**Guards**Inside transition classes or `canTransitionTo()` methodDedicated `TransitionGuard` contract, container-resolved**Hooks**Transition class `handle()` + events`before`/`after` hooks on `#[Transition]` attribute**History**Via separate package or customBuilt-in `state_transitions` table**Multiple fields**Supported, requires explicit configSupported, auto-detected from `$casts`**Boilerplate**1 class per state + 1 class per transition1 enum + attributes only**PHP version**PHP 8.0+PHP 8.1+ (requires Backed Enums)**Advantages of laravel-enum-states:**

- Zero boilerplate — no separate state/transition classes
- Everything declared in one place — the Enum itself
- Native PHP Enums for type safety — IDE autocomplete, exhaustive match
- Built-in transition history with metadata
- Guards and hooks resolved via service container

**Disadvantages compared to spatie:**

- Requires PHP 8.1+ (Backed Enums)
- No custom transition logic classes — hooks are simpler but less flexible
- Smaller community and ecosystem
- No default state configuration on the model

### vs. asantibanez/laravel-eloquent-state-machines

[](#vs-asantibanezlaravel-eloquent-state-machines)

Aspectasantibanezlaravel-enum-states**State definition**`StateMachine` class with `$initialState` and `$transitions`Backed Enum with `#[Transition]` attributes**Configuration**`$stateMachines` array in modelAuto-detected from `$casts`**History**Built-inBuilt-in**Guards**`beforeTransitionHook()` in StateMachine classDedicated `TransitionGuard` contract**Type safety**String-based statesEnum-based — IDE autocomplete, type checking### Summary: When to use laravel-enum-states

[](#summary-when-to-use-laravel-enum-states)

**Choose laravel-enum-states when:**

- You want states defined as native PHP Enums with full type safety
- You prefer zero-config auto-detection over manual registration
- You want guards and hooks as separate, testable, injectable classes
- You need built-in transition history with metadata
- You want everything declared in one place — the Enum

**Choose alternatives when:**

- You need complex transition logic in dedicated classes
- You need PHP 8.0 compatibility
- You need a larger community and ecosystem
- You prefer explicit configuration over convention

API Reference
-------------

[](#api-reference)

### Attributes

[](#attributes)

AttributeTargetParameters`#[InitialState]`Enum case—`#[FinalState]`Enum case—`#[Transition]`Enum case (repeatable)`to: array`, `?guard: string`, `?before: string`, `?after: string`### Contracts

[](#contracts)

InterfaceMethod`TransitionGuard``allow(Model $model, array $metadata): bool``TransitionHook``handle(Model $model, mixed $from, mixed $to, array $metadata): void``AsyncTransitionHook``handle(...)` + `queue(): ?string` — dispatched as queued job### HasStateMachines trait

[](#hasstatemachines-trait)

MethodReturnsDescription`transitionTo($state, $metadata)``void`Transition to a new state`transitionTo($field, $state, $metadata)``void`Transition with explicit field name`canTransitionTo($state, $metadata)``bool`Check if transition is allowed`stateHistory($field)``Collection`Get transition history for a field`stateHistory()``Collection`Get transition history for all fields`getStateMachineFields()``array`Get detected state machine fields### Query scopes

[](#query-scopes-1)

ScopeSignature`whereState``whereState(string $field, BackedEnum $state)``whereNotState``whereNotState(string $field, BackedEnum $state)``whereStateIn``whereStateIn(string $field, array $states)`### Events

[](#events-1)

EventProperties`TransitionStarted``Model $model`, `string $field`, `mixed $from`, `mixed $to`, `array $metadata``TransitionCompleted``Model $model`, `string $field`, `mixed $from`, `mixed $to`, `array $metadata``TransitionFailed``Model $model`, `string $field`, `mixed $from`, `mixed $to`, `Throwable $exception`### Exceptions

[](#exceptions)

ExceptionWhen thrown`FinalStateException`Attempting to transition from a `#[FinalState]``InvalidTransitionException`No matching `#[Transition]` found, or guard returned `false`### Models

[](#models)

ClassTableDescription`StateTransition``state_transitions`Polymorphic history record with `from`, `to`, `field`, `metadata`, `transitioned_at`License
-------

[](#license)

MIT License. See [LICENSE.md](LICENSE.md) for details.

###  Health Score

40

—

FairBetter than 88% of packages

Maintenance90

Actively maintained with recent releases

Popularity9

Limited adoption so far

Community6

Small or concentrated contributor base

Maturity47

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 100% 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 ~2 days

Total

6

Last Release

45d ago

### Community

Maintainers

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

---

Top Contributors

[![soylentgreenstudio](https://avatars.githubusercontent.com/u/268559501?v=4)](https://github.com/soylentgreenstudio "soylentgreenstudio (8 commits)")

---

Tags

enumlaravelphp8state-machinelaravelenumstate-machinephp-attributestransitions

###  Code Quality

TestsPest

### Embed Badge

![Health badge](/badges/soylentgreenstudio-laravel-enum-states/health.svg)

```
[![Health](https://phpackages.com/badges/soylentgreenstudio-laravel-enum-states/health.svg)](https://phpackages.com/packages/soylentgreenstudio-laravel-enum-states)
```

###  Alternatives

[barryvdh/laravel-ide-helper

Laravel IDE Helper, generates correct PHPDocs for all Facade classes, to improve auto-completion.

14.9k123.0M687](/packages/barryvdh-laravel-ide-helper)[spatie/laravel-enum

Laravel Enum support

3655.4M31](/packages/spatie-laravel-enum)[datomatic/nova-enum-field

A Laravel Nova PHP 8.1 enum field with filters

20134.2k](/packages/datomatic-nova-enum-field)[api-platform/laravel

API Platform support for Laravel

59126.4k6](/packages/api-platform-laravel)

PHPackages © 2026

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