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

Enum Laravel Package

greg0ire/enum

A lightweight PHP enumeration library that lets you define enum-like classes with constants, validate values, and access available constants. It provides a simple AbstractEnum base class for projects that need typed, reusable sets of values without heavy dependencies.

View on GitHub
Deep Wiki
Context7

Getting Started

Install with Composer — the package is a single, dependency-free abstract class:

composer require greg0ire/enum

Then declare each enum-like concept as a final class of public constants extending AbstractEnum:

<?php
declare(strict_types=1);

namespace App\Domain\Order;

use Greg0ire\Enum\AbstractEnum;

final class Status extends AbstractEnum
{
    public const PENDING  = 'pending';
    public const PAID     = 'paid';
    public const SHIPPED  = 'shipped';
    public const CANCELLED = 'cancelled';
}

Where to look first: open src/AbstractEnum.php. It is one small file of static helpers built on ReflectionClass::getConstants(). Reading it end-to-end (5 minutes) is faster and more reliable than skimming docs, because the entire contract of the package — which helpers exist, how they treat duplicate values, whether they cache reflection — is visible there.

First use case: validating an untrusted scalar at a boundary. Instead of scattering in_array($status, ['pending', 'paid', ...]) around the codebase:

if (!Status::isValid($request->get('status'))) {
    throw new \InvalidArgumentException('Unknown order status');
}

You now have a single source of truth for the set of legal values, usable from controllers, form types, Doctrine types, fixtures and API docs alike.

Implementation Patterns

Validation at the edge, string in the core. Since the library gives you no type enforcement, treat the enum class as a catalogue, not a type. Validate once when data enters (HTTP request, message consumer, CLI argument) and let plain strings flow through your services. This keeps signatures simple and avoids pretending you have type safety you don't.

Doctrine column type. Wrap the enum in a DBAL type so persistence validates on the way in:

final class StatusType extends Type
{
    public function getSQLDeclaration(array $column, AbstractPlatform $platform): string
    {
        return $platform->getStringTypeDeclarationSQL($column);
    }

    public function convertToPHPValue($value, AbstractPlatform $platform): ?string
    {
        if ($value !== null && !Status::isValid($value)) {
            throw new \UnexpectedValueException("Invalid status: $value");
        }

        return $value;
    }
}

Register it in doctrine.dbal.types and use type: "status" on the mapping.

Symfony Form / ChoiceType. Status::getConstants() gives a ready-made label => value array, which is exactly what ChoiceType wants:

$builder->add('status', ChoiceType::class, [
    'choices' => array_flip(Status::getConstants()),
]);

Keep user-facing labels in translation files (enum.status.pending) rather than hard-coding them in the enum class — the constants should stay language-agnostic.

API contracts and OpenAPI. Generate an enum schema directly from Status::getValues(). Anything that accepts the field can be asserted against the same array, so the schema cannot drift from the code.

Fixtures and tests. Faker's randomElement(Status::getValues()) produces valid data without duplicating the list. For PHPUnit, write one data-provider-driven test that asserts isValid() accepts every value in getValues() and rejects a sentinel string — that test then covers every constant you add later.

Static analysis. Constants are untyped, so annotate the value union once and reuse it:

/** @psalm-type StatusValue = 'pending'|'paid'|'shipped'|'cancelled' */

This is the closest thing to real enum typing you get, and it makes PHPStan/Psalm flag impossible match arms.

Gotchas and Tips

  • It is not a type. No type safety, no exhaustiveness checking, no instances, no methods with state. Every helper is static, so Status::isValid(...) is a runtime check that a string happens to be in a list. Design your signatures accordingly and don't build domain logic around the class.
  • PHP 8.1+ supersedes it. On any supported runtime you should prefer native enum Status: string { case Pending = 'pending'; } with ::from() / ::tryFrom(). Treat this package as a legacy bridge. Migration is mechanical: isValid($v) → Status::tryFrom($v) !== null, getValues() → array_column(Status::cases(), 'value'), getConstants() → a map over cases(). If you adopt it today, add a TODO and set a deprecation date.
  • Reflection on every call. Helpers typically reflect the class per invocation. In hot loops (serializers, list rendering) memoize into a private static ?array $cache in your own subclass, or hoist the call out of the loop.
  • Watch duplicate values. If two constants share a value, key/value lookups that go through array_flip or array_search become ambiguous — getKey('x')-style helpers return only the first match. Avoid aliases unless you genuinely need backwards-compatible names.
  • getConstants() vs getValues(). Use the former when you need names (forms, labels); the latter when you need payload values (persistence, API). Mixing them up is the most common source of "why is my select showing PENDING".
  • Mark subclasses final and use static::. Helpers rely on late static binding; a non-final subclass that redeclares a constant will silently change what the parent's helpers see for that subclass. final documents intent and prevents the footgun.
  • Constant ordering follows declaration order today, but treat it as an implementation detail — never assert on getValues()[0]. Define an explicit DEFAULT constant and reference it by name.
  • No behaviour, no flags. Don't encode bitmasks or state machines here; these are flat scalars. If you need transitions (pending → paid), put that in a service or a real state machine, not in the constant catalogue.
  • Adding a constant is cheap but not free. Old rows remain valid, yet any switch/match over the values and any generated API schema changes. Grep for getConstants() and getValues() consumers before merging.
  • Maintenance risk. Latest release was May 2023 with no active development. It is small enough to vendor or copy the single class into your codebase if you want to drop the dependency, and doing so lets you add caching or typed helpers without waiting on upstream. Pin the version and plan the native-enum exit rather than expecting fixes.
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.
robertmarney/lara-hierarchial-collections
simonschaufi/rule-doc-generator
emissaoja/emissaoja
blackbricksoftware/gravityforms-civicrm-form-processor
al-rahabi/fancy-crud
jinas/dhivatar-component
mltstephane/laravel-quality
bernskiold/laravel-talentlms
bernskioldmedia/laravel-form-architect
youbar/easy-crud
c-point-labs/laravel-hostyourai
dbravoan/dbcms-admin-theme-dbcms
dbravoan/dbcms-theme-db-cyber
dbravoan/dbcms-blocks-basic
dbravoan/dbcms-module-content-audit
dbravoan/dbcms-module-ai-assistant
paygate-to/paygate-php
padosoft/askmydocs-connector-base
defstudio/supercharged-carbon
bernskioldmedia/laravel-matomo