azimkordpour/power-enum
Power Enum enhances native PHP enums for Laravel with convenient helpers for labels, validation rules, Eloquent casts, and value comparisons, making status and type fields safer, more consistent, and easier to use across your application.
Install and requirements
composer require azimkordpour/power-enum
The package is for PHP 8.1+ enums and is framework-agnostic, so it works in Laravel, Symfony, or plain PHP. There is no service provider to register in most cases — you attach the trait to your enum and you are done. Check composer show azimkordpour/power-enum after install to confirm the version and whether a config file exists (publish it only if the README mentions one).
First place to look
Read the package source (vendor/azimkordpour/power-enum/src) before the README. It is a "light" package, so the trait is small — a 10-minute read tells you exactly which helper methods exist (toArray, values, names, options, random, comparison helpers, etc.) and their exact signatures. Because it has a single maintainer and low adoption, treat the source as the source of truth.
First use case: a status enum for a form + validation
namespace App\Enums;
use AzimKordpour\PowerEnum\Traits\PowerEnum; // confirm exact namespace in source
enum Status: string
{
use PowerEnum;
case Active = 'active';
case Inactive = 'inactive';
case Pending = 'pending';
}
Then immediately exercise the two helpers you will use every day: a list for a <select> and a values array for validation.
Status::toArray(); // e.g. ['active' => 'Active', ...] or ['Active', ...] — verify shape
Status::values(); // ['active', 'inactive', 'pending']
If toArray() returns [value => label], it drops straight into Form::select / a Blade <select>; if it returns a list of names, wrap it yourself. Verify this once and standardize across the app.
1. Trait + contract for labels
Define your own small interface so the rest of the app depends on your contract, not the package:
interface HasLabel { public function label(): string; }
Then implement label() per case and call it from a Blade component. This keeps the enum usable even if you later drop the package.
2. Form options
// Controller
return view('statuses.edit', ['statuses' => Status::toArray()]);
// Blade
<select name="status">
@foreach ($statuses as $value => $label)
<option value="{{ $value }}">{{ $label }}</option>
@endforeach
</select>
3. Validation
Prefer Laravel's built-in rule and use the package only for the list:
$request->validate([
'status' => ['required', Rule::enum(Status::class)],
]);
If you are on an older Laravel, Rule::in(Status::values()) is the fallback — this is where the trait earns its keep.
4. Eloquent casting
protected $casts = [
'status' => Status::class,
];
Now $model->status is an enum instance. Because enums are singletons, comparisons should use ===:
if ($model->status === Status::Active) { ... }
If the trait provides an is() / in() helper, use it for readability but keep === as the mental model.
5. Query params and API input
Use Status::tryFrom($request->string('status')) and return 422 on null. Avoid from() unless you have an exception handler mapped — ValueError leaking to a 500 is a common mistake.
6. API resources
return [
'status' => $this->status->value,
'status_label' => $this->status->label(),
];
Return the scalar value, never the enum object directly, unless you have explicitly tested JSON serialization on your PHP version.
7. Seeders, factories, tests
Status::random() (if present) or Status::cases()[array_rand(Status::cases())] for factories. For PHPUnit/Pest data providers, prefer explicit cases:
public static function statusProvider(): array
{
return array_map(fn ($c) => [$c], Status::cases());
}
8. Grouping / filtering UI
When you have many cases, keep grouping logic in a dedicated method on the enum (e.g. Status::groupedOptions()) rather than in controllers. The package is deliberately small; don't expect it to solve grouping for you.
: string or : int). If you use a pure enum, values() has nothing to return — check the source before adding the trait.toArray(). Whether it is [name => label], [value => name], or [value => label] changes your Blade loop. Do not assume; dd(Status::toArray()) once at the start of the project.lang/en/enums.php. If your labels need i18n, implement label() as __("enums.status.{$this->value}") and create the translation file yourself.'active' is now persisted in your database, in queued jobs, and in API payloads. Renaming requires a data migration; renaming cases (not values) is also breaking if you call Status::Active by name in code.Status::Active === Status::Active is always true; == also works but === is the idiomatic check and avoids surprises when comparing across casts.tryFrom returning null. Always handle the null branch at HTTP boundaries. A missing ->value after a failed tryFrom is the most common runtime error in enum-based controllers.composer.json ("azimkordpour/power-enum": "^1.0" with a known-good minor), commit composer.lock, and keep the trait usage shallow so replacing it with five lines of your own code is trivial.@method docblock above enums if PHPStan/Larastan flags the trait methods as missing, or generate a small stub. Check whether the package ships @method annotations; if not, your IDE may show "undefined method" on Status::values().PowerEnum and layers on top — avoid editing vendor code.var_dump(Status::cases()) and Status::tryFrom($x) in php artisan tinker is the fastest loop; json_encode(Status::Active) will fail on pure enums but succeed on backed enums, which is a quick way to confirm your enum flavor.php artisan view:clear / config:clear after changing enum cases — Blade and config caches will otherwise serve stale lists in local dev.How can I help you explore Laravel packages today?