biiiiiigmonster/laravel-enum

laravel enum helper base php version 8.1

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

Enum helper for laravel10 based on the enum feature of php 8.1.

Installation

You can install the package via composer:

composer require biiiiiigmonster/laravel-enum

Usage

To get started, enums typically live in the app\Enums directory. You may use the make:enum Artisan command to generate a new enum:

php artisan make:enum TaskStatus

if you want to generate a backed enum, you may use the make:enum Artisan command with --type options:

php artisan make:enum TaskStatus --type=int

and also you can apply the trait on your exists enum:

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

Invokable

This helper lets you get the primitive value of a backed enum, or the name of a pure enum, by "invoking" it — either statically (MyEnum::FOO() instead of MyEnum::FOO), or as an instance ($enum()).

That way, you can use enums as array keys:

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

Or access the underlying primitives for any other use cases:

public function updateStatus(int $status): void;

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

The main point: this is all without having to append ->value to everything:

TaskStatus::CANCELED; // => TaskStatus instance
TaskStatus::CANCELED(); // => 2

Use static calls to get the primitive value

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

Invoke instances to get the primitive value

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

Enhancement

Helper provide many static methods for you to enhance experience with enums.

Names

This helper returns a list of case names in the enum.

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

Values

This helper returns a list of case values for backed enums, or a list of case names for pure enums (making this functionally equivalent to ::names() for pure Enums)

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

Options

This helper returns an array, that key is each instance invoke () return, and value is instance ->label() returns.

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

Tables

This helper returns a list of case map array that each instance, if instance append attributes that extended Meta, the map array including more.

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

From

This helper adds from() and tryFrom() to pure enums, and adds fromName() and tryFromName() to all enums.

Important Notes:

  • BackedEnum instances already implement their own from() and tryFrom() methods, which will not be overridden by this trait. Attempting to override those methods in a BackedEnum causes a fatal error.
  • Pure enums only have named cases and not values, so the from() and tryFrom() methods are functionally equivalent to fromName() and tryFromName()
Use the from() method
Role::from('ADMINISTRATOR'); // Role::ADMINISTRATOR
Role::from('NOBODY'); // Error: ValueError
Use the tryFrom() method
Role::tryFrom('GUEST'); // Role::GUEST
Role::tryFrom('NEVER'); // null
Use the fromName() method
TaskStatus::fromName('INCOMPLETE'); // TaskStatus::INCOMPLETE
TaskStatus::fromName('MISSING'); // Error: ValueError
Role::fromName('SUBSCRIBER'); // Role::SUBSCRIBER
Role::fromName('HACKER'); // Error: ValueError
Use the tryFromName() method
TaskStatus::tryFromName('COMPLETED'); // TaskStatus::COMPLETED
TaskStatus::tryFromName('NOTHING'); // null
Role::tryFromName('GUEST'); // Role::GUEST
Role::tryFromName('TESTER'); // null

Random

This helper returns an instance of case by random.

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

Default Case

Sometimes you may need to specify default case for your enum, which is easy as below: simply append the #[DefaultCase] attribute to the case:

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

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

Then use the ::default() static method to get this case instance:

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

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

Meta

This feature lets you add metadata to enum cases, it's used by way of attributes.

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

Creating meta attributes

To generate a new meta attributes, you may use the make:enumMeta Artisan command:

php artisan make:enumMeta Color

meta attribute needs to exist as an Attribute.

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

#[Attribute]
class Color extends Meta {}

#[Attribute]
class Description extends Meta {}

Inside the attribute, you can customize a few things. For instance, you may want to use a different method name than the one derived from the class name (Description becomes description() by default). To do that, define the alias static property on the meta:

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

With the code above, the ->description() of a case will be accessible as ->note().

Another thing you can customize is the passed value. For instance, to wrap a color name like text-{$color}-500, you'd add the following transform() method:

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

And now the returned color will be correctly transformed:

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

Access the metadata

By accessing the attribute method name, you can get the meta value:

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

Also, ::tables() static method can return all meta attribute maps on each instance.

$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'
    ]
]

Use the fromMeta() method

Similarly, you can also get the enum case instance through the meta instance.

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

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

Use the tryFromMeta() method

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

Validation

Usually, we need limit your application's incoming data to a specified enums, laravel provides the basic rule, but here we have perfected it.

Array Validation

You can use the 'array' syntax for rules.

Enum

Validate that a parameter is an instance of a given enum, it's similar to Enum Rules and can support pure enums.

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

Additionally, validate that a parameter is an instance of the given meta in the given enum.

use BiiiiiigMonster\LaravelEnum\Rules\EnumMeta;

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

EnumMeta rule takes two parameters, the first is given enum, the second is given meta, if parameter name is same of meta method name, you can omit it:

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

Pipe Validation

You can also use the 'pipe' syntax for rules.

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

Validation messages

If needed, you can modify the error message when validated fails.

Run the following command to publish the language files to your lang folder:

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

Localization

Labels

The enum instances are descriptive, and we have added translation capabilities for this. You can translate the strings returned by the enum instance's ->label() 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:

// 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',
    ],

];

Now, you just need to make sure that your enum implements the Localizable interface as demonstrated below:

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

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

Alternatively, when creating with the make:enum Artisan command, add the --local option:

php artisan make:enum TaskStatus --local

The ->label() method will now look for the value in your localization files:

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

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

and the ::options() static method returned array's value also be localized:

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

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

Artisan Command

If you want your IDE to autocomplete the static instantiation helpers, you can generate 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:phpdoc

Also, you can annotate a single class by specifying the class name

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

Testing

composer test

Changelog

Please see CHANGELOG for more information on what has changed recently.

References

License

The MIT License (MIT). Please see License File for more information.