laravel的枚举助手——基于php8.1的枚举特性

LARAVEL ENUM

基于php8.1枚举特性的laravel的枚举助手。

Github (喜欢这个项目点个 star 吧,灰常感谢~)

安装

你可以通过composer安装软件包:

composer require biiiiiigmonster/laravel-enum

使用

将Trait类应用于枚举:

use BiiiiiigMonster\LaravelEnum\Concerns\EnumTraits;

// 值枚举
enum TaskStatus: int
{
    use EnumTraits;

    case INCOMPLETE = 0;
    case COMPLETED = 1;
    case CANCELED = 2;
}

// 纯枚举
enum Role
{
    use EnumTraits;

    case ADMINISTRATOR;
    case SUBSCRIBER;
    case GUEST;
}

Invokable

此助手允许你通过静态方法MyEnum::FOO()或者枚举实例调用$enum()的方式,来获取值枚举的值或纯枚举的名。

这样,就可以直接使用枚举作为数组键:

'statuses' => [
    TaskStatus::INCOMPLETE() => ['some configuration'],
    TaskStatus::COMPLETED() => ['other configuration'],
],

或者可以直接调用任何其他case:

public function updateStatus(int $status): void;

$task->updateStatus(TaskStatus::COMPLETED());

要点:这一切都无需追加->value

TaskStatus::CANCELED; // => TaskStatus 实例
TaskStatus::CANCELED(); // => 2

使用静态调用方式获取基础值

TaskStatus::INCOMPLETE(); // 0
TaskStatus::COMPLETED(); // 1
TaskStatus::CANCELED(); // 2
Role::ADMINISTRATOR(); // 'ADMINISTRATOR'
Role::SUBSCRIBER(); // 'SUBSCRIBER'
Role::GUEST(); // 'GUEST'

调用实例方式获取基础值

public function updateStatus(TaskStatus $status, Role $role)
{
    $this->record->setStatus($status(), $role());
}

增强

助手为你提供了许多静态方法来增强枚举使用的体验。

Names

返回枚举中所有case ->name属性值的列表数组。

TaskStatus::names(); // ['INCOMPLETE', 'COMPLETED', 'CANCELED']
Role::names(); // ['ADMINISTRATOR', 'SUBSCRIBER', 'GUEST']

Values

返回枚举中所有case ->value属性值的列表数组,如果在纯枚举中调用,它将与::names()结果一样。

TaskStatus::values(); // [0, 1, 2]
Role::values(); // ['ADMINISTRATOR', 'SUBSCRIBER', 'GUEST']

Options

返回一个数组,该数组的键是枚举中每一个case实例()调用值,具有唯一性;而该数组的值是枚举中每一个case实例的->label()返回值。此方法能够轻松的将一个枚举转化成下拉框中的候选项:

TaskStatus::options();
/*
    [
        0 => 'Incomplete',
        1 => 'Completed',
        2 => 'Canceled'
    ]
*/
Role::options();
/*
    [
        'ADMINISTRATOR' => 'Administrator',
        'SUBSCRIBER' => 'Subscriber',
        'GUEST' => 'Guest'
    ]
*/

Tables

返回一个列表数组,他们当中的每一项都是一个case实例的映射数组,如果实例中有添加Meta注解,那么case实例的映射数组中将包含更多内容。

TaskStatus::tables();
/*
    [
        ['name' => 'INCOMPLETE', 'value' => 0],
        ['name' => 'COMPLETED', 'value' => 1],
        ['name' => 'CANCELED', 'value' => 2]
    ]
*/
Role::tables();
/*
    [
        ['name' => 'ADMINISTRATOR'],
        ['name' => 'SUBSCRIBER'],
        ['name' => 'GUEST']
    ]
*/

From

此助手为纯枚举中添加了from()tryFrom()方法,并且添加了fromName()tryFromName()公共方法。

重要提示:

  • 值枚举 实例已经实现了源生的from()tryFrom()方法,这些方法不会被此Trait覆盖,试图重写值枚举中的这些方法会导致致命错误。
  • 纯枚举只有命名case而没有值,因此from()tryFrom()方法在功能上等效于fromName()tryFromName()
使用from()方法
Role::from('ADMINISTRATOR'); // Role::ADMINISTRATOR
Role::from('NOBODY'); // Error: ValueError
使用tryFrom()方法
Role::tryFrom('GUEST'); // Role::GUEST
Role::tryFrom('NEVER'); // null
使用fromName()方法
TaskStatus::fromName('INCOMPLETE'); // TaskStatus::INCOMPLETE
TaskStatus::fromName('MISSING'); // Error: ValueError
Role::fromName('SUBSCRIBER'); // Role::SUBSCRIBER
Role::fromName('HACKER'); // Error: ValueError
使用tryFromName()方法
TaskStatus::tryFromName('COMPLETED'); // TaskStatus::COMPLETED
TaskStatus::tryFromName('NOTHING'); // null
Role::tryFromName('GUEST'); // Role::GUEST
Role::tryFromName('TESTER'); // null

Random

返回一个随机的case。

TaskStatus::random(); // TaskStatus::COMPLETED
Role::random(); // Role::GUEST

Meta

此功能允许你将Meta数据添加到枚举case中,它是通过php注解的方式使用的。

use BiiiiiigMonster\LaravelEnum\Concerns\EnumTraits;
use App\Enums\Metas\{Description, Color};

enum TaskStatus: int
{
    use EnumTraits;

    #[Description('Incomplete Task')] #[Color('red')]
    case INCOMPLETE = 0;

    #[Description('Completed Task')] #[Color('green')]
    case COMPLETED = 1;

    #[Description('Canceled Task')] #[Color('gray')]
    case CANCELED = 2;
}

创建Meta注解

每个Meta注解都是作为一个类存在的,它必须继承BiiiiiigMonster\LaravelEnum\Concerns\Meta类。

use BiiiiiigMonster\LaravelEnum\Concerns\Meta;

#[Attribute]
class Color extends Meta {}

#[Attribute]
class Description extends Meta {}

在注解中,你可以自定义一些内容。例如,你可能希望使用与从类名派生的方法名称不同的方法名称(默认情况下,Description变为description()),可以在注解中定义alias静态属性:

#[Attribute]
class Description extends Meta
{
    public static string $alias = 'note';
}

基于上面的改动,case的->description()将可以作为->note()访问。

你还可以自定义传递的Meta注解值。例如,要包装像text-{$color}-500这样的颜色名称,你需要添加以下transform()方法:

#[Attribute]
class Color extends Meta
{
    protected function transform(mixed $value): string
    {
        return "text-{$value}-500";
    }
}

现在,返回的颜色将被正确转换:

TaskStatus::COMPLETED->color(); // 'text-green-500'

访问Meta数据

通过访问注解类方法名称,可以获得meta值:

TaskStatus::INCOMPLETE->description(); // 'Incomplete Task'
TaskStatus::COMPLETED->color(); // 'green'

此外,::tables()静态方法可以返回每个实例上的所有Meta注解映射。

$tables = TaskStatus::tables();

// $tables
[
    [
        'name' => 'INCOMPLETE',
        'value' => 0,
        'description' => 'Incomplete Task',
        'color' => 'red'
    ],
    [
        'name' => 'COMPLETED',
        'value' => 1,
        'description' => 'Completed Task',
        'color' => 'green'
    ],
    [
        'name' => 'CANCELED',
        'value' => 2,
        'description' => 'Canceled Task',
        'color' => 'gray'
    ]
]

使用fromMeta()方法

同样,你也可以通过Meta实例获得枚举case实例:

$green = Color::make('green');// new Color('green');
$blue = Color::make('blue');// new Color('blue');

TaskStatus::fromMeta($green); // TaskStatus::COMPLETED
TaskStatus::fromMeta($blue); // Error: ValueError

使用tryFromMeta()方法

TaskStatus::tryFromMeta($green); // TaskStatus::COMPLETED
TaskStatus::tryFromMeta($blue); // null

表单验证

通常,我们需要将应用程序的传入数据限制在指定的枚举中,laravel提供了基本规则,但在这里我们已经完善了它。

数组语法验证

你可以对规则使用array语法。

Enum

验证参数是否是给定枚举的实例,它类似于Enum规则,并且可以支持纯枚举。

use BiiiiiigMonster\LaravelEnum\Rules\Enum;

public function store(Request $request)
{
    $this->validate($request, [
        'status' => ['required', new Enum(TaskStatus::class)],
        'role' => ['required', new Enum(Role::class)],
    ]);
}

EnumMeta

此外,验证参数是否是给定枚举中给定Meta的实例。

use BiiiiiigMonster\LaravelEnum\Rules\EnumMeta;

public function store(Request $request)
{
    $this->validate($request, [
        'color' => ['required', new EnumMeta(TaskStatus::class, Color::class)],
    ]);
}

EnumMeta规则有两个参数,第一个为给定枚举,第二个为给定Meta注解类,如果参数名称和Meta方法名称相同,可以省略第二个参数:

'color' => ['required', new EnumMeta(TaskStatus::class)],

管道语法验证

你也可以对规则使用pipe语法。

  • enumerate: enum_class
  • enum_meta: enum_class,[meta_attribute]
'status' => 'required|enumerate:' . TaskStatus::class,
'color' => 'required|enum_meta:' . TaskStatus::class . ',' . Color::class,

验证消息

如果需要,您可以在验证失败时修改错误消息。运行以下命令将语言文件发布到lang文件夹:

php artisan vendor:publish --provider="BiiiiiigMonster\LaravelEnum\EnumServiceProvider" --tag="translations"

本地化

标签

枚举case是描述性的,我们为此添加了翻译功能。你可以使用Laravel内置的本地化功能来翻译枚举实例的->label()方法返回的字符串。

为你支持的每种语言添加一个新的enums.php翻译文件。在本例中,有一个用于英语,一个用于西班牙语:

// lang/en/enums.php
<?php declare(strict_types=1);

use App\Enums\TaskStatus;

return [

    TaskStatus::class => [
        TaskStatus::INCOMPLETE() => 'Incomplete',
        TaskStatus::COMPLETED() => 'Completed',
        TaskStatus::CANCELED() => 'Canceled',
    ],

];
// lang/es/enums.php
<?php declare(strict_types=1);

use App\Enums\TaskStatus;

return [

    TaskStatus::class => [
        TaskStatus::INCOMPLETE() => 'Incompleto',
        TaskStatus::COMPLETED() => 'Completo',
        TaskStatus::CANCELED() => 'Cancelación',
    ],

];

现在,你只需要确保你的枚举实现了Localized接口,如下所示:

use BiiiiiigMonster\LaravelEnum\Concerns\EnumTraits;
use BiiiiiigMonster\LaravelEnum\Contracts\Localizable;

enum TaskStatus: int implements Localizable
{
    use EnumTraits;
    // ...
}

->label()方法现在将在本地化文件中查找该翻译字符串:

// en/enums.php
TaskStatus::CANCELED->label();// 'Canceled'

// es/enums.php
TaskStatus::CANCELED->label();// 'Cancelación'

并且::options()静态方法返回的数组的值也被本地化:

// en/enums.php
TaskStatus::options();// [0 => 'Incomplete', 1 => 'Completed', 2 => 'Canceled']

// es/enums.php
TaskStatus::options();// [0 => 'Incompleto', 1 => 'Completo', 2 => 'Cancelación']

命令行

如果你希望IDE自动完成代码提示,你可以通过artisan命令生成PHPDoc注释。

默认情况下,app/Enums路径中的所有枚举都将生成注释(你可以通过--folder来指定文件夹路径):

php artisan enum:phpdoc

此外,还可以通过指定枚举类名为单个类生成注释:

php artisan enum:phpdoc "App\Enums\TaskStatus"
use BiiiiiigMonster\LaravelEnum\Concerns\EnumTraits;
use App\Enums\Metas\{Description, Color};

/**
* @method static int INCOMPLETE()
* @method static int COMPLETED()
* @method static int CANCELED()
* @method mixed description()
* @method mixed color()
*/
enum TaskStatus: int
{
    use EnumTraits;
    // ...
}
本作品采用《CC 协议》,转载必须注明作者和本文链接
《L05 电商实战》
从零开发一个电商项目,功能包括电商后台、商品 & SKU 管理、购物车、订单管理、支付宝支付、微信支付、订单退款流程、优惠券等
《L03 构架 API 服务器》
你将学到如 RESTFul 设计风格、PostMan 的使用、OAuth 流程,JWT 概念及使用 和 API 开发相关的进阶知识。
讨论数量: 2

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!