mindtwo / laravel-enum
Simple, extensible and powerful enumeration implementation for Laravel.
Requires
- php: ~7.1
- hanneskod/classtools: ~1.0
- illuminate/support: 5.4.*|5.5.*|5.6.*|5.7.*|5.8.*|5.9.*|6.*|7.*
- zendframework/zend-code: ^3.3
Requires (Dev)
- laravel/framework: 7.*
- orchestra/testbench: ^5.0
This package is auto-updated.
Last update: 2020-09-21 16:11:16 UTC
README
About Laravel Enum
Simple, extensible and powerful enumeration implementation for Laravel.
- Enum key value pairs as class constants
- Full featured suite of methods
- Enum instantiation
- Type hinting
- Attribute casting
- Enum artisan generator
- Validation rules for passing enum key or values as input parameters
- Localization support
- Extendable via Macros
Created by Ben Sampson
Jump To
- Guide
- Installation
- Enum Library
- Basic Usage
- Attribute Casting
- Validation
- Localization
- Overriding the getDescription method
- Extending the Enum Base Class
- PHPStan Integration
- Artisan Command List
- Enum Class Reference
Guide
I wrote a blog post about using laravel-enum: https://sampo.co.uk/blog/using-enums-in-laravel
Requirements
- Laravel
5.4
or newer - PHP
7.1
or newer
Installation
Via Composer
composer require bensampo/laravel-enum
If you're using Laravel < 5.5 you'll need to add the service provider to config/app.php
'BenSampo\Enum\EnumServiceProvider'
Enum Library
Browse and download from a list of commonly used, community contributed enums.
Basic Usage
Enum Definition
You can use the following Artisan command to generate a new enum class:
php artisan make:enum UserType
Now, you just need to add the possible values your enum can have as constants.
<?php namespace App\Enums; use BenSampo\Enum\Enum; final class UserType extends Enum { const Administrator = 0; const Moderator = 1; const Subscriber = 2; const SuperAdministrator = 3; }
That's it! Note that because the enum values are defined as plain constants, you can simple access them like any other class constant.
UserType::Administrator // Has a value of 0
Instantiation
It can be useful to instantiate enums in order to pass them between functions with the benefit of type hinting.
Additionally, it's impossible to instantiate an enum with an invalid value, therefore you can be certain that the passed value is always valid.
For convenience, enums can be instantiated in multiple ways:
// Standard new PHP class, passing the desired enum value as a parameter $enumInstance = new UserType(UserType::Administrator); // Static getInstance method, again passing the desired enum value as a parameter $enumInstance = UserType::getInstance(UserType::Administrator); // Statically calling the key name as a method, utilizing __callStatic magic $enumInstance = UserType::Administrator(); // Using the coerce static method to attempt to instantiate an Enum using the given value if it exists. $enumInstance = UserType::coerce($someValue);
If you want your IDE to autocomplete the static instantiation helpers, you can generate PHPDoc annotations through an artisan command.
By default all Enums in app/Enums
will be annotated (you can change the folder by passing a path to --folder
)
php artisan enum:annotate
You can annotate a single class by specifying the class name
php artisan enum:annotate "App\Enums\UserType"
Instance Properties
Once you have an enum instance, you can access the key
, value
and description
as properties.
$userType = UserType::getInstance(UserType::SuperAdministrator); $userType->key; // SuperAdministrator $userType->value; // 0 $userType->description; // Super Administrator
This is particularly useful if you're passing an enum instance to a blade view.
Instance Casting
Enum instances can be cast to strings as they implement the __toString()
magic method.
This also means they can be echoed in blade views, for example.
$userType = UserType::getInstance(UserType::SuperAdministrator); (string) $userType // '0'
Instance Equality
You can check the equality of an instance against any value by passing it to the is
method. For convenience, there is also an isNot
method which is the exact reverse of the is
method.
$admin = UserType::getInstance(UserType::Administrator); $admin->is(UserType::Administrator); // true $admin->is($admin); // true $admin->is(UserType::Administrator()); // true $admin->is(UserType::Moderator); // false $admin->is(UserType::Moderator()); // false $admin->is('random-value'); // false
You can also check to see if the instance's value matches against an array of possible values using the in
method.
$admin = UserType::getInstance(UserType::Administrator); $admin->in([UserType::Moderator, UserType::Administrator]); // true $admin->in([UserType::Moderator(), UserType::Administrator()]); // true $admin->in([UserType::Moderator, UserType::Subscriber]); // false $admin->in(['random-value']); // false
Type Hinting
One of the benefits of enum instances is that it enables you to use type hinting, as shown below.
function canPerformAction(UserType $userType) { if ($userType->is(UserType::SuperAdministrator)) { return true; } return false; } $userType1 = UserType::getInstance(UserType::SuperAdministrator); $userType2 = UserType::getInstance(UserType::Moderator); canPerformAction($userType1); // Returns true canPerformAction($userType2); // Returns false
Attribute Casting
You may cast model attributes to enums using the CastsEnums
trait. This will cast the attribute to an enum instance when getting and back to the enum value when setting.
Similar to how standard attribute casting works, you simply define which attributes you want to cast to which enum as an array on the model.
use BenSampo\Enum\Traits\CastsEnums; use BenSampo\Enum\Tests\Enums\UserType; use Illuminate\Database\Eloquent\Model; class Example extends Model { use CastsEnums; protected $enumCasts = [ // 'attribute_name' => Enum::class 'user_type' => UserType::class, ]; /** * Existing casts are processed before $enumCasts which can be useful if you're * taking input from forms and your enum values are integers. */ protected $casts = [ 'user_type' => 'int', ]; }
Now, when you access the user_type
attribute of your Example
model,
the underlying value will be returned as a UserType
enum.
$example = Example::first(); $example->user_type // Instance of UserType
Review the methods and properties available on enum instances to get the most out of attribute casting.
You can set the value by either passing the enum value or another enum instance.
$example = Example::first(); // Set using enum value $example->user_type = UserType::Moderator; // Set using enum instance $example->user_type = UserType::Moderator();
Model Annotation
The package can automatically generate DocBlocks for your Model
classes to provide type hinting & completion in your IDE.
By default all Model
classes in the root of app
will be annotated (you can change the folder by passing a path to --folder
)
php artisan enum:annotate-model
Validation
Array Validation
You may validate that an enum value passed to a controller is a valid value for a given enum by using the EnumValue
rule.
public function store(Request $request) { $this->validate($request, [ 'user_type' => ['required', new EnumValue(UserType::class)], ]); }
By default, type checking is set to strict, but you can bypass this by passing false
to the optional second parameter of the EnumValue class.
new EnumValue(UserType::class, false) // Turn off strict type checking.
You can also validate on keys using the EnumKey
rule. This is useful if you're taking the enum key as a URL parameter for sorting or filtering for example.
public function store(Request $request) { $this->validate($request, [ 'user_type' => ['required', new EnumKey(UserType::class)], ]); }
Of course, both of these work on form request classes too.
Make sure to include BenSampo\Enum\Rules\EnumValue
and/or BenSampo\Enum\Rules\EnumKey
and your enum class in the usings.
Pipe Validation
You can also use the 'pipe' syntax for both the EnumKey and EnumValue rules by using enum_value
and/or enum_key
respectively.
enum_value:enum_class,[strict]
enum_key:enum_class
'user_type' => 'required|enum_value:' . UserType::class, 'user_type' => 'required|enum_key:' . UserType::class,
Localization
You can translate the strings returned by the getDescription
method using Laravel's built in localization features.
Add a new enums.php
keys file for each of your supported languages. In this example there is one for English and one for Spanish.
// resources/lang/en/enums.php <?php use App\Enums\UserType; return [ UserType::class => [ UserType::Administrator => 'Administrator', UserType::SuperAdministrator => 'Super administrator', ], ];
// resources/lang/es/enums.php <?php use App\Enums\UserType; return [ UserType::class => [ UserType::Administrator => 'Administrador', UserType::SuperAdministrator => 'Súper administrador', ], ];
Now, you just need to make sure that your enum implements the LocalizedEnum
interface as demonstrated below:
use BenSampo\Enum\Enum; use BenSampo\Enum\Contracts\LocalizedEnum; final class UserType extends Enum implements LocalizedEnum { // ... }
The getDescription
method will now look for the value in your localization files. If a value doesn't exist for a given key, the default description is returned instead.
Overriding the getDescription method
If you'd like to return a custom value from the getDescription method, you may do so by overriding the method on your enum:
public static function getDescription($value): string { if ($value === self::SuperAdministrator) { return 'Super admin'; } return parent::getDescription($value); }
Calling UserType::getDescription(3);
now returns Super admin
instead of Super administator
.
Extending the Enum Base Class
The Enum
base class implements the Laravel Macroable
trait, meaning it's easy to extend it with your own functions. If you have a function that you often add to each of your enums, you can use a macro.
Let's say we want to be able to get a flipped version of the enum toArray
method, we can do this using:
Enum::macro('toFlippedArray', function() { return array_flip(self::toArray()); });
Now, on each of my enums, I can call it using UserType::toFlippedArray()
.
It's best to register the macro inside of a service providers' boot method.
PHPStan integration
If you are using PHPStan for static analysis, you can enable the extension for proper recognition of the magic instantiation methods.
Add the following to your projects phpstan.neon
includes:
includes: - vendor/bensampo/laravel-enum/extension.neon
Artisan Command List
php artisan make:enum
Create a new enum class
Find out more
php artisan enum:annotate
Generate DocBlock annotations for enum classes
Find out more
php artisan enum:annotate-model
Generate DocBlock annotations for models that have enums
Find out more
Enum Class Reference
static getKeys(): array
Returns an array of the keys for an enum.
UserType::getKeys(); // Returns ['Administrator', 'Moderator', 'Subscriber', 'SuperAdministrator']
static getValues(): array
Returns an array of the values for an enum.
UserType::getValues(); // Returns [0, 1, 2, 3]
static getKey(mixed $value): string
Returns the key for the given enum value.
UserType::getKey(1); // Returns 'Moderator' UserType::getKey(UserType::Moderator); // Returns 'Moderator'
static getValue(string $key): mixed
Returns the value for the given enum key.
UserType::getValue('Moderator'); // Returns 1
static hasKey(string $key): bool
Check if the enum contains a given key.
UserType::hasKey('Moderator'); // Returns 'True'
static hasValue(mixed $value, bool $strict = true): bool
Check if the enum contains a given value.
UserType::hasValue(1); // Returns 'True' // It's possible to disable the strict type checking: UserType::hasValue('1'); // Returns 'False' UserType::hasValue('1', false); // Returns 'True'
static getDescription(mixed $value): string
Returns the key in sentence case for the enum value. It's possible to override the getDescription method to return custom descriptions.
UserType::getDescription(3); // Returns 'Super administrator' UserType::getDescription(UserType::SuperAdministrator); // Returns 'Super administrator'
static getRandomKey(): string
Returns a random key from the enum. Useful for factories.
UserType::getRandomKey(); // Returns 'Administrator', 'Moderator', 'Subscriber' or 'SuperAdministrator'
static getRandomValue(): mixed
Returns a random value from the enum. Useful for factories.
UserType::getRandomValue(); // Returns 0, 1, 2 or 3
static getRandomInstance(): mixed
Returns a random instance of the enum. Useful for factories.
UserType::getRandomInstance(); // Returns an instance of UserType with a random value
static toArray(): array
Returns the enum key value pairs as an associative array.
UserType::toArray(); // Returns ['Administrator' => 0, 'Moderator' => 1, 'Subscriber' => 2, 'SuperAdministrator' => 3]
static toSelectArray(): array
Returns the enum for use in a select as value => description.
UserType::toSelectArray(); // Returns [0 => 'Administrator', 1 => 'Moderator', 2 => 'Subscriber', 3 => 'Super administrator']
static getInstance(mixed $enumValue): Enum
Returns an instance of the called enum. Read more about enum instantiation.
UserType::getInstance(UserType::Administrator); // Returns instance of Enum with the value set to UserType::Administrator
static getInstances(): array
Returns an array of all possible instances of the called enum, keyed by the constant names.
var_dump(UserType::getInstances()); array(4) { 'Administrator' => class BenSampo\Enum\Tests\Enums\UserType#415 (3) { public $key => string(13) "Administrator" public $value => int(0) public $description => string(13) "Administrator" } 'Moderator' => class BenSampo\Enum\Tests\Enums\UserType#396 (3) { public $key => string(9) "Moderator" public $value => int(1) public $description => string(9) "Moderator" } 'Subscriber' => class BenSampo\Enum\Tests\Enums\UserType#393 (3) { public $key => string(10) "Subscriber" public $value => int(2) public $description => string(10) "Subscriber" } 'SuperAdministrator' => class BenSampo\Enum\Tests\Enums\UserType#102 (3) { public $key => string(18) "SuperAdministrator" public $value => int(3) public $description => string(19) "Super administrator" } }
static coerce(): ?Enum
Attempt to instantiate a new Enum using the given value if it exists. Returns null if it doesn't.
UserType::coerce(0); // Returns instance of UserType with the value set to UserType::Administrator UserType::coerce(99); // Returns null (not a valid enum value)