codica-studio / enum
一个随机的Codica Studio包。
Requires
- php: ^7.4
- hanneskod/classtools: ~1.0
- illuminate/contracts: ^8.0
- illuminate/support: ^8.0
- laminas/laminas-code: ^3.4
Requires (Dev)
- doctrine/dbal: ^2.9
- laravel/framework: ^8.0
- orchestra/testbench: ^6.0
- phpstan/phpstan: ^0.12.9
- phpunit/phpunit: ^9.3
- squizlabs/php_codesniffer: ^3.0
This package is auto-updated.
Last update: 2024-09-19 15:17:26 UTC
README
为Laravel提供简单、可扩展且功能强大的枚举实现。
- 枚举键值对作为类常量
- 功能齐全的方法集
- 枚举实例化
- 标记/位枚举
- 类型提示
- 属性转换
- 枚举Artisan生成器
- 验证规则,用于将枚举键或值作为输入参数传递
- 本地化支持
- 可通过宏扩展
跳转至
- 指南
- 安装
- 枚举库
- 基本用法
- 标记/位枚举
- 属性转换
- 迁移
- 验证
- 本地化
- 重写getDescription方法
- 扩展枚举基类
- Laravel Nova集成
- PHPStan集成
- Artisan命令列表
- 枚举类参考
安装
要求
- Laravel
8
或更高版本 - PHP
7.3
或更高版本
通过Composer
composer require codicastudio/enum
枚举库
浏览并从常用、社区贡献的枚举列表中下载。
基本用法
枚举定义
您可以使用以下Artisan命令来生成一个新的枚举类
php artisan make:enum UserType
现在,您只需添加枚举可以有的可能值作为常量。
<?php namespace App\Enums; use codicastudio\Enum\Enum; final class UserType extends Enum { const Administrator = 0; const Moderator = 1; const Subscriber = 2; const SuperAdministrator = 3; }
就这样!请注意,由于枚举值被定义为普通常量,您可以像访问任何其他类常量一样访问它们。
UserType::Administrator // Has a value of 0
实例化
实例化枚举以在函数之间传递它们,同时具有类型提示的好处是有用的。
此外,无法使用无效值实例化枚举,因此您可以确信传递的值始终有效。
为了方便,枚举可以以多种方式实例化
// 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);
如果您希望您的IDE自动完成静态实例化辅助程序,您可以通过Artisan命令生成PHPDoc注释。
默认情况下,所有位于app/Enums
中的枚举都将被注释(您可以通过传递路径到--folder
来更改文件夹)
php artisan enum:annotate
您可以通过指定类名来注释单个类
php artisan enum:annotate "App\Enums\UserType"
实例属性
一旦您有了枚举实例,您就可以通过属性访问key
、value
和description
。
$userType = UserType::fromValue(UserType::SuperAdministrator); $userType->key; // SuperAdministrator $userType->value; // 0 $userType->description; // Super Administrator
如果您将枚举实例传递给blade视图,这尤其有用。
实例转换
枚举实例可以转换为字符串,因为它们实现了__toString()
魔法方法。
这意味着它们可以在blade视图中进行回显,例如。
$userType = UserType::fromValue(UserType::SuperAdministrator); (string) $userType // '0'
实例等价性
您可以通过传递给is
方法来检查实例是否与任何值相等。为了方便,还有一个isNot
方法,它与is
方法相反。
$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
您还可以使用in
方法检查实例的值是否与一组可能的值匹配。
$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
类型提示
枚举实例的一个优点是它允许您使用类型提示,如下所示。
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
标记/位枚举
标准枚举一次表示一个值,但标记或位枚举可以同时表示多个值。这使得它们非常适合您想要表达一组有限选项的多选情况。一个很好的例子是用户权限,其中可能有有限数量的可能权限,但用户可以有零个、一些或全部权限。
您可以使用以下Artisan命令创建标记枚举
php artisan make:enum UserPermissions --flagged
定义值
在定义值时,必须使用2的幂,最简单的方法是使用左移运算符<<
,如下所示:
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... }
定义快捷键
您可以使用位运算或 |
来设置一个表示一组值的快捷键值。
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. }
实例化带标志的枚举
实例化带标志的枚举有几种方法
// 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()]);
属性转换与单个值枚举的方式相同。
空带标志的枚举
带标志的枚举可以完全不包含任何值。每个带标志的枚举都有一个预定义的常量None
,其与0
等价。
UserPermissions::flags([])->value === UserPermissions::None; // True
带标志的枚举方法
除了标准的枚举方法外,带标志的枚举还有一些有用的方法可供使用。
注意:任何地方传递静态属性的地方,您也可以传递枚举实例。
setFlags(array $flags): Enum
将枚举的标志设置为给定的标志数组。
$permissions = UserPermissions::flags([UserPermissions::ReadComments]); $permissions->flags([UserPermissions::EditComments, UserPermissions::DeleteComments]); // Flags are now: EditComments, DeleteComments.
addFlag($flag): Enum
将给定的标志添加到枚举中
$permissions = UserPermissions::flags([UserPermissions::ReadComments]); $permissions->addFlag(UserPermissions::EditComments); // Flags are now: ReadComments, EditComments.
addFlags(array $flags): Enum
将给定的标志添加到枚举中
$permissions = UserPermissions::flags([UserPermissions::ReadComments]); $permissions->addFlags([UserPermissions::EditComments, UserPermissions::WriteComments]); // Flags are now: ReadComments, EditComments, WriteComments.
removeFlag($flag): Enum
从枚举中删除给定的标志
$permissions = UserPermissions::flags([UserPermissions::ReadComments, UserPermissions::WriteComments]); $permissions->removeFlag(UserPermissions::ReadComments); // Flags are now: WriteComments.
removeFlags(array $flags): Enum
从枚举中删除给定的标志
$permissions = UserPermissions::flags([UserPermissions::ReadComments, UserPermissions::WriteComments, UserPermissions::EditComments]); $permissions->removeFlags([UserPermissions::ReadComments, UserPermissions::WriteComments]); // Flags are now: EditComments.
hasFlag($flag): bool
检查枚举是否具有指定的标志。
$permissions = UserPermissions::flags([UserPermissions::ReadComments, UserPermissions::WriteComments]); $permissions->hasFlag(UserPermissions::ReadComments); // True $permissions->hasFlag(UserPermissions::EditComments); // False
hasFlags(array $flags): bool
检查枚举是否具有所有指定的标志。
$permissions = UserPermissions::flags([UserPermissions::ReadComments, UserPermissions::WriteComments]); $permissions->hasFlags([UserPermissions::ReadComments, UserPermissions::WriteComments]); // True $permissions->hasFlags([UserPermissions::ReadComments, UserPermissions::EditComments]); // False
notHasFlag($flag): bool
检查枚举是否不具有指定的标志。
$permissions = UserPermissions::flags([UserPermissions::ReadComments, UserPermissions::WriteComments]); $permissions->notHasFlag(UserPermissions::EditComments); // True $permissions->notHasFlag(UserPermissions::ReadComments); // False
notHasFlags(array $flags): bool
检查枚举是否不具有任何指定的标志。
$permissions = UserPermissions::flags([UserPermissions::ReadComments, UserPermissions::WriteComments]); $permissions->notHasFlags([UserPermissions::ReadComments, UserPermissions::EditComments]); // True $permissions->notHasFlags([UserPermissions::ReadComments, UserPermissions::WriteComments]); // False
getFlags(): Enum[]
以实例数组的形式返回标志。
$permissions = UserPermissions::flags([UserPermissions::ReadComments, UserPermissions::WriteComments]); $permissions->getFlags(); // [UserPermissions::ReadComments(), UserPermissions::WriteComments()];
hasMultipleFlags(): bool
检查枚举上是否设置了多个标志。
$permissions = UserPermissions::flags([UserPermissions::ReadComments, UserPermissions::WriteComments]); $permissions->hasMultipleFlags(); // True; $permissions->removeFlag(UserPermissions::ReadComments)->hasMultipleFlags(); // False
getBitmask(): int
获取枚举的掩码。
UserPermissions::Member()->getBitmask(); // 11; UserPermissions::Moderator()->getBitmask(); // 111; UserPermissions::Admin()->getBitmask(); // 1111; UserPermissions::DeleteComments()->getBitmask(); // 1000;
属性转换
您可以使用Laravel 7.x内置的自定义转换将模型属性转换为枚举。这将将在获取时将属性转换为枚举实例,并在设置时将枚举值转换回属性值。由于Enum::class
实现了Castable
接口,因此您只需指定枚举的类名。
use codicastudio\Enum\Traits\CastsEnums; use codicastudio\Enum\Tests\Enums\UserType; use Illuminate\Database\Eloquent\Model; class Example extends Model { use CastsEnums; protected $casts = [ 'random_flag' => 'boolean', // Example standard laravel cast 'user_type' => UserType::class, // Example enum cast ]; }
现在,当您访问Example
模型的user_type
属性时,底层值将以UserType
枚举的形式返回。
$example = Example::first(); $example->user_type // Instance of UserType
查看枚举实例上的方法和属性,以充分利用属性转换。
您可以通过传递枚举值或另一个枚举实例来设置值。
$example = Example::first(); // Set using enum value $example->user_type = UserType::Moderator; // Set using enum instance $example->user_type = UserType::Moderator();
转换底层原生类型
许多数据库将所有内容都返回为字符串(例如,整数可能以字符串'1'
的形式返回)。为了减少库用户的摩擦,我们使用类型强制转换来确定预期的值。如果您想控制这一点,可以覆盖枚举类上的parseDatabase
静态方法。
final class UserType extends Enum { const Administrator = 0; const Moderator = 1; public static function parseDatabase($value) { return (int) $value; } }
从parseDatabase
方法返回null
将导致模型上的属性也变为null
。如果您的数据库存储不一致的空值(例如,使用空字符串而不是NULL
),这可能会很有用。
模型注解
如果您正在使用Laravel 7转换,可以使用laravel-ide-helper包来自动生成模型的属性文档块。
迁移
推荐
因为枚举在代码级别强制一致性,所以在数据库级别再次这样做就不必要了,因此推荐的数据库列类型是string
或int
,具体取决于您的枚举值。这意味着您可以在代码中添加/删除枚举值,而无需担心数据库层。
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
列表类型
或者您也可以在迁移中使用 Enum
类来定义列表列。列表值必须定义为字符串。
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); }); } }
验证
数组验证
列表值
您可以使用 EnumValue
规则来验证传递给控制器的列表值是否为给定列表的有效值。
use codicastudio\Enum\Rules\EnumValue; public function store(Request $request) { $this->validate($request, [ 'user_type' => ['required', new EnumValue(UserType::class)], ]); }
默认情况下,类型检查设置为严格,但您可以通过将 false
传递给 EnumValue
类的可选第二个参数来绕过此设置。
new EnumValue(UserType::class, false) // Turn off strict type checking.
列表键
您还可以使用 EnumKey
规则来验证键。如果您将列表键用作 URL 参数进行排序或过滤等操作,这很有用。
use codicastudio\Enum\Rules\EnumKey; public function store(Request $request) { $this->validate($request, [ 'user_type' => ['required', new EnumKey(UserType::class)], ]); }
列表实例
此外,您还可以验证参数是否为给定列表的实例。
use codicastudio\Enum\Rules\Enum; public function store(Request $request) { $this->validate($request, [ 'user_type' => ['required', new Enum(UserType::class)], ]); }
管道验证
您还可以使用 '管道' 语法来指定规则。
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,
本地化
验证信息
运行以下命令将语言文件发布到您的 resources/lang
文件夹。
php artisan vendor:publish --provider="codicastudio\Enum\EnumServiceProvider"
列表描述
您可以使用 Laravel 内置的 本地化 功能来翻译由 getDescription
方法返回的字符串。
为您的每种支持的语言添加一个新的 enums.php
键文件。在这个例子中,有一个英文和一个西班牙语。
// 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', ], ];
现在,您只需确保您的列表实现如以下示例所示的 LocalizedEnum
接口
use codicastudio\Enum\Enum; use codicastudio\Enum\Contracts\LocalizedEnum; final class UserType extends Enum implements LocalizedEnum { // ... }
getDescription
方法现在将在您的本地化文件中查找值。如果给定键不存在值,则返回默认描述。
重写getDescription方法
如果您想从 getDescription
方法返回自定义值,您可以在枚举上重写该方法。
public static function getDescription($value): string { if ($value === self::SuperAdministrator) { return 'Super admin'; } return parent::getDescription($value); }
现在调用 UserType::getDescription(3);
返回 Super admin
而不是 Super administrator
。
扩展枚举基类
Enum
基类实现了 Laravel 的 Macroable
特性,这意味着可以轻松地通过自己的函数扩展它。如果您有一个经常添加到每个列表中的函数,您可以使用宏。
假设我们想能够获取枚举 asArray
方法的翻转版本,我们可以这样做
Enum::macro('asFlippedArray', function() { return array_flip(self::asArray()); });
现在,我可以在每个列表上调用它,使用 UserType::asFlippedArray()
。
最好在服务提供者的 boot 方法中注册宏。
Laravel Nova集成
使用 Simple Squid 的 nova-enum-field 包来轻松创建 Nova 中的列表字段。请参阅其说明以获取用法。
PHPStan 集成
如果您使用 PHPStan 进行静态分析,您可以启用扩展以正确识别魔法实例化方法。
将以下内容添加到项目的 phpstan.neon
包含中
includes: - vendor/codicastudio/enum/extension.neon
Artisan命令列表
php artisan make:enum
创建一个新的列表类。通过传递 --flagged
选项创建一个标记列表。
了解更多信息
php artisan enum:annotate
为列表类生成 DocBlock 注释。
了解更多信息
枚举类参考
static getKeys(): array
返回列表的键数组。
UserType::getKeys(); // Returns ['Administrator', 'Moderator', 'Subscriber', 'SuperAdministrator']
static getValues(): array
返回列表的值数组。
UserType::getValues(); // Returns [0, 1, 2, 3]
static getKey(mixed $value): string
返回给定列表值的键。
UserType::getKey(1); // Returns 'Moderator' UserType::getKey(UserType::Moderator); // Returns 'Moderator'
static getValue(string $key): mixed
返回给定列表键的值。
UserType::getValue('Moderator'); // Returns 1
static hasKey(string $key): bool
检查列表是否包含给定的键。
UserType::hasKey('Moderator'); // Returns 'True'
static hasValue(mixed $value, bool $strict = true): bool
检查列表是否包含给定的值。
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
返回枚举值的句子大小写键。可以重写getDescription方法来返回自定义描述。
UserType::getDescription(3); // Returns 'Super administrator' UserType::getDescription(UserType::SuperAdministrator); // Returns 'Super administrator'
static getRandomKey(): string
返回枚举中的随机键。对于工厂类很有用。
UserType::getRandomKey(); // Returns 'Administrator', 'Moderator', 'Subscriber' or 'SuperAdministrator'
static getRandomValue(): mixed
返回枚举中的随机值。对于工厂类很有用。
UserType::getRandomValue(); // Returns 0, 1, 2 or 3
static getRandomInstance(): mixed
返回枚举中的随机实例。对于工厂类很有用。
UserType::getRandomInstance(); // Returns an instance of UserType with a random value
static asArray(): array
返回枚举键值对作为关联数组。
UserType::asArray(); // Returns ['Administrator' => 0, 'Moderator' => 1, 'Subscriber' => 2, 'SuperAdministrator' => 3]
static asSelectArray(): array
返回用于select的枚举,格式为value => description。
UserType::asSelectArray(); // Returns [0 => 'Administrator', 1 => 'Moderator', 2 => 'Subscriber', 3 => 'Super administrator']
static fromValue(mixed $enumValue): Enum
返回调用枚举的实例。更多关于枚举实例化的信息。
UserType::fromValue(UserType::Administrator); // Returns instance of Enum with the value set to UserType::Administrator
static getInstances(): array
返回所有可能的枚举实例数组,键为常量名称。
var_dump(UserType::getInstances()); array(4) { 'Administrator' => class codicastudio\Enum\Tests\Enums\UserType#415 (3) { public $key => string(13) "Administrator" public $value => int(0) public $description => string(13) "Administrator" } 'Moderator' => class codicastudio\Enum\Tests\Enums\UserType#396 (3) { public $key => string(9) "Moderator" public $value => int(1) public $description => string(9) "Moderator" } 'Subscriber' => class codicastudio\Enum\Tests\Enums\UserType#393 (3) { public $key => string(10) "Subscriber" public $value => int(2) public $description => string(10) "Subscriber" } 'SuperAdministrator' => class codicastudio\Enum\Tests\Enums\UserType#102 (3) { public $key => string(18) "SuperAdministrator" public $value => int(3) public $description => string(19) "Super administrator" } }
static coerce(mixed $enumKeyOrValue): ?Enum
尝试使用给定的键或值创建新的Enum实例。如果枚举无法实例化,则返回null。
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)