Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Interact With Enum Laravel Package

kongulov/interact-with-enum

Interact with PHP enums the Laravel way. This lightweight package adds convenient helpers for backed enums so you can compare, validate, and convert values cleanly in application code and validation rules, keeping enum handling expressive and simple.

Deep Wiki
Context7

Getting Started

Install and wire up in under five minutes:

composer require kongulov/interact-with-enum

Add the trait to any enum that needs it:

namespace App\Enums;

use Kongulov\InteractWithEnum\InteractWithEnum; // verify namespace in vendor/

enum OrderStatus: string
{
    use InteractWithEnum;

    case Pending    = 'pending';
    case Paid       = 'paid';
    case Shipped    = 'shipped';
    case Cancelled  = 'cancelled';
}

Where to look first (in this order):

  1. vendor/kongulov/interact-with-enum/src/ — open the trait itself. It's a single small file; every public method is the API. This is faster than reading the README and tells you exactly what you get (values(), names(), toArray(), labels(), options(), fromName(), tryFromName(), is(), etc., depending on the version).
  2. composer.json inside the package for the PHP and Laravel version constraints — this package predates strict Laravel typing, so confirm php: ^8.1.
  3. The GitHub README for any usage examples that differ from what you inferred from the source.

First useful call — a form select or validation rule:

OrderStatus::values();     // ['pending', 'paid', 'shipped', 'cancelled']
OrderStatus::names();      // ['Pending', 'Paid', 'Shipped', 'Cancelled']
OrderStatus::toArray();    // ['Pending' => 'pending', ...] (usually)

The first real use case most teams hit is populating a <select> in a form and validating the submitted value with Rule::enum() or Rule::in(OrderStatus::values()).

Implementation Patterns

Model casting + Blade rendering. The natural home for the trait is a backed enum cast on an Eloquent model, then rendered in views via the enum's own label helpers.

class Order extends Model
{
    protected $casts = ['status' => OrderStatus::class];
}
{{-- in Blade --}}
<select name="status">
    @foreach (OrderStatus::cases() as $case)
        <option value="{{ $case->value }}">{{ $case->label() }}</option>
    @endforeach
</select>

Centralised labels, per-case overrides. A common pattern is to override label() inside each case so the trait's static options() / toArray() methods (which typically call label()) pick up translated strings automatically.

enum OrderStatus: string
{
    use InteractWithEnum;

    case Pending   = 'pending';
    case Paid      = 'paid';

    public function label(): string
    {
        return match ($this) {
            self::Pending => __('Awaiting payment'),
            self::Paid    => __('Payment received'),
        };
    }
}

If the trait defines label() and your enum also defines it, PHP allows the case-local method to win — but you must confirm the trait doesn't declare it final. If it does, use labels() (the map producer) instead.

Validation rules. Two idiomatic ways:

$request->validate([
    'status' => ['required', Rule::enum(OrderStatus::class)],
    // or, for arrays / filters:
    'statuses'   => ['array'],
    'statuses.*' => [Rule::in(OrderStatus::values())],
]);

API responses. Cast enums into arrays with names as keys for a stable JSON contract:

return response()->json([
    'statuses' => OrderStatus::toArray(), // ['Pending' => 'pending', ...]
]);

For per-record output, use ->value explicitly rather than relying on serialisation — the trait does not change Laravel's enum-casting behaviour.

Query scopes and comparisons. Use the trait's is() / isNot() helpers for readability when the caller has both a model and a status:

if ($order->status->is(OrderStatus::Paid)) { /* ... */ }

Or add a scope on the model:

public function scopeWhereStatus($q, OrderStatus ...$statuses)
{
    return $q->whereIn('status', array_map(fn ($s) => $s->value, $statuses));
}

Seeding / factories. OrderStatus::random() (if present) or OrderStatus::cases()[array_rand(...)] keeps seed data honest without magic strings.

Blade badge component. Because the trait usually exposes a name→value map, a single partial can render any enum consistently:

@props(['case'])
<span class="badge badge-{{ $case->value }}">{{ $case->label() }}</span>

Gotchas and Tips

Namespace is not Kongulov\.... Verify the exact use statement — many small packages use a different case or a Kongulov\Enum prefix. A wrong namespace produces a "trait not found" that is easy to misspell-match against an autoload cache.

Trait vs interface collisions. If your enum also implements a shared interface like HasLabel or HasColor (common in Filament/Livewire ecosystems), confirm the trait's method signatures match. A label(): string in the trait clashing with label(): ?string in an interface (or vice versa) throws a fatal error at load time in some PHP versions. Look for a config flag or a use InteractWithEnum { label as traitLabel; } escape hatch.

Backed vs pure enums. Methods returning values() only make sense for string/int backed enums. On a pure enum, values() will typically return case names or throw — check the trait source before choosing the enum kind. Laravel's model casting requires a backed enum anyway.

Enums are not objects in the usual sense. You cannot app(OrderStatus::class), mock an enum case, or extend an enum. Tests should assert against cases directly:

$this->assertSame('paid', OrderStatus::Paid->value);
$this->assertTrue(OrderStatus::Paid->is(OrderStatus::Paid));

from() / tryFrom() are built-in. Don't override them. Use the trait's fromName() / tryFromName() for name-based lookups — those are genuinely new, whereas from() is native to backed enums.

Cache static method results in hot paths. values() and toArray() recompute the case list on each call. In a large @foreach form or a repeated validation rule, cache the array once:

$options = cache()->rememberForever('order_statuses', fn () => OrderStatus::toArray());

DB values must match case values exactly. If the trait's toArray() outputs names as keys and values as values, do not feed toArray() directly into an <option value> loop expecting keys — read values() for form values and toArray() for name→value pairs. Mixing these up is the most common source of "invalid enum cast" exceptions.

Extension points. Add domain methods to the enum rather than to the trait so they stay with the case definitions. Use match ($this) for exhaustive behaviour; adding a case will trigger a PHPStan/match error and prevent silent fall-throughs — this is a feature, not a bug.

Version drift. The last release (April 2025) may have tweaked method names or removed helpers; there's no large user base, so pin the version in composer.json ("kongulov/interact-with-enum": "^1.0") and read the CHANGELOG before upgrading. For a package this small, treat the trait file as the source of truth — a 30-star package is unlikely to keep the README fully in sync.

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
diephp/sequences
users-au/socialite-provider
twidpay/twid-logger
mrnewport/laravel-plaid
mrnewport/laravel-repo
mrnewport/laravel-docsign
mrnewport/laravel-stow
mrnewport/laravel-flow
mrnewport/laravel-priceable
mrnewport/laravel-nestedterms
fredmeng/laravel-apidoc-generator
itstructure/laravel-multilingual-tools
pdustdar/elasticsearch
markupai/php-sdk
rlacerda83/lumem-microservice-shipment
uni-method/symfony-lib
tacticmedia/scim-server-bundle
neika-ai/symfony-bundle
mattleads/agent-publishing-bundle
glavweb/framework-bundle