Simple, extensible and powerful enumeration implementation for Laravel.
Created by Ben Sampson
You are reading the documentation for 3.x
.
2.x
.1.x
.Please see the upgrade 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
8
or higher7.3
or higherVia Composer
composer require bensampo/laravel-enum
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.
<?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
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 = new UserType(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 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"
Once you have an enum instance, you can access the key
, value
and description
as properties.
$userType = UserType::fromValue(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.
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 // '0'
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::fromValue(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. Iterables can also be checked against.
$admin = UserType::fromValue(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
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::fromValue(UserType::SuperAdministrator);
$userType2 = UserType::fromValue(UserType::Moderator);
canPerformAction($userType1); // Returns true
canPerformAction($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 the shift left <<
operator like so:
final class UserPermissions extends FlaggedEnum
{
const ReadComments = 1 << 0;
const WriteComments = 1 << 1;
const EditComments = 1 << 2;
const DeleteComments = 1 << 3;
// The next one would be `1 << 4` and so on...
}
You can use the bitwise or |
to set a shortcut value which represents a given set of values.
final class UserPermissions extends FlaggedEnum
{
const ReadComments = 1 << 0;
const WriteComments = 1 << 1;
const EditComments = 1 << 2;
const DeleteComments = 1 << 3;
// Shortcuts
const Member = self::ReadComments | self::WriteComments; // Read and write.
const Moderator = self::Member | self::EditComments; // All the permissions a Member has, plus Edit.
const Admin = 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 = new UserPermissions([UserPermissions::ReadComments, UserPermissions::EditComments]);
$permissions = new UserPermissions([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 of None
which is comparable to 0
.
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 the QueriesFlaggedEnums
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 7.x's built in custom casting. This will cast the attribute to an enum instance when getting and back to the enum value when setting.Since Enum::class
implements the Castable
contract, you just need to specify the classname of the enum:
use BenSampo\Enum\Tests\Enums\UserType;
use Illuminate\Database\Eloquent\Model;
class Example extends Model
{
protected $casts = [
'random_flag' => 'boolean', // Example standard laravel cast
'user_type' => UserType::class, // Example enum cast
];
}
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->toArray()
behaviourWhen using toArray
(or returning model/models from your controller as a response) Laravel will call the toArray
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 the toArray
method on the enum instance.
// Example Enum
final class UserType extends Enum
{
const ADMINISTRATOR = 0;
const MODERATOR = 1;
}
$instance = UserType::Moderator();
// Default
public function toArray()
{
return $this->value;
}
// Returns int(1)
// Return all properties
public function toArray()
{
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 the parseDatabase
static method on your enum class:
final class UserType extends Enum
{
const Administrator = 0;
const Moderator = 1;
public static function parseDatabase($value)
{
return (int) $value;
}
}
Returning null
from the parseDatabase
method will cause the attribute on the model to also be null
. This can be useful if your database stores inconsistent blank values such as empty strings instead of NULL
.
If you're using Laravel 7 casting, the laravel-ide-helper package can be used to automatically generate property docblocks for your models.
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 is string
or int
depending on your enum values. This means you can add/remove enum values in your code without worrying about your database layer.
use App\Enums\UserType;
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class CreateUsersTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up(): void
{
Schema::table('users', function (Blueprint $table): void {
$table->bigIncrements('id');
$table->timestamps();
$table->string('type')
->default(UserType::Moderator);
});
}
}
enum
column typeAlternatively you may use Enum
classes in your migrations to define enum columns.The enum values must be defined as strings.
use App\Enums\UserType;
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class CreateUsersTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up(): 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 the EnumValue
rule.
use BenSampo\Enum\Rules\EnumValue;
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.
use BenSampo\Enum\Rules\EnumKey;
public function store(Request $request)
{
$this->validate($request, [
'user_type' => ['required', new EnumKey(UserType::class)],
]);
}
Additionally you can validate that a parameter is an instance of a given enum.
use BenSampo\Enum\Rules\Enum;
public function store(Request $request)
{
$this->validate($request, [
'user_type' => ['required', new Enum(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 your resources/lang
folder.
php artisan vendor:publish --provider="BenSampo\Enum\EnumServiceProvider" --tag="translations"
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.
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
.
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 asArray
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 using UserType::asFlippedArray()
.
It's best to register the macro inside of a service providers' boot method.
Use the nova-enum-field package by Simple Squid to easily create fields for your Enums in Nova. See their readme for usage.
If you are using PHPStan for staticanalysis, you can enable the extension for proper recognition of themagic instantiation methods.
Add the following to your projects phpstan.neon
includes:
includes:
- vendor/bensampo/laravel-enum/extension.neon
php artisan make:enum
Create a new enum class. Pass --flagged
as an option to create a flagged enum.
Find out more
php artisan enum:annotate
Generate DocBlock annotations for enum classes.
Find out more
Returns an array of the keys for an enum.
UserType::getKeys(); // Returns ['Administrator', 'Moderator', 'Subscriber', 'SuperAdministrator']
Returns an array of the values for an enum.
UserType::getValues(); // Returns [0, 1, 2, 3]
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 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'
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 about enum 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::Administrator
UserType::coerce('Administrator'); // Returns instance of UserType with the value set to UserType::Administrator
UserType::coerce(99); // Returns null (not a valid enum value)
Run the following command to publish the stub files to the stubs
folder in the root of your application.
php artisan vendor:publish --provider="BenSampo\Enum\EnumServiceProvider" --tag="stubs"
数据迁移migration方法,在方法里面加上 Schema::getConnection()->getDoctrineSchemaManager()->getDatabasePlatform()->registerDoctrineTypeMapping('enum', 'string'); public function up() { // 加上这一句就可以啦 Schema::getC
结构生成器 简介 Laravel 的 Schema 类提供了一种与数据库无关的方式维护表。它和 Laravel 所支持的所有数据库都能很好的工作,并且提供了统一的接口。 创建和删除表 使用 Schema::create 创建一个数据库的表:Schema::create('users', function($table) { $table->increments('id'); }); 传递给 cre
参考连接:Enum filter with numeric values 修改Fields\Enum::build()方法 $options['options'][] = array( 'id' => is_numeric($val) && (!array_key_exists('enum_numeric_keys', $options) || $options['
第一步:删除安装失败的laravel项目,window直接删除,linux 使用 rm -rf 文件名(更换为自己的项目文件夹名) 删除。 第二步:使用composer self-update命令确认自己的composer版本是不是最新版本。 第三步:使用composer clearcache 命令清除composer缓存。 第四步:重点。更换composer镜像为阿里云镜像。 composer
Laravel 是一套简洁、优雅的PHP Web开发框架(PHP Web Framework)。它可以让你从面条一样杂乱的代码中解脱出来;它可以帮你构建一个完美的网络APP,而且每行代码都可以简洁、富于表达力。 功能特点 1、语法更富有表现力 你知道下面这行代码里 “true” 代表什么意思么? $uri = Uri::create(‘some/uri’, array(), array(), tr
我需要空间/Laravel权限的帮助。当我试图分配它给我错误哎呀,看起来像出了问题。 错误 Connection.php第761行中的QueryExcema:SQLSTATE[23000]:完整性约束冲突:1048列role_id不能为空(SQL:插入到(,)值(9,))
Laravel 作为现在最流行的 PHP 框架,其中的知识较多,所以单独拿出来写一篇。 简述 Laravel 的生命周期 Laravel 采用了单一入口模式,应用的所有请求入口都是 public/index.php 文件。 注册类文件自动加载器 : Laravel通过 composer 进行依赖管理,无需开发者手动导入各种类文件,而由自动加载器自行导入。 创建服务容器:从 bootstrap/ap
简介 Laravel Scout 为 Eloquent 模型 全文搜索提供了简单的,基于驱动的解决方案。通过使用模型观察者,Scout 会自动同步 Eloquent 记录的搜索索引。 目前,Scout 自带一个 Algolia 驱动;不过,编写自定义驱动很简单, 你可以轻松的通过自己的搜索实现来扩展 Scout。 安装 首先,通过 Composer 包管理器来安装 Scout: composer
简介 Laravel 致力于让整个 PHP 开发体验变得愉快, 包括你的本地开发环境。 Vagrant 提供了一种简单,优雅的方式来管理和配置虚拟机。 Laravel Homestead 是一个官方预封装的 Vagrant box,它为你提供了一个完美的开发环境,而无需在本地机器安装 PHP 、Web 服务器和其他服务器软件。不用担心会搞乱你的操作系统!Vagrant boxes 是一次性的。如果
WebStack-Laravel 一个开源的网址导航网站项目,具备完整的前后台,您可以拿来制作自己的网址导航。 部署 克隆代码: git clone https://github.com/hui-ho/WebStack-Laravel.git 安装依赖: composer installphp artisan key:generate 编辑配置: cp .env.example .env ...D