biiiiiigmonster/laravel-enum

基于 PHP 8.1 的 Laravel 枚举助手

v1.3.0 2023-08-03 02:10 UTC

README

Latest Version on Packagist GitHub Tests Action Status GitHub Code Style Action Status Coverage Status Scrutinizer Code Quality Total Downloads

基于 PHP 8.1 枚举特性的 Laravel 10 枚举助手。

安装

您可以通过 composer 安装此包。

composer require biiiiiigmonster/laravel-enum

使用方法

要开始使用,枚举通常位于 app\Enums 目录。您可以使用 make:enum Artisan 命令生成一个新的枚举。

php artisan make:enum TaskStatus

如果您想生成一个 支持值的枚举,您可以使用带有 --type 选项的 make:enum Artisan 命令。

php artisan make:enum TaskStatus --type=int

同时,您也可以将 trait 应用到现有的枚举上。

use BiiiiiigMonster\LaravelEnum\Concerns\EnumTraits;

// pure enum.
enum Role
{
    use EnumTraits;

    case ADMINISTRATOR;
    case SUBSCRIBER;
    case GUEST;
}

// backed enum.
enum TaskStatus: int
{
    use EnumTraits;

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

可调用的

此助手让您可以通过“调用”枚举来获取其原始值或纯枚举的名称——无论是静态地(MyEnum::FOO() 代替 MyEnum::FOO),还是作为实例($enum())。

这样,您可以使用枚举作为数组键。

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

或访问任何其他用例的基础原始值。

public function updateStatus(int $status): void;

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

主要观点:这一切都不需要为每个元素添加 ->value

TaskStatus::CANCELED; // => TaskStatus instance
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());
}

增强

助手提供许多静态方法,以增强您使用枚举的体验。

名称

此助手返回枚举中的情况 名称 列表。

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

此助手返回支持值的枚举的情况 列表,或纯枚举的情况 名称 列表(使此函数与纯枚举的 ::names() 函数等效)。

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

选项

此助手返回一个数组,键是每个实例调用 () 返回的值,值是实例 ->label() 返回的值。

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

表格

此助手返回每个实例的情况映射数组列表,如果实例附加了扩展 Meta 的属性,映射数组将包含更多内容。

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

此助手将 from()tryFrom() 添加到纯枚举,并将 fromName()tryFromName() 添加到所有枚举。

重要说明:

  • BackedEnum 实例已经实现了自己的 from()tryFrom() 方法,不会被此 trait 覆盖。在 BackedEnum 中尝试覆盖这些方法会导致致命错误。
  • 纯枚举只有命名情况而没有值,因此 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

随机

此助手返回通过随机选择的实例。

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

默认情况

有时您可能需要为枚举指定默认情况,这很简单:只需将 #[DefaultCase] 属性附加到情况即可。

use BiiiiiigMonster\LaravelEnum\Attributes\DefaultCase;
use BiiiiiigMonster\LaravelEnum\Concerns\EnumTraits;

enum Role
{
    use EnumTraits;
    
    #[DefaultCase]
    case ADMIN;
    
    case GUEST;
}

然后使用 ::default() 静态方法获取此情况实例。

Role::default(); // Role::ADMIN

Role::ADMIN->isDefault(); // true

元数据

此功能允许您向枚举情况添加元数据,它通过属性的方式使用。

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;
}

创建元属性

要生成新的元属性,您可以使用 make:enumMeta Artisan 命令。

php artisan make:enumMeta Color

元属性需要作为一个属性存在。

use BiiiiiigMonster\LaravelEnum\Concerns\Meta;
use Attribute;

#[Attribute]
class Color extends Meta {}

#[Attribute]
class Description extends Meta {}

在属性中,您可以自定义一些内容。例如,您可能想使用与类名派生的不同方法名(默认情况下 Description 变为 description())。为此,请在元数据上定义静态属性 alias

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

使用上面的代码,案例的 ->description() 将作为 ->note() 可访问。

您还可以自定义传递的值。例如,要包装颜色名称如 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'

访问元数据

通过访问属性方法名称,您可以获取元数据值。

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

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

$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() 方法

同样,您也可以通过元实例获取枚举案例实例。

$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' 语法规则。

枚举

验证一个参数是否是给定枚举的实例,它与 枚举规则 类似,并支持纯枚举。

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)],
    ]);
}

枚举元数据

此外,验证一个参数是否是给定枚举中给定元数据的实例。

use BiiiiiigMonster\LaravelEnum\Rules\EnumMeta;

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

EnumMeta 规则接受两个参数,第一个是给定的枚举,第二个是给定的元数据,如果参数名称与元数据方法名称相同,则可以省略。

'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"

本地化

标签

枚举实例是描述性的,我们已经添加了翻译功能。您可以使用 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',
    ],

];

现在,您只需要确保您的枚举实现了如以下示例所示的 Localizable 接口。

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

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

或者,当使用 make:enum Artisan 命令创建时,添加 --local 选项。

php artisan make:enum TaskStatus --local

现在,->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']

Artisan 命令

如果您希望您的 IDE 自动完成静态实例辅助工具,您可以通过 artisan 命令生成 PHPDoc 注释。

默认情况下,app/Enums 中的所有 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;
    // ...
}

测试

composer test

变更日志

有关最近更改的更多信息,请参阅 CHANGELOG

参考

许可

MIT 许可证 (MIT)。有关更多信息,请参阅 许可文件