yeugone/enum-bundle
yeugone/enum-bundle is a PHP package for Laravel developers seeking a cleaner way to organize and work with enums. It bundles practical enum utilities that help define type-safe values, reduce scattered constants, and keep application code more structured and readable across your project.
The package bundles a simple value-object enumeration system (constants on a class) with a Symfony bundle that wires it into the container, forms, Doctrine, and validation. It is not a Laravel package — do not try to install it there. Confirm the actual namespace and base class in the repo's src/ before writing code, since the API surface is small and version drift is a real risk at this maturity level.
composer require yeugone/enum-bundle
config/bundles.php (Symfony Flex usually does this automatically if the package ships a Flex recipe; verify):
return [
// ...
Yeugone\EnumBundle\EnumBundle::class => ['all' => true],
];
src/Enum.php (or similarly named base class) — that is the only file you really need to understand. Then check DependencyInjection/ for the extension alias (usually enum or yeugone_enum) and Resources/config/services.yaml for what gets registered.use Yeugone\EnumBundle\Enum;
final class OrderStatus extends Enum
{
public const PENDING = 'pending';
public const SHIPPED = 'shipped';
public const CANCELLED = 'cancelled';
}
// Day-to-day usage
$status = new OrderStatus(OrderStatus::SHIPPED);
$status->getValue(); // 'shipped' (verify method name)
OrderStatus::values(); // ['pending','shipped','cancelled']
OrderStatus::isValid('foo'); // false
The immediate win is that OrderStatus::values() can feed a Symfony ChoiceType and a Doctrine choice/string column without duplicating the list in three places.Value-object enum classes. Treat every enum as an immutable wrapper around a scalar constant. Instantiate once per request (they are cheap), pass them around typed against the concrete class, and only unwrap to scalar at the persistence / serialization / template boundary:
public function ship(): void
{
if (!$this->status->equals(new OrderStatus(OrderStatus::PENDING))) {
throw new \DomainException('Cannot ship a non-pending order.');
}
$this->status = new OrderStatus(OrderStatus::SHIPPED);
}
Symfony form integration. Map the enum to a ChoiceType using choices: OrderStatus::values() plus a choice_label that humanizes the value, and convert the chosen string back to an enum in the DTO setter (or use a data transformer). This is the most common day-to-day integration and the one most likely to save time.
Doctrine mapping. Persist enums as a plain string/integer column and convert in the entity getter/setter. Don't rely on a custom DBAL type unless you've verified it ships in this bundle — the bundle is small, and a hand-rolled Type in your app is more predictable than betting on undocumented behavior.
Validation. Register a custom constraint (#[Enum(OrderStatus::class)]) or a closure on the property that calls SomeEnum::isValid($value). Keeping this in one constraint avoids scattering in_array checks across controllers.
Service wiring. If the bundle exposes a tagged Enum service or autoconfiguration, prefer explicit $container->register() in your own bundle config so you control the enum registry. Where the bundle offers a compiler pass for collecting enum classes, use it only for cross-cutting concerns (e.g. building a global "all statuses" list for admin filters).
Serialization. Enums in API responses should go out as their scalar value, not as objects. Add JsonSerializable handling (either on a shared base class or via a Symfony normalizer) so json_encode($order) yields "status": "shipped" — never {"value": "shipped"} leaking into a public contract.
composer.json and add a couple of unit tests around your enum classes so a future incompatibility is caught by your own suite, not in production.int|string; the base class likely validates this, but don't assume — a duplicate value silently breaks from()/isValid() lookups. Add a test asserting count(Enum::values()) === count((new ReflectionClass(Enum::class))->getConstants()).__callStatic (OrderStatus::PENDING()), you lose IDE autocompletion and static analysis. Check src/ — if that's the API, prefer instantiating with new OrderStatus(OrderStatus::PENDING) and keep references to the raw constants, which are greppable.$enum->equals(...) is safer than == on the enum object. When comparing scalars, use === — Doctrine can hand you int where you expect string for integer-backed enums.config/bundles.php and bin/console debug:container | grep enum.myclabs/php-enum-style base class is a drop-in alternative with far more community support).App\Enum\Enum that extends the package base class — you can add toLabel(), jsonSerialize(), and #[Enum]-friendly helpers there without touching vendor code, so swapping the underlying library later is a one-file change.var_dump($enum) shows the wrapped value; if you get an "invalid value" exception, dump the raw input from the request/DB first — usually it's whitespace, a case mismatch ('Shipped' vs 'shipped'), or a null sneaking through a nullable column.How can I help you explore Laravel packages today?