Uh oh!
There was an error while loading.Please reload this page.
- Notifications
You must be signed in to change notification settings - Fork161
Simple, extensible and powerful enumeration implementation for Laravel.
License
BenSampo/laravel-enum
Folders and files
Name | Name | Last commit message | Last commit date | |
---|---|---|---|---|
Repository files navigation
Using this library is no longer recommended, especially for new projects.PHP 8.1 supports enums natively.
See#332.
Simple, extensible and powerful enumeration implementation for Laravel.
- Enum key value pairs as class constants
- Full-featured suite of methods
- Enum instantiation
- Flagged/Bitwise enums
- Type hinting
- Attribute casting
- Enum artisan generator
- Validation rules for passing enum key or values as input parameters
- Localization support
- Extendable via Macros
Created byBen Sampson
- Guide
- Installation
- Migrate to Native PHP Enums
- Enum Library
- Basic Usage
- Flagged/Bitwise Enum
- Attribute Casting
- Migrations
- Validation
- Localization
- Customizing Descriptions
- Extending the Enum Base Class
- Laravel Nova Integration
- PHPStan Integration
- Artisan Command List
- Enum Class Reference
- Stubs
You are reading the documentation for6.x
.
- If you're usingLaravel 8 please see thedocs for
4.x
. - If you're usingLaravel 7 please see thedocs for
2.x
. - If you're usingLaravel 6 or below, please see thedocs for
1.x
.
Please see theupgrade guide for information on how to upgrade to the latest version.
I wrote a blog post about using laravel-enum:https://sampo.co.uk/blog/using-enums-in-laravel
Requires PHP 8, and Laravel 9 or 10.
composer require bensampo/laravel-enum
PHP 8.1 supports enums natively.You can migrate your usages ofBenSampo\Enum\Enum
to native PHP enums using the following steps.
Make sure you meet the following requirements:
- PHP 8.1 or higher
- Laravel 10 or higher
- Rector 0.17 or higher, your
rector.php
includes all relevant files - Latest version of this library
Depending on the size of your project, you may choose to migrate all enums at once,or migrate just a couple or one enum at a time.
Convert all enums at once:
php artisan enum:to-native
Pass the fully qualified class name of an enum to limit the conversion:
php artisan enum:to-native "App\Enums\UserType"
This is necessary if any enums are used during the bootstrap phase of Laravel,the conversion of their usages interferes with Larastan and prevents a second run of Rector from working.
Review and validate the code changes for missed edge cases:
- SeeUnimplemented
Enum::coerce()
: If only values were passed, you can replace it withtryFrom()
.If keys or instances could also be passed, you might need additional logic to cover this.Enum::$description
andEnum::getDescription()
: Implement an alternative.- try/catch-blocks that handle
BenSampo\Enum\Exceptions\InvalidEnumKeyException
orBenSampo\Enum\Exceptions\InvalidEnumMemberException
.Either catch theValueError
thrown by native enums, or switch to usingtryFrom()
and handlenull
.
Once all enums are converted, you can remove your dependency on this library.
Browse and download from a list of commonly used, community contributed enums.
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.
<?phpdeclare(strict_types=1);namespaceApp\Enums;useBenSampo\Enum\Enum;finalclass UserTypeextends Enum{constAdministrator =0;constModerator =1;constSubscriber =2;constSuperAdministrator =3;}
That's it! Note that because the enum values are defined as plain constants,you can simply access them like any other class constant.
UserType::Administrator// Has a value of 0
It can be useful to instantiate enums in order to pass them between functionswith 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 =newUserType(UserType::Administrator);// Same as the constructor, instantiate by value$enumInstance = UserType::fromValue(UserType::Administrator);// Use an enum key instead of its value$enumInstance = UserType::fromKey('Administrator');// Statically calling the key name as a method, utilizing __callStatic magic$enumInstance = UserType::Administrator();// Attempt to instantiate a new Enum using the given key or value. Returns null if the Enum cannot be instantiated.$enumInstance = UserType::coerce($someValue);
If you want your IDE to autocomplete the static instantiation helpers, you cangenerate PHPDoc annotations through an artisan command.
By default, all Enums inapp/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"
Once you have an enum instance, you can access thekey
,value
anddescription
as properties.
$userType = UserType::fromValue(UserType::SuperAdministrator);$userType->key;// SuperAdministrator$userType->value;// 3$userType->description;// Super Administrator
This is particularly useful if you're passing an enum instance to a blade view.
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::fromValue(UserType::SuperAdministrator);(string)$userType// '3'
You can check the equality of an instance against any value by passing it to theis
method.For convenience, there is also anisNot
method which is the exact reverse of theis
method.
$admin = 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 thein
method,and usenotIn
to check if instance value is not in an array of values.Iterables can also be checked against.
$admin = 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$admin->notIn([UserType::Moderator, UserType::Administrator]);// false$admin->notIn([UserType::Moderator(), UserType::Administrator()]);// false$admin->notIn([UserType::Moderator, UserType::Subscriber]);// true$admin->notIn(['random-value']);// true
The instantiated enums are not singletons, rather a new object is created every time.Thus, strict comparison===
of different enum instances will always returnfalse
, no matter the value.In contrast, loose comparison==
will depend on the value.
$admin = UserType::Administrator();$admin === UserType::Administrator();// falseUserType::Administrator() === UserType::Administrator();// false$admin === UserType::Moderator();// false$admin ===$admin;// true$admin == UserType::Administrator();// true$admin == UserType::Administrator;// true$admin == UserType::Moderator();// false$admin == UserType::Moderator;// false
One of the benefits of enum instances is that it enables you to use type hinting, as shown below.
functioncanPerformAction(UserType$userType){if ($userType->is(UserType::SuperAdministrator)) {returntrue; }returnfalse;}$userType1 = UserType::fromValue(UserType::SuperAdministrator);$userType2 = UserType::fromValue(UserType::Moderator);canPerformAction($userType1);// Returns truecanPerformAction($userType2);// Returns false
Standard enums represent a single value at a time, but flagged or bitwise enums are capable of of representing multiple values simultaneously. This makes them perfect for when you want to express multiple selections of a limited set of options. A good example of this would be user permissions where there are a limited number of possible permissions but a user can have none, some or all of them.
You can create a flagged enum using the following artisan command:
php artisan make:enum UserPermissions --flagged
When defining values you must use powers of 2, the easiest way to do this is by using theshift left<<
operator like so:
finalclass UserPermissionsextends FlaggedEnum{constReadComments =1 <<0;constWriteComments =1 <<1;constEditComments =1 <<2;constDeleteComments =1 <<3;// The next one would be `1 << 4` and so on...}
You can use the bitwiseor|
to set a shortcut value which represents a given set of values.
finalclass UserPermissionsextends FlaggedEnum{constReadComments =1 <<0;constWriteComments =1 <<1;constEditComments =1 <<2;constDeleteComments =1 <<3;// ShortcutsconstMember =self::ReadComments |self::WriteComments;// Read and write.constModerator =self::Member |self::EditComments;// All the permissions a Member has, plus Edit.constAdmin =self::Moderator |self::DeleteComments;// All the permissions a Moderator has, plus Delete.}
There are couple of ways to instantiate a flagged enum:
// Standard new PHP class, passing the desired enum values as an array of values or array of enum instances$permissions =newUserPermissions([UserPermissions::ReadComments, UserPermissions::EditComments]);$permissions =newUserPermissions([UserPermissions::ReadComments(), UserPermissions::EditComments()]);// Static flags method, again passing the desired enum values as an array of values or array of enum instances$permissions = UserPermissions::flags([UserPermissions::ReadComments, UserPermissions::EditComments]);$permissions = UserPermissions::flags([UserPermissions::ReadComments(), UserPermissions::EditComments()]);
Attribute casting works in the same way as single value enums.
Flagged enums can contain no value at all. Every flagged enum has a pre-defined constant ofNone
which is comparable to0
.
UserPermissions::flags([])->value === UserPermissions::None;// True
In addition to the standard enum methods, there are a suite of helpful methods available on flagged enums.
Note: Anywhere where a static property is passed, you can also pass an enum instance.
Set the flags for the enum to the given array of flags.
$permissions = UserPermissions::flags([UserPermissions::ReadComments]);$permissions->flags([UserPermissions::EditComments, UserPermissions::DeleteComments]);// Flags are now: EditComments, DeleteComments.
Add the given flag to the enum
$permissions = UserPermissions::flags([UserPermissions::ReadComments]);$permissions->addFlag(UserPermissions::EditComments);// Flags are now: ReadComments, EditComments.
Add the given flags to the enum
$permissions = UserPermissions::flags([UserPermissions::ReadComments]);$permissions->addFlags([UserPermissions::EditComments, UserPermissions::WriteComments]);// Flags are now: ReadComments, EditComments, WriteComments.
Add all flags to the enum
$permissions = UserPermissions::flags([UserPermissions::ReadComments]);$permissions->addAllFlags();// Enum now has all flags
Remove the given flag from the enum
$permissions = UserPermissions::flags([UserPermissions::ReadComments, UserPermissions::WriteComments]);$permissions->removeFlag(UserPermissions::ReadComments);// Flags are now: WriteComments.
Remove the given flags from the enum
$permissions = UserPermissions::flags([UserPermissions::ReadComments, UserPermissions::WriteComments, UserPermissions::EditComments]);$permissions->removeFlags([UserPermissions::ReadComments, UserPermissions::WriteComments]);// Flags are now: EditComments.
Remove all flags from the enum
$permissions = UserPermissions::flags([UserPermissions::ReadComments, UserPermissions::WriteComments]);$permissions->removeAllFlags();
Check if the enum has the specified flag.
$permissions = UserPermissions::flags([UserPermissions::ReadComments, UserPermissions::WriteComments]);$permissions->hasFlag(UserPermissions::ReadComments);// True$permissions->hasFlag(UserPermissions::EditComments);// False
Check if the enum has all of the specified flags.
$permissions = UserPermissions::flags([UserPermissions::ReadComments, UserPermissions::WriteComments]);$permissions->hasFlags([UserPermissions::ReadComments, UserPermissions::WriteComments]);// True$permissions->hasFlags([UserPermissions::ReadComments, UserPermissions::EditComments]);// False
Check if the enum does not have the specified flag.
$permissions = UserPermissions::flags([UserPermissions::ReadComments, UserPermissions::WriteComments]);$permissions->notHasFlag(UserPermissions::EditComments);// True$permissions->notHasFlag(UserPermissions::ReadComments);// False
Check if the enum doesn't have any of the specified flags.
$permissions = UserPermissions::flags([UserPermissions::ReadComments, UserPermissions::WriteComments]);$permissions->notHasFlags([UserPermissions::ReadComments, UserPermissions::EditComments]);// True$permissions->notHasFlags([UserPermissions::ReadComments, UserPermissions::WriteComments]);// False
Return the flags as an array of instances.
$permissions = UserPermissions::flags([UserPermissions::ReadComments, UserPermissions::WriteComments]);$permissions->getFlags();// [UserPermissions::ReadComments(), UserPermissions::WriteComments()];
Check if there are multiple flags set on the enum.
$permissions = UserPermissions::flags([UserPermissions::ReadComments, UserPermissions::WriteComments]);$permissions->hasMultipleFlags();// True;$permissions->removeFlag(UserPermissions::ReadComments)->hasMultipleFlags();// False
Get the bitmask for the enum.
UserPermissions::Member()->getBitmask();// 11;UserPermissions::Moderator()->getBitmask();// 111;UserPermissions::Admin()->getBitmask();// 1111;UserPermissions::DeleteComments()->getBitmask();// 1000;
To use flagged enums directly in your Eloquent queries, you may use theQueriesFlaggedEnums
trait on your model which provides you with the following methods:
User::hasFlag('permissions', UserPermissions::DeleteComments())->get();
User::notHasFlag('permissions', UserPermissions::DeleteComments())->get();
User::hasAllFlags('permissions', [UserPermissions::EditComment(), UserPermissions::ReadComment()])->get();
User::hasAnyFlags('permissions', [UserPermissions::DeleteComments(), UserPermissions::EditComments()])->get();
You may cast model attributes to enums using Laravel's built in custom casting. This will cast the attribute to an enum instance when getting and back to the enum value when setting.SinceEnum::class
implements theCastable
contract, you just need to specify the classname of the enum:
useBenSampo\Enum\Tests\Enums\UserType;useIlluminate\Database\Eloquent\Model;class Exampleextends Model{protected$casts = ['random_flag' =>'boolean',// Example standard laravel cast'user_type' => UserType::class,// Example enum cast ];}
Now, when you access theuser_type
attribute of yourExample
model,the underlying value will be returned as aUserType
enum.
$example = Example::first();$example->user_type// Instance of UserType
Review themethods 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();
When usingtoArray
(or returning model/models from your controller as a response) Laravel will call thetoArray
method on the enum instance.
By default, this will return only the value in its native type. You may want to also have access to the other properties (key, description), for example to returnto javascript app.
To customise this behaviour, you can override thetoArray
method on the enum instance.
// Example Enumfinalclass UserTypeextends Enum{constADMINISTRATOR =0;constMODERATOR =1;}$instance = UserType::Moderator();// DefaultpublicfunctiontoArray(){return$this->value;}// Returns int(1)// Return all propertiespublicfunctiontoArray(){return$this;}// Returns an array of all the properties// array(3) {// ["value"]=>// int(1)"// ["key"]=>// string(9) "MODERATOR"// ["description"]=>// string(9) "Moderator"// }
Many databases return everything as strings (for example, an integer may be returned as the string'1'
).To reduce friction for users of the library, we use type coercion to figure out the intended value. If you'd prefer to control this, you can override theparseDatabase
static method on your enum class:
finalclass UserTypeextends Enum{constAdministrator =0;constModerator =1;publicstaticfunctionparseDatabase($value) {return (int)$value; }}
Returningnull
from theparseDatabase
method will cause the attribute on the model to also benull
. This can be useful if your database stores inconsistent blank values such as empty strings instead ofNULL
.
If you're casting attributes on your model to enums, thelaravel-ide-helper package can be used to automatically generate property docblocks for you.
Because enums enforce consistency at the code level it's not necessary to do so again at the database level, therefore the recommended type for database columns isstring
orint
depending on your enum values. This means you can add/remove enum values in your code without worrying about your database layer.
useApp\Enums\UserType;useIlluminate\Support\Facades\Schema;useIlluminate\Database\Schema\Blueprint;useIlluminate\Database\Migrations\Migration;class CreateUsersTableextends Migration{/** * Run the migrations. * * @return void */publicfunctionup():void { Schema::table('users',function (Blueprint$table):void {$table->bigIncrements('id');$table->timestamps();$table->string('type') ->default(UserType::Moderator); }); }}
Alternatively you may useEnum
classes in your migrations to define enum columns.The enum values must be defined as strings.
useApp\Enums\UserType;useIlluminate\Support\Facades\Schema;useIlluminate\Database\Schema\Blueprint;useIlluminate\Database\Migrations\Migration;class CreateUsersTableextends Migration{/** * Run the migrations. * * @return void */publicfunctionup():void { Schema::table('users',function (Blueprint$table):void {$table->bigIncrements('id');$table->timestamps();$table->enum('type', UserType::getValues()) ->default(UserType::Moderator); }); }}
You may validate that an enum value passed to a controller is a valid value for a given enum by using theEnumValue
rule.
useBenSampo\Enum\Rules\EnumValue;publicfunctionstore(Request$request){$this->validate($request, ['user_type' => ['required',newEnumValue(UserType::class)], ]);}
By default, type checking is set to strict, but you can bypass this by passingfalse
to the optional second parameter of the EnumValue class.
newEnumValue(UserType::class,false)// Turn off strict type checking.
You can also validate on keys using theEnumKey
rule. This is useful if you're taking the enum key as a URL parameter for sorting or filtering for example.
useBenSampo\Enum\Rules\EnumKey;publicfunctionstore(Request$request){$this->validate($request, ['user_type' => ['required',newEnumKey(UserType::class)], ]);}
Additionally you can validate that a parameter is an instance of a given enum.
useBenSampo\Enum\Rules\Enum;publicfunctionstore(Request$request){$this->validate($request, ['user_type' => ['required',newEnum(UserType::class)], ]);}
You can also use the 'pipe' syntax for rules.
enum_value:enum_class,[strict]
enum_key:enum_class
enum:enum_class
'user_type' =>'required|enum_value:' . UserType::class,'user_type' =>'required|enum_key:' . UserType::class,'user_type' =>'required|enum:' . UserType::class,
Run the following command to publish the language files to yourlang
folder.
php artisan vendor:publish --provider="BenSampo\Enum\EnumServiceProvider" --tag="translations"
You can translate the strings returned by thegetDescription
method using Laravel's built-inlocalization features.
Add a newenums.php
keys file for each of your supported languages. In this example there is one for English and one for Spanish.
// lang/en/enums.php<?phpdeclare(strict_types=1);useApp\Enums\UserType;return [ UserType::class => [ UserType::Administrator =>'Administrator', UserType::SuperAdministrator =>'Super administrator', ],];
// lang/es/enums.php<?phpdeclare(strict_types=1);useApp\Enums\UserType;return [ UserType::class => [ UserType::Administrator =>'Administrador', UserType::SuperAdministrator =>'Súper administrador', ],];
Now, you just need to make sure that your enum implements theLocalizedEnum
interface as demonstrated below:
useBenSampo\Enum\Enum;useBenSampo\Enum\Contracts\LocalizedEnum;finalclass UserTypeextends Enumimplements LocalizedEnum{// ...}
ThegetDescription
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.
If you'd like to return a custom description for your enum class, add aDescription
attribute to your Enum class:
useBenSampo\Enum\Enum;useBenSampo\Enum\Attributes\Description;#[Description('List of available User types')]finalclass UserTypeextends Enum{ ...}
CallingUserType::getClassDescription()
now returnsList of available User types
instead ofUser type
.
You may also override thegetClassDescription
method on the base Enum class if you wish to have more control of the description.
If you'd like to return a custom description for your enum values, add aDescription
attribute to your Enum constants:
useBenSampo\Enum\Enum;useBenSampo\Enum\Attributes\Description;finalclass UserTypeextends Enum{constAdministrator ='Administrator'; #[Description('Super admin')]constSuperAdministrator ='SuperAdministrator';}
CallingUserType::SuperAdministrator()->description
now returnsSuper admin
instead ofSuper administrator
.
You may also override thegetDescription
method on the base Enum class if you wish to have more control of the description.
TheEnum
base class implements theLaravelMacroable
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 enumasArray
method, we can do this using:
Enum::macro('asFlippedArray', function() { return array_flip(self::asArray());});
Now, on each of my enums, I can call it usingUserType::asFlippedArray()
.
It's best to register the macro inside a service providers' boot method.
Use thenova-enum-field package by Simple Squid to easily create fields for your Enums in Nova. See their readme for usage.
If you are usingPHPStan for static analysis, enable the extension for:
- proper recognition of the magic instantiation methods
- detection of duplicate enum values
UsePHPStan Extension Installer or add the following to your projectsphpstan.neon
includes:
includes:- vendor/bensampo/laravel-enum/extension.neon
Create a new enum class. Pass--flagged
as an option to create a flagged enum.
Find out more
Generate DocBlock annotations for enum classes.
Find out more
Seemigrate to native PHP enums.
Returns an array of all or a custom set of the keys for an enum.
UserType::getKeys();// Returns ['Administrator', 'Moderator', 'Subscriber', 'SuperAdministrator']UserType::getKeys(UserType::Administrator);// Returns ['Administrator']UserType::getKeys(UserType::Administrator, UserType::Moderator);// Returns ['Administrator', 'Moderator']UserType::getKeys([UserType::Administrator, UserType::Moderator]);// Returns ['Administrator', 'Moderator']
Returns an array of all or a custom set of the values for an enum.
UserType::getValues();// Returns [0, 1, 2, 3]UserType::getValues('Administrator');// Returns [0]UserType::getValues('Administrator','Moderator');// Returns [0, 1]UserType::getValues(['Administrator','Moderator']);// Returns [0, 1]
Returns the key for the given enum value.
UserType::getKey(1);// Returns 'Moderator'UserType::getKey(UserType::Moderator);// Returns 'Moderator'
Returns the value for the given enum key.
UserType::getValue('Moderator');// Returns 1
Check if the enum contains a given key.
UserType::hasKey('Moderator');// Returns 'True'
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'
Returns the class name in sentence case for the enum class. It's possible tocustomize the description if the guessed description is not appropriate.
UserType::getClassDescription();// Returns 'User type'
Returns the key in sentence case for the enum value. It's possible tocustomize the description if the guessed description is not appropriate.
UserType::getDescription(3);// Returns 'Super administrator'UserType::getDescription(UserType::SuperAdministrator);// Returns 'Super administrator'
Returns a random key from the enum. Useful for factories.
UserType::getRandomKey();// Returns 'Administrator', 'Moderator', 'Subscriber' or 'SuperAdministrator'
Returns a random value from the enum. Useful for factories.
UserType::getRandomValue();// Returns 0, 1, 2 or 3
Returns a random instance of the enum. Useful for factories.
UserType::getRandomInstance();// Returns an instance of UserType with a random value
Returns the enum key value pairs as an associative array.
UserType::asArray();// Returns ['Administrator' => 0, 'Moderator' => 1, 'Subscriber' => 2, 'SuperAdministrator' => 3]
Returns the enum for use in a select as value => description.
UserType::asSelectArray();// Returns [0 => 'Administrator', 1 => 'Moderator', 2 => 'Subscriber', 3 => 'Super administrator']
Returns an instance of the called enum. Read more aboutenum instantiation.
UserType::fromValue(UserType::Administrator);// Returns instance of Enum with the value set to UserType::Administrator
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" }}
Attempt to instantiate a new Enum using the given key or value. Returns null if the Enum cannot be instantiated.
UserType::coerce(0);// Returns instance of UserType with the value set to UserType::AdministratorUserType::coerce('Administrator');// Returns instance of UserType with the value set to UserType::AdministratorUserType::coerce(99);// Returns null (not a valid enum value)
Run the following command to publish the stub files to thestubs
folder in the root of your application.
php artisan vendor:publish --provider="BenSampo\Enum\EnumServiceProvider" --tag="stubs"
About
Simple, extensible and powerful enumeration implementation for Laravel.
Topics
Resources
License
Contributing
Uh oh!
There was an error while loading.Please reload this page.
Stars
Watchers
Forks
Sponsor this project
Uh oh!
There was an error while loading.Please reload this page.
Packages0
Uh oh!
There was an error while loading.Please reload this page.