Code Monkey home page Code Monkey logo

laravel-enum's Introduction

Laravel Enum

Packagist Stable Version Packagist downloads MIT Software License

Using this library is no longer recommended

Using this library is no longer recommended, especially for new projects. PHP 8.1 supports enums natively.

See #332.

About Laravel Enum

Simple, extensible and powerful enumeration implementation for Laravel.

  • Enum key value pairs as class constants
  • Full-featured suite of methods
  • Enum instantiation
  • Flagged/Bitwise enums
  • Type hinting
  • Attribute casting
  • Enum artisan generator
  • Validation rules for passing enum key or values as input parameters
  • Localization support
  • Extendable via Macros

Created by Ben Sampson

Jump To

Documentation for older versions

You are reading the documentation for 6.x.

Please see the upgrade guide for information on how to upgrade to the latest version.

Guide

I wrote a blog post about using laravel-enum: https://sampo.co.uk/blog/using-enums-in-laravel

Installation

Requires PHP 8, and Laravel 9 or 10.

composer require bensampo/laravel-enum

Migrate to Native PHP Enums

PHP 8.1 supports enums natively. You can migrate your usages of BenSampo\Enum\Enum to native PHP enums using the following steps.

Make sure you meet the following requirements:

  • PHP 8.1 or higher
  • Laravel 10 or higher
  • Rector 0.17 or higher, your rector.php includes all relevant files
  • Latest version of this library

Depending on the size of your project, you may choose to migrate all enums at once, or migrate just a couple or one enum at a time.

  • Convert all enums at once: php artisan enum:to-native

  • Pass the fully qualified class name of an enum to limit the conversion: php artisan enum:to-native "App\Enums\UserType"

    This is necessary if any enums are used during the bootstrap phase of Laravel, the conversion of their usages interferes with Larastan and prevents a second run of Rector from working.

Review and validate the code changes for missed edge cases:

  • See Unimplemented
  • Enum::coerce(): If only values were passed, you can replace it with tryFrom(). If keys or instances could also be passed, you might need additional logic to cover this.
  • Enum::$description and Enum::getDescription(): Implement an alternative.
  • try/catch-blocks that handle BenSampo\Enum\Exceptions\InvalidEnumKeyException or BenSampo\Enum\Exceptions\InvalidEnumMemberException. Either catch the ValueError thrown by native enums, or switch to using tryFrom() and handle null.

Once all enums are converted, you can remove your dependency on this library.

Enum Library

Browse and download from a list of commonly used, community contributed enums.

Enum library →

Basic Usage

Enum Definition

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 declare(strict_types=1);

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 simply access them like any other class constant.

UserType::Administrator // Has a value of 0

Instantiation

It can be useful to instantiate enums in order to pass them between functions with 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 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:annotate

You can annotate a single class by specifying the class name.

php artisan enum:annotate "App\Enums\UserType"

Instance Properties

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; // 3
$userType->description; // Super Administrator

This is particularly useful if you're passing an enum instance to a blade view.

Instance Casting

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 // '3'

Instance Equality

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::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, and use notIn to check if instance value is not in an array of values. Iterables can also be checked against.

$admin = 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

$admin->notIn([UserType::Moderator, UserType::Administrator]);     // false
$admin->notIn([UserType::Moderator(), UserType::Administrator()]); // false

$admin->notIn([UserType::Moderator, UserType::Subscriber]);        // true
$admin->notIn(['random-value']);                                   // true

The instantiated enums are not singletons, rather a new object is created every time. Thus, strict comparison === of different enum instances will always return false, no matter the value. In contrast, loose comparison == will depend on the value.

$admin = UserType::Administrator();

$admin === UserType::Administrator();                    // false
UserType::Administrator() === UserType::Administrator(); // false
$admin === UserType::Moderator();                        // false

$admin === $admin;                                       // true

$admin == UserType::Administrator(); // true
$admin == UserType::Administrator;   // true

$admin == UserType::Moderator();     // false
$admin == UserType::Moderator;       // false

Type Hinting

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

Flagged/Bitwise Enum

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

Defining values

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

Defining shortcuts

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

Instantiating a flagged enum

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.

Empty flagged 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

Flagged enum methods

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.

setFlags(array $flags): Enum

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.

addFlag($flag): Enum

Add the given flag to the enum

$permissions = UserPermissions::flags([UserPermissions::ReadComments]);
$permissions->addFlag(UserPermissions::EditComments); // Flags are now: ReadComments, EditComments.

addFlags(array $flags): Enum

Add the given flags to the enum

$permissions = UserPermissions::flags([UserPermissions::ReadComments]);
$permissions->addFlags([UserPermissions::EditComments, UserPermissions::WriteComments]); // Flags are now: ReadComments, EditComments, WriteComments.

addAllFlags(): Enum

Add all flags to the enum

$permissions = UserPermissions::flags([UserPermissions::ReadComments]);
$permissions->addAllFlags(); // Enum now has all flags

removeFlag($flag): Enum

Remove the given flag from the enum

$permissions = UserPermissions::flags([UserPermissions::ReadComments, UserPermissions::WriteComments]);
$permissions->removeFlag(UserPermissions::ReadComments); // Flags are now: WriteComments.

removeFlags(array $flags): Enum

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.

removeAllFlags(): Enum

Remove all flags from the enum

$permissions = UserPermissions::flags([UserPermissions::ReadComments, UserPermissions::WriteComments]);
$permissions->removeAllFlags();

hasFlag($flag): bool

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

hasFlags(array $flags): bool

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

notHasFlag($flag): bool

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

notHasFlags(array $flags): bool

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

getFlags(): Enum[]

Return the flags as an array of instances.

$permissions = UserPermissions::flags([UserPermissions::ReadComments, UserPermissions::WriteComments]);
$permissions->getFlags(); // [UserPermissions::ReadComments(), UserPermissions::WriteComments()];

hasMultipleFlags(): bool

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

getBitmask(): int

Get the bitmask for the enum.

UserPermissions::Member()->getBitmask(); // 11;
UserPermissions::Moderator()->getBitmask(); // 111;
UserPermissions::Admin()->getBitmask(); // 1111;
UserPermissions::DeleteComments()->getBitmask(); // 1000;

Flagged enums in Eloquent queries

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:

hasFlag($column, $flag): Builder

User::hasFlag('permissions', UserPermissions::DeleteComments())->get();

notHasFlag($column, $flag): Builder

User::notHasFlag('permissions', UserPermissions::DeleteComments())->get();

hasAllFlags($column, $flags): Builder

User::hasAllFlags('permissions', [UserPermissions::EditComment(), UserPermissions::ReadComment()])->get();

hasAnyFlags($column, $flags): Builder

User::hasAnyFlags('permissions', [UserPermissions::DeleteComments(), UserPermissions::EditComments()])->get();

Attribute Casting

You may cast model attributes to enums using Laravel'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();

Customising $model->toArray() behaviour

When 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 return to 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"
// }

Casting underlying native types

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.

Model Annotation

If you're casting attributes on your model to enums, the laravel-ide-helper package can be used to automatically generate property docblocks for you.

Migrations

Recommended

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

Using enum column type

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

Validation

Array Validation

Enum value

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.

Enum key

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

Enum instance

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

Pipe Validation

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,

Localization

Validation messages

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

php artisan vendor:publish --provider="BenSampo\Enum\EnumServiceProvider" --tag="translations"

Enum descriptions

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.

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

use App\Enums\UserType;

return [

    UserType::class => [
        UserType::Administrator => 'Administrator',
        UserType::SuperAdministrator => 'Super administrator',
    ],

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

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.

Customizing descriptions

Customizing class description

If you'd like to return a custom description for your enum class, add a Description attribute to your Enum class:

use BenSampo\Enum\Enum;
use BenSampo\Enum\Attributes\Description;

#[Description('List of available User types')]
final class UserType extends Enum
{
    ...
}

Calling UserType::getClassDescription() now returns List of available User types instead of User type.

You may also override the getClassDescription method on the base Enum class if you wish to have more control of the description.

Customizing value descriptions

If you'd like to return a custom description for your enum values, add a Description attribute to your Enum constants:

use BenSampo\Enum\Enum;
use BenSampo\Enum\Attributes\Description;

final class UserType extends Enum
{
    const Administrator = 'Administrator';

    #[Description('Super admin')]
    const SuperAdministrator = 'SuperAdministrator';
}

Calling UserType::SuperAdministrator()->description now returns Super admin instead of Super administrator.

You may also override the getDescription method on the base Enum class if you wish to have more control of the description.

Extending the Enum Base Class

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 a service providers' boot method.

Laravel Nova Integration

Use the nova-enum-field package by Simple Squid to easily create fields for your Enums in Nova. See their readme for usage.

PHPStan Integration

If you are using PHPStan for static analysis, enable the extension for:

  • proper recognition of the magic instantiation methods
  • detection of duplicate enum values

Use PHPStan Extension Installer or add the following to your projects phpstan.neon includes:

includes:
- vendor/bensampo/laravel-enum/extension.neon

Artisan Command List

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

php artisan enum:to-native

See migrate to native PHP enums.

Enum Class Reference

static getKeys(mixed $values = null): array

Returns an array of all or a custom set of the keys for an enum.

UserType::getKeys(); // Returns ['Administrator', 'Moderator', 'Subscriber', 'SuperAdministrator']
UserType::getKeys(UserType::Administrator); // Returns ['Administrator']
UserType::getKeys(UserType::Administrator, UserType::Moderator); // Returns ['Administrator', 'Moderator']
UserType::getKeys([UserType::Administrator, UserType::Moderator]); // Returns ['Administrator', 'Moderator']

static getValues(mixed $keys = null): array

Returns an array of all or a custom set of the values for an enum.

UserType::getValues(); // Returns [0, 1, 2, 3]
UserType::getValues('Administrator'); // Returns [0]
UserType::getValues('Administrator', 'Moderator'); // Returns [0, 1]
UserType::getValues(['Administrator', 'Moderator']); // Returns [0, 1]

static getKey(mixed $value): string

Returns the key for the given enum value.

UserType::getKey(1); // Returns 'Moderator'
UserType::getKey(UserType::Moderator); // Returns 'Moderator'

static getValue(string $key): mixed

Returns the value for the given enum key.

UserType::getValue('Moderator'); // Returns 1

static hasKey(string $key): bool

Check if the enum contains a given key.

UserType::hasKey('Moderator'); // Returns 'True'

static hasValue(mixed $value, bool $strict = true): bool

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'

static getClassDescription(): string

Returns the class name in sentence case for the enum class. It's possible to customize the description if the guessed description is not appropriate.

UserType::getClassDescription(); // Returns 'User type'

static getDescription(mixed $value): string

Returns the key in sentence case for the enum value. It's possible to customize the description if the guessed description is not appropriate.

UserType::getDescription(3); // Returns 'Super administrator'
UserType::getDescription(UserType::SuperAdministrator); // Returns 'Super administrator'

static getRandomKey(): string

Returns a random key from the enum. Useful for factories.

UserType::getRandomKey(); // Returns 'Administrator', 'Moderator', 'Subscriber' or 'SuperAdministrator'

static getRandomValue(): mixed

Returns a random value from the enum. Useful for factories.

UserType::getRandomValue(); // Returns 0, 1, 2 or 3

static getRandomInstance(): mixed

Returns a random instance of the enum. Useful for factories.

UserType::getRandomInstance(); // Returns an instance of UserType with a random value

static asArray(): array

Returns the enum key value pairs as an associative array.

UserType::asArray(); // Returns ['Administrator' => 0, 'Moderator' => 1, 'Subscriber' => 2, 'SuperAdministrator' => 3]

static asSelectArray(): array

Returns the enum for use in a select as value => description.

UserType::asSelectArray(); // Returns [0 => 'Administrator', 1 => 'Moderator', 2 => 'Subscriber', 3 => 'Super administrator']

static fromValue(mixed $enumValue): Enum

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

static getInstances(): array

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

static coerce(mixed $enumKeyOrValue): ?Enum

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)

Stubs

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"

laravel-enum's People

Contributors

ankurk91 avatar atymic avatar bensampo avatar chapeupreto avatar christian-thomas avatar crynobone avatar daniyal-javani avatar heywhy avatar joecianflone avatar lidoma avatar me-shaon avatar mikkoaf avatar musa11971 avatar nevoss avatar obennaci avatar portablesteve avatar propaganistas avatar rodrigopedra avatar rudashi avatar shaffe-fr avatar spawnia avatar sunaoka avatar sy-dante avatar szepeviktor avatar uguurozkan avatar uintaam avatar vaughany avatar wimski avatar xint0-elab avatar zarunet avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

laravel-enum's Issues

Trait method getAttributeValue collision

Hi,

I'm trying to use this package within a model which already has an implementation of the getAttributeValue function and I then get an error due to the duplicity of this method definition (one in my model and one in the laravel-enum package).

PHP Fatal error:  Trait method getAttributeValue has not been applied, because there are collisions with other trait methods

How can I use this package in that context ?

Attribute casting in model toArray

Hi Ben

I may be missing something, so please excuse me if I am. I've also abstracted the problem a bit using the example in the README.

I create a class such as this which uses the Enum attribute casting:

class Example extends Model
{
    use CastsEnums;
    
    protected $enumCasts = [
        'user_type' => UserType::class,
    ];
}

After seeding, I run Example::first()->toArray() and it returns something like this:

[
     'user_type' => 2
]

Whereas I expect the value to be cast and return something like this:

[
     'user_type' => App\Enums\UserType{#1234
          +key: "Guest"
          +value: 2
          +description: "Guest"
        }
]

If I run Example::first()->user_type, however, the casting works perfectly.

Am I doing something wrong, or is the toArray method not supported? If it is the latter, is it possible to include support for it?

Thank you!

As the test for hasValue in the Enum constructor is strict, it fails with form request data

I have used ::toSelectArray() to generate the select, then the EnumValue rule in the Request validator (having to switch strict to false, as the value is a string rather than integer).
As a result, trying to set the model value (which has been enumCast) fails, as it uses a strict test in the Enum constructor.
I don't think I've missed a better method? The casting is supposed to be done by enumCast, so casting beforehand to avoid the constructor failing seems pointless. Does the constructor need to avoid using strict comparisons?

getDescription overwrites Localization

when implementing a custom getDescription() method, localization via LocalizedEnum stops working. Maybe I'm using it wrong, but I would have preferred the getDescription() implementation to work as a fallback if there's no localization for the particular language.

Setting using casting

Hey,

Loving the new updates and just trying to refactor to use enum casting but having an issue. Not sure if it's a feature or bug but thought I'd ask anyway.

So I thought to set the user status using the static method as follows:

User::create([..., 'status' => UserStatus::Approved()]);

This works fine when setting as it casts down to the value as an int. But when fetching back out of DB, the int is pulled as a string and when attempting to cast back to a UserStatus enum it fails on the strict checking and I get the following exception msg:

BenSampo\Enum\Exceptions\InvalidEnumMemberException : Value 0 doesn't exist in [0, 1]

So I thought to set the original cast as well which I was using before your enum casting. So the status attribute would cast to an int before being cast to the UserStatus enum.

This seems to work when fetching, but then fails when setting. When setting via a new user create method call, as shown above, I get the following error:

ErrorException : Object of class App\Enums\UserStatus could not be converted to int

It seems we need to check when setting if it's already an enum object or not and act accordingly.

I'm surprised this hasn't come up before though, so it's possible I'm missing something. I could work around it by using UserStatus::Approved as the value rather than an instance - perhaps that's the intended way...?

More than happy to provide a PR and tests if needed but thought I'd open the discussion first.

Thanks!
Lee

Failing tests

Considering UserType sample class, there are 3 failing tests:

on testEnumGetKey():

$this->assertEquals('StringTest', UserType::getKey('TEST'));

on testEnumGetValue():

$this->assertEquals('TEST', UserType::getValue('StringTest'));

on testEnumGetDescription():

$this->assertEquals('StringTest', UserType::getDescription('TEST'));

Such failings are because of scalar type declaration used by those methods.

Furthermore, because switch/case does loose comparison (for example ,TEST == 0 evaluates to true) , it's better to change Enum.stub file as well.

Error type-hinting in controller

Maybe I'm missing how the type-hinting works but when I try to type hint an enum in a controller action I get this error...

Illuminate\Contracts\Container\BindingResolutionException thrown with message "Unresolvable dependency resolving [Parameter #0 [ <required> $enumValue ]] in class App\Enums\Report\Scope"

Stacktrace:
#67 Illuminate\Contracts\Container\BindingResolutionException in /var/www/app/vendor/laravel/framework/src/Illuminate/Container/Container.php:973
#66 Illuminate\Container\Container:unresolvablePrimitive in /var/www/app/vendor/laravel/framework/src/Illuminate/Container/Container.php:911
#65 Illuminate\Container\Container:resolvePrimitive in /var/www/app/vendor/laravel/framework/src/Illuminate/Container/Container.php:852
#64 Illuminate\Container\Container:resolveDependencies in /var/www/app/vendor/laravel/framework/src/Illuminate/Container/Container.php:818
#63 Illuminate\Container\Container:build in /var/www/app/vendor/laravel/framework/src/Illuminate/Container/Container.php:667
#62 Illuminate\Container\Container:resolve in /var/www/app/vendor/laravel/framework/src/Illuminate/Container/Container.php:615
#61 Illuminate\Container\Container:make in /var/www/app/vendor/laravel/framework/src/Illuminate/Foundation/Application.php:757
#60 Illuminate\Foundation\Application:make in /var/www/app/vendor/laravel/framework/src/Illuminate/Routing/RouteDependencyResolverTrait.php:79
#59 Illuminate\Routing\ControllerDispatcher:transformDependency in /var/www/app/vendor/laravel/framework/src/Illuminate/Routing/RouteDependencyResolverTrait.php:46
#58 Illuminate\Routing\ControllerDispatcher:resolveMethodDependencies in /var/www/app/vendor/laravel/framework/src/Illuminate/Routing/RouteDependencyResolverTrait.php:27
#57 Illuminate\Routing\ControllerDispatcher:resolveClassMethodDependencies in /var/www/app/vendor/laravel/framework/src/Illuminate/Routing/ControllerDispatcher.php:41
#56 Illuminate\Routing\ControllerDispatcher:dispatch in /var/www/app/vendor/laravel/framework/src/Illuminate/Routing/Route.php:219
#55 Illuminate\Routing\Route:runController in /var/www/app/vendor/laravel/framework/src/Illuminate/Routing/Route.php:176
#54 Illuminate\Routing\Route:run in /var/www/app/vendor/laravel/framework/src/Illuminate/Routing/Router.php:680
#53 Illuminate\Routing\Router:Illuminate\Routing\{closure} in /var/www/app/vendor/laravel/framework/src/Illuminate/Routing/Pipeline.php:30
#52 Illuminate\Routing\Pipeline:Illuminate\Routing\{closure} in /var/www/app/app/Http/Middleware/SentryContext.php:47
#51 App\Http\Middleware\SentryContext:handle in /var/www/app/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php:163
#50 Illuminate\Pipeline\Pipeline:Illuminate\Pipeline\{closure} in /var/www/app/vendor/laravel/framework/src/Illuminate/Routing/Pipeline.php:53
#49 Illuminate\Routing\Pipeline:Illuminate\Routing\{closure} in /var/www/app/vendor/laravel/framework/src/Illuminate/Routing/Middleware/SubstituteBindings.php:41
#48 Illuminate\Routing\Middleware\SubstituteBindings:handle in /var/www/app/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php:163
#47 Illuminate\Pipeline\Pipeline:Illuminate\Pipeline\{closure} in /var/www/app/vendor/laravel/framework/src/Illuminate/Routing/Pipeline.php:53
#46 Illuminate\Routing\Pipeline:Illuminate\Routing\{closure} in /var/www/app/vendor/laravel/framework/src/Illuminate/Auth/Middleware/Authenticate.php:43
#45 Illuminate\Auth\Middleware\Authenticate:handle in /var/www/app/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php:163
#44 Illuminate\Pipeline\Pipeline:Illuminate\Pipeline\{closure} in /var/www/app/vendor/laravel/framework/src/Illuminate/Routing/Pipeline.php:53
#43 Illuminate\Routing\Pipeline:Illuminate\Routing\{closure} in /var/www/app/vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/VerifyCsrfToken.php:75
#42 Illuminate\Foundation\Http\Middleware\VerifyCsrfToken:handle in /var/www/app/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php:163
#41 Illuminate\Pipeline\Pipeline:Illuminate\Pipeline\{closure} in /var/www/app/vendor/laravel/framework/src/Illuminate/Routing/Pipeline.php:53
#40 Illuminate\Routing\Pipeline:Illuminate\Routing\{closure} in /var/www/app/vendor/laravel/framework/src/Illuminate/View/Middleware/ShareErrorsFromSession.php:49
#39 Illuminate\View\Middleware\ShareErrorsFromSession:handle in /var/www/app/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php:163
#38 Illuminate\Pipeline\Pipeline:Illuminate\Pipeline\{closure} in /var/www/app/vendor/laravel/framework/src/Illuminate/Routing/Pipeline.php:53
#37 Illuminate\Routing\Pipeline:Illuminate\Routing\{closure} in /var/www/app/vendor/laravel/framework/src/Illuminate/Session/Middleware/StartSession.php:56
#36 Illuminate\Session\Middleware\StartSession:handle in /var/www/app/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php:163
#35 Illuminate\Pipeline\Pipeline:Illuminate\Pipeline\{closure} in /var/www/app/vendor/laravel/framework/src/Illuminate/Routing/Pipeline.php:53
#34 Illuminate\Routing\Pipeline:Illuminate\Routing\{closure} in /var/www/app/vendor/laravel/framework/src/Illuminate/Cookie/Middleware/AddQueuedCookiesToResponse.php:37
#33 Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse:handle in /var/www/app/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php:163
#32 Illuminate\Pipeline\Pipeline:Illuminate\Pipeline\{closure} in /var/www/app/vendor/laravel/framework/src/Illuminate/Routing/Pipeline.php:53
#31 Illuminate\Routing\Pipeline:Illuminate\Routing\{closure} in /var/www/app/vendor/laravel/framework/src/Illuminate/Cookie/Middleware/EncryptCookies.php:66
#30 Illuminate\Cookie\Middleware\EncryptCookies:handle in /var/www/app/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php:163
#29 Illuminate\Pipeline\Pipeline:Illuminate\Pipeline\{closure} in /var/www/app/vendor/laravel/framework/src/Illuminate/Routing/Pipeline.php:53
#28 Illuminate\Routing\Pipeline:Illuminate\Routing\{closure} in /var/www/app/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php:104
#27 Illuminate\Pipeline\Pipeline:then in /var/www/app/vendor/laravel/framework/src/Illuminate/Routing/Router.php:682
#26 Illuminate\Routing\Router:runRouteWithinStack in /var/www/app/vendor/laravel/framework/src/Illuminate/Routing/Router.php:657
#25 Illuminate\Routing\Router:runRoute in /var/www/app/vendor/laravel/framework/src/Illuminate/Routing/Router.php:623
#24 Illuminate\Routing\Router:dispatchToRoute in /var/www/app/vendor/laravel/framework/src/Illuminate/Routing/Router.php:612
#23 Illuminate\Routing\Router:dispatch in /var/www/app/vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php:176
#22 Illuminate\Foundation\Http\Kernel:Illuminate\Foundation\Http\{closure} in /var/www/app/vendor/laravel/framework/src/Illuminate/Routing/Pipeline.php:30
#21 Illuminate\Routing\Pipeline:Illuminate\Routing\{closure} in /var/www/app/vendor/barryvdh/laravel-debugbar/src/Middleware/InjectDebugbar.php:65
#20 Barryvdh\Debugbar\Middleware\InjectDebugbar:handle in /var/www/app/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php:163
#19 Illuminate\Pipeline\Pipeline:Illuminate\Pipeline\{closure} in /var/www/app/vendor/laravel/framework/src/Illuminate/Routing/Pipeline.php:53
#18 Illuminate\Routing\Pipeline:Illuminate\Routing\{closure} in /var/www/app/vendor/fideloper/proxy/src/TrustProxies.php:57
#17 Fideloper\Proxy\TrustProxies:handle in /var/www/app/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php:163
#16 Illuminate\Pipeline\Pipeline:Illuminate\Pipeline\{closure} in /var/www/app/vendor/laravel/framework/src/Illuminate/Routing/Pipeline.php:53
#15 Illuminate\Routing\Pipeline:Illuminate\Routing\{closure} in /var/www/app/vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/TransformsRequest.php:21
#14 Illuminate\Foundation\Http\Middleware\TransformsRequest:handle in /var/www/app/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php:163
#13 Illuminate\Pipeline\Pipeline:Illuminate\Pipeline\{closure} in /var/www/app/vendor/laravel/framework/src/Illuminate/Routing/Pipeline.php:53
#12 Illuminate\Routing\Pipeline:Illuminate\Routing\{closure} in /var/www/app/vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/TransformsRequest.php:21
#11 Illuminate\Foundation\Http\Middleware\TransformsRequest:handle in /var/www/app/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php:163
#10 Illuminate\Pipeline\Pipeline:Illuminate\Pipeline\{closure} in /var/www/app/vendor/laravel/framework/src/Illuminate/Routing/Pipeline.php:53
#9 Illuminate\Routing\Pipeline:Illuminate\Routing\{closure} in /var/www/app/vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/ValidatePostSize.php:27
#8 Illuminate\Foundation\Http\Middleware\ValidatePostSize:handle in /var/www/app/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php:163
#7 Illuminate\Pipeline\Pipeline:Illuminate\Pipeline\{closure} in /var/www/app/vendor/laravel/framework/src/Illuminate/Routing/Pipeline.php:53
#6 Illuminate\Routing\Pipeline:Illuminate\Routing\{closure} in /var/www/app/vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/CheckForMaintenanceMode.php:62
#5 Illuminate\Foundation\Http\Middleware\CheckForMaintenanceMode:handle in /var/www/app/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php:163
#4 Illuminate\Pipeline\Pipeline:Illuminate\Pipeline\{closure} in /var/www/app/vendor/laravel/framework/src/Illuminate/Routing/Pipeline.php:53
#3 Illuminate\Routing\Pipeline:Illuminate\Routing\{closure} in /var/www/app/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php:104
#2 Illuminate\Pipeline\Pipeline:then in /var/www/app/vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php:151
#1 Illuminate\Foundation\Http\Kernel:sendRequestThroughRouter in /var/www/app/vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php:116
#0 Illuminate\Foundation\Http\Kernel:handle in /var/www/app/public/index.php:55

Enum to Option List

Hi Ben!

When I was using your package I was missing a to options list. Usually if you work with enums you will get to a point where you may need to create a select field. For now we need to create the HTML by ourselves but how about a method that returns the options as HTML tags.

I don't want to implement a select field since the configuration for can be too heavy (e.g. readonly, required attributes and so on). Instead I want to have a list with options. So why don't we implement a toOptions() method which will render the option list.

So how do I imagine how we should create a select field:

            <select name="countries" id="i-countries">
                <option value="">{{ __('** Please choose **') }}</option>
                {!! App\Enums\Countries::toOptions() !!}
            </select>

So App\Enums\Countries::toOptions([$key]) will generate something like this:

<option value="$key" selected="selected">$value</option>

May you wonder why we pass in an array? This attribute determines an array of selected options and it will expecting the keys. So if we find the key within our enum we will flag it as selected - an array is helpful if you would like to use multiselect fields.

Example

A possible implementation will be:

    /**
     * Return the enum as a HTML option list.
     * 
     * @param array $selected
     * An array that list the keys that will have the `selected` attribute.
     *  
     * @return string
     */
    public static function toOptions($selected = []): string
    {
        $html = '';
        $data = static::toArray();

        foreach($data as $key => $value) {
            $html .= '<option value="';
            $html .= $key;
            $html .= '"';
            if (array_key_exists($key, $selected)) {
                $html .= ' selected="selected"';
            }
            $html .= '>';
            $html .= $value;
            $html .= '</option>'
        }

        return $html;
    }

What do you think about this? One question I had is: Do we need an implentation to use the toSelectArray() instead of toArray()? I don't think so.

Tasks

  • Add BenSampo\Enum::toOptions() method.
  • Update README.md
  • Add tests BenSampo\Enum\Tests\HtmlRender (agree with the naming convention)?

Contribute

Branch: master
Version: 1.18.1 or 1.17.1 (depend on answer at #38).
Release Date: 24. Decembre 2018 (My xmas present for you ;)

Feedback: «your feedback is welcome here»

  • Please check if I can create a pull request for this.

Best regards

Alexander Bösch

Enum to array

Hi,

it would be nice if there would be on option for getting all the possible enum values as an array. Either by making the getConstants() function public, or by creating an accessor in the Enum class:

public static function toArray()
    {
        return self::getConstants();
    }

What do you think?

Bug: Validation on integer value

@BenSampo , in vendor/bensampo/laravel-enum/src/Enum.php on method hasValue, the pipe validation fails if values of my enum class is integer.

Example:

<?php

namespace App\Enums;

use BenSampo\Enum\Contracts\LocalizedEnum;
use BenSampo\Enum\Enum;

final class EGenero extends Enum implements LocalizedEnum
{
    public const BAR = 1;
    public const FOO = 2;
}

This is due to the data conversion you make to string. I want to leave the suggestion not to convert the data to string because the Laravel 5.8 validation understands that 1 is deferential from "1"

return in_array(>>>remove>>>(string)<<<remove<<< $value, array_map('strval', $validValues), true);

next major version ideas

hi there,

any plans for next major version? i would propose following:

  • use https://github.com/myclabs/php-enum - this is probably most popular enum implementation for PHP - quite heavily tested
  • integrate enum fields with Eloquent models (casting attributes to enum instances)
  • add ability to translate enum fields

what do you think?

hasKey() is case insensitive, but getValue() is case sensitive

const Watching  = 0;
UserLibraryStatus::hasKey('watching'); // true
UserLibraryStatus::hasKey('Watching'); // true

The above would make think that getValue would also accept both strings, but that's not true.

UserLibraryStatus::getValue('watching');

throws the following exception:

{
  "message": "Undefined index: watching",
  "exception": "ErrorException",
  "file": ".../project/vendor/bensampo/laravel-enum/src/Enum.php"
}

Is this intended? I would personally prefer it if the getValue function would also be case insensitive.

Change getFriendlyKeyName visibility from private to protected

Given these following constants

const SUPER_ADMIN = 'super_admin';
const SUPER_MODERATOR = 'super_moderator';
const MODERATOR = 'moderator';
const PREMIUM_USER = 'premium_user';

getDescription will return

S u p e r a d m i n
S u p e r m o d e r a t o r
Moderator
P r e m i u m u s e r

Since I was using upper snake case convention ctype_upper will return false. Override the getDescription method get the job done but I don't like this approach because there are so much if. Instead override getFriendlyKeyName would be better, I can format the final result to anything I want. E.g. use title case so Super admin would become Super Admin. But getFriendlyKeyName is private, so it is impossible to override it atm.

Country List

Hi folks!

First of all thank you @BenSampo for creating this package - it helps and works just fine.

If you are interested I have made a snippet for a country enumeration in english:
https://gist.github.com/sirthxalot/24507fb57964d1b7b660f08fdfebf9ce

Just thought may some other folks are interested in this.

Maybe a independent documentation where we can share snippets would be cool. Are you interested? I usually use VuePress in combination with GitHub pages. Just an idea.

best regards
Alexander Bösch

Add annotations to models

The enum casting on models is awesome, but it's a bit hard to remember that cast attributes are instances of the enum, rather than a string/int/etc.

Since there's already a command to annotate the enum, maybe we can add another to annotate the model like so?

/**
 * App\Models\User
 *
 * @property \App\Enums\UserTypeEnum|null $user_type
 * @property \App\Enums\RoleEnum|null $role
 */

Will PR w/ tests if you are keen :)
Thanks!

Validation message localization

I noticed that inside the EnumValue validation rule the message is hard coded so I was wondering how to translate that as you are not using trans?

Requires incorrect

\BenSampo\Enum\Enum::getLocalizedDescription(value): ?string
requires PHP 7.1 but you write require PHP 7.0, so I got the error message:

In Enum.php line 100:
Parse error: syntax error, unexpected '?'

illuminate/support required version sould be bumped

Hi,

first of all, thanks for creating this great package. It is very useful, so keep maintaining it! 🙂

In composer.json there are two requirements: php in version 7.0 or higher and illuminate\support in version 5.1 or higher. This is a bit confusing, because illuminate/support in 5.1 requires php in at least 5.5.9 version. Also if you try using this package with Laravel 5.4, which requires php in version 5.6.4, you cannot use validation rules - Illuminate\Contracts\Validation\Rule was introduces in Laravel 5.5.

To sum up: you can install this package on server with php in version 7.0 or higher and with Laravel in versions between 5.1 and 5.4, but in this configuration you cannot use validation rules.

What do you think about bumping version of illuminate/support to 5.5?

Broken in Lumen

When using validation, errors came.

Call to undefined function BenSampo\Enum\Rules\resolve()

Automatic Enum Annotation

Hey :)

Currently to annotate all your enums, you have to pass each class name individually after changing them.

I think it would be good to offer a command (or modify the existing command) to find all classes implementing the base class in a folder (by default app/Enums) and annotate them.

If you are happy with the idea I'll create a PR.

Validation is not working

I'm trying EVERYTHING to make the validation work but it doesn't.

final class PlanInterval extends Enum
{
    const Day = 0;
    const Month = 1;
    const Year = 2;
}

Form Request:

public function rules()
{
    return [
        'price' => ['required', 'numeric'],
        'period' => ['required', 'numeric', 'min:1'],
        'interval' => ['required', new EnumValue(PlanInterval::class)],
    ];
}
<div class="form-group row">
    <label for="interval" class="col-md-4 col-form-label text-md-right">{{ __('Interval') }}</label>

    <div class="col-md-6">
        <select class="custom-select" id="interval" name="interval">
            @foreach($intervals as $key => $value)
                <option value="{{ $value }}" @if($plan->interval->is($key)) selected @endif>{{ $value }}</option>
            @endforeach
        </select>
    </div>
</div>

PlanController:

/**
 * Show the form for editing the specified resource.
 *
 * @param  int  $id
 * @return Response
 */
public function edit($id)
{
    $plan = Plan::find($id);
    $intervals = PlanInterval::toSelectArray();

    return view('panel.plans.edit', compact('plan', 'intervals'));
}

It always say that it's the wrong value in the validation. What is happening? I'm using Laravel 5.8.

Issue storing integer

Hi!

I have my Order model like this:

protected $enumCasts = [ 'status' => OrderStatusTest::class, ];

I use toSelectArray() function in my controller to return array to my view

$statuses = OrderStatusTest::toSelectArray();

My select:

<select name="status" > @foreach ($statuses as $value => $status) <option value="{{ $value }}" >{{ $status }}</option> @endforeach </select>

Im trying to store like this

$order->status = $request->status;

But i get this error: Value 7 doesn't exist in [0, 1, 2, 3, 4, 5, 6, 7]

To solve I have to force cast to int like this:
$order->status = (int) $request->status;

What is the correct way to do it?

Thanks you bro!

Incorrect PHPDoc

    /**
     * Get the value for a single enum key
     *
     * @param string $key
     * @return void
     */
    public static function getValue(string $key)
    {
        return self::getConstants()[$key];
    }

This should most probably be "mixed", but definitely not void.

Missing Localization within toArray()

Hi Ben!

Its me again (@sirthxalot) - don't worry I don't want to blow up your issue tracker nor the source code but I have found two improvements, which I would like to discuss with you. I will open the requests separately in order to keep everything isolated.

Background

My first improvement will be the toArray() method. When using the method in combination with localized enums the translations are missing. This is because there is no getDescription() method within toArray() on the other hand you implemented the localization within toSelectArray() (https://github.com/BenSampo/laravel-enum/blob/master/src/Enum.php#L153). So why don't we extract that to the toArray() method so both arrays will be translated?

Questions

Due the code review I was wondering how you cache the array there is a $constantCacheArray property filled by the getConstants() method, but when we translate the toArray() array method these properties will not be updated. How should we handle this?

Another question I had:

Is there any reason to return the array without localization?

I think the answer is "no". So should we add a parameter to disable localization, e.g. toArray($localized = true).

And last but not least: If you are translating the values of the enum you will propeply expecting a sorted array. So in my opionion there should be another parameter to determine the sorting.

Example

Hope you will get the points. The final method propably will look like the following:

    /**
     * Return the enum as an array.
     * 
     * @param boolean $localized
     * A boolean that determine whether if the values should be translated (`true`) 
     * or not (`false`). Default is: `true`.
     *
     * @param boolean $sorting
     * A boolean that determine whether if the sorting is enabled (`true`) 
     * or not (`false`). Default is: `true`.
     *  
     * @return array
     */
    public static function toArray($localized = true, $sorting = true): array
    {
        $constants = static::getConstants();
        $array = [];

        foreach ($constants as $key => $value) {
            if (true === $localized) {
                $array[$key] = static::getDescription($value);
            } else {
                $array[$key] = $value;
            }
        }

        if (true === $sorting) {
            asort($array);
        }

        return $array;
    }

Tasks

  • Update BenSampo\Enum::toArray() method.
  • Update README.md
  • Add tests BenSampo\Enum\Tests\EnumLocalizationTest (may other test will be affected by this)?

Contribute

Branch: master
Version: 1.17.1
Release Date: 24. Decembre 2018 (My xmas present for you ;)

Feedback: «your feedback is welcome here»

  • Please check if I can create a pull request for this.

Best regards

Alexander Bösch

Library is not extendable

Hi There.

Thank you for this library!

I wanted to extend your Enum Base class, but a lot of methods are private. Could you convert those to protected?

Also, you probably want to replace those 'self' references to 'static' then, for the LSB.

Thanks in advance!

Best regards,

Ciaro

Checking if instance has value in array

I'm really been enjoying working with this package, particularly the model integration.

I often do something similar to this:

$booking->status->is(Status::DRAFT) || $booking->status->is(Status::PENDING) || $booking->status->is(Status::REVIEW) 

It gets a little verbose, particularly when checking many values.

I was wondering what your thoughts would be on adding an in function to the instance, for example:

$booking->status->in([Status::DRAFT, Status::PENDING, Status::REVIEW])

It could also support the passing the choices as function arguments:

$booking->status->in(Status::DRAFT, Status::PENDING)

Let me know 😄

ERROR: Method Illuminate\Validation\Validator::validateEnumValue does not exist

I'm getting the following error on production environment only when using the pipe validators.
Any ideas why? dev env works fine.

Laravel 5.7
Php 7.3.1
Laravel-enum 1.16

FormRequest::

<?php

namespace App\Enums;

use BenSampo\Enum\Contracts\LocalizedEnum;
use BenSampo\Enum\Enum;

final class Gender extends Enum implements LocalizedEnum
{
    const MALE = 'male';
    const FEMALE = 'female';
    const UNKNOWN = 'unknown';
}

Validator:

'gender' => 'required|enum_value:' . Gender::class,

Stacktrace:

[2019-01-28 10:58:16] production.ERROR: Method Illuminate\Validation\Validator::validateEnumValue does not exist. {"userId":2,"email":"xxxxx@xxxx","exception":"[object] (BadMethodCallException(code: 0): Method Illuminate\\Validation\\Validator::validateEnumValue does not exist. at /var/www/myLaravelApp/vendor/laravel/framework/src/Illuminate/Validation/Validator.php:1187)
[stacktrace]
#0 /var/www/myLaravelApp/vendor/laravel/framework/src/Illuminate/Validation/Validator.php(398): Illuminate\\Validation\\Validator->__call('validateEnumVal...', Array)
#1 /var/www/myLaravelApp/vendor/laravel/framework/src/Illuminate/Validation/Validator.php(277): Illuminate\\Validation\\Validator->validateAttribute('gender', 'EnumValue')
#2 /var/www/myLaravelApp/vendor/laravel/framework/src/Illuminate/Validation/Validator.php(302): Illuminate\\Validation\\Validator->passes()
#3 /var/www/myLaravelApp/vendor/laravel/framework/src/Illuminate/Validation/ValidatesWhenResolvedTrait.php(25): Illuminate\\Validation\\Validator->fails()
#4 /var/www/myLaravelApp/vendor/laravel/framework/src/Illuminate/Foundation/Providers/FormRequestServiceProvider.php(30): Illuminate\\Foundation\\Http\\FormRequest->validateResolved()
#5 /var/www/myLaravelApp/vendor/laravel/framework/src/Illuminate/Container/Container.php(1069): Illuminate\\Foundation\\Providers\\FormRequestServiceProvider->Illuminate\\Foundation\\Providers\\{closure}(Object(App\\Http\\Requests\\RegistrationFormRequest), Object(Illuminate\\Foundation\\Application))
#6 /var/www/myLaravelApp/vendor/laravel/framework/src/Illuminate/Container/Container.php(1033): Illuminate\\Container\\Container->fireCallbackArray(Object(App\\Http\\Requests\\RegistrationFormRequest), Array)
#7 /var/www/myLaravelApp/vendor/laravel/framework/src/Illuminate/Container/Container.php(1018): Illuminate\\Container\\Container->fireAfterResolvingCallbacks('App\\\\Http\\\\Reques...', Object(App\\Http\\Requests\\RegistrationFormRequest))
#8 /var/www/myLaravelApp/vendor/laravel/framework/src/Illuminate/Container/Container.php(677): Illuminate\\Container\\Container->fireResolvingCallbacks('App\\\\Http\\\\Reques...', Object(App\\Http\\Requests\\RegistrationFormRequest))
#9 /var/www/myLaravelApp/vendor/laravel/framework/src/Illuminate/Container/Container.php(609): Illuminate\\Container\\Container->resolve('App\\\\Http\\\\Reques...', Array)
#10 /var/www/myLaravelApp/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(735): Illuminate\\Container\\Container->make('App\\\\Http\\\\Reques...', Array)
#11 /var/www/myLaravelApp/vendor/laravel/framework/src/Illuminate/Routing/RouteDependencyResolverTrait.php(79): Illuminate\\Foundation\\Application->make('App\\\\Http\\\\Reques...')
#12 /var/www/myLaravelApp/vendor/laravel/framework/src/Illuminate/Routing/RouteDependencyResolverTrait.php(46): Illuminate\\Routing\\ControllerDispatcher->transformDependency(Object(ReflectionParameter), Array)
#13 /var/www/myLaravelApp/vendor/laravel/framework/src/Illuminate/Routing/RouteDependencyResolverTrait.php(27): Illuminate\\Routing\\ControllerDispatcher->resolveMethodDependencies(Array, Object(ReflectionMethod))
#14 /var/www/myLaravelApp/vendor/laravel/framework/src/Illuminate/Routing/ControllerDispatcher.php(41): Illuminate\\Routing\\ControllerDispatcher->resolveClassMethodDependencies(Array, Object(App\\Http\\Controllers\\Platform\\Admin\\RegistrationController), 'update')
#15 /var/www/myLaravelApp/vendor/laravel/framework/src/Illuminate/Routing/Route.php(219): Illuminate\\Routing\\ControllerDispatcher->dispatch(Object(Illuminate\\Routing\\Route), Object(App\\Http\\Controllers\\Platform\\Admin\\RegistrationController), 'update')
#16 /var/www/myLaravelApp/vendor/laravel/framework/src/Illuminate/Routing/Route.php(176): Illuminate\\Routing\\Route->runController()
#17 /var/www/myLaravelApp/vendor/laravel/framework/src/Illuminate/Routing/Router.php(682): Illuminate\\Routing\\Route->run()
#18 /var/www/myLaravelApp/vendor/laravel/framework/src/Illuminate/Routing/Pipeline.php(30): Illuminate\\Routing\\Router->Illuminate\\Routing\\{closure}(Object(Illuminate\\Http\\Request))
#19 /var/www/myLaravelApp/vendor/santigarcor/laratrust/src/Laratrust/Middleware/LaratrustRole.php(57): Illuminate\\Routing\\Pipeline->Illuminate\\Routing\\{closure}(Object(Illuminate\\Http\\Request))
#20 /var/www/myLaravelApp/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(151): Laratrust\\Middleware\\LaratrustRole->handle(Object(Illuminate\\Http\\Request), Object(Closure), Array, 'myteam')
#21 /var/www/myLaravelApp/vendor/laravel/framework/src/Illuminate/Routing/Pipeline.php(53): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))
#22 /var/www/myLaravelApp/app/Http/Middleware/Authenticate.php(52): Illuminate\\Routing\\Pipeline->Illuminate\\Routing\\{closure}(Object(Illuminate\\Http\\Request))
#23 /var/www/myLaravelApp/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(151): App\\Http\\Middleware\\Authenticate->handle(Object(Illuminate\\Http\\Request), Object(Closure))
#24 /var/www/myLaravelApp/vendor/laravel/framework/src/Illuminate/Routing/Pipeline.php(53): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))
#25 /var/www/myLaravelApp/app/Http/Middleware/IdentifyTenant.php(35): Illuminate\\Routing\\Pipeline->Illuminate\\Routing\\{closure}(Object(Illuminate\\Http\\Request))
#26 /var/www/myLaravelApp/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(151): App\\Http\\Middleware\\IdentifyTenant->handle(Object(Illuminate\\Http\\Request), Object(Closure))
#27 /var/www/myLaravelApp/vendor/laravel/framework/src/Illuminate/Routing/Pipeline.php(53): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))
#28 /var/www/myLaravelApp/vendor/laravel/framework/src/Illuminate/Routing/Middleware/SubstituteBindings.php(41): Illuminate\\Routing\\Pipeline->Illuminate\\Routing\\{closure}(Object(Illuminate\\Http\\Request))
#29 /var/www/myLaravelApp/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(151): Illuminate\\Routing\\Middleware\\SubstituteBindings->handle(Object(Illuminate\\Http\\Request), Object(Closure))
#30 /var/www/myLaravelApp/vendor/laravel/framework/src/Illuminate/Routing/Pipeline.php(53): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))
#31 /var/www/myLaravelApp/vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/VerifyCsrfToken.php(75): Illuminate\\Routing\\Pipeline->Illuminate\\Routing\\{closure}(Object(Illuminate\\Http\\Request))
#32 /var/www/myLaravelApp/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(151): Illuminate\\Foundation\\Http\\Middleware\\VerifyCsrfToken->handle(Object(Illuminate\\Http\\Request), Object(Closure))
#33 /var/www/myLaravelApp/vendor/laravel/framework/src/Illuminate/Routing/Pipeline.php(53): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))
#34 /var/www/myLaravelApp/vendor/laravel/framework/src/Illuminate/View/Middleware/ShareErrorsFromSession.php(49): Illuminate\\Routing\\Pipeline->Illuminate\\Routing\\{closure}(Object(Illuminate\\Http\\Request))
#35 /var/www/myLaravelApp/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(151): Illuminate\\View\\Middleware\\ShareErrorsFromSession->handle(Object(Illuminate\\Http\\Request), Object(Closure))
#36 /var/www/myLaravelApp/vendor/laravel/framework/src/Illuminate/Routing/Pipeline.php(53): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))
#37 /var/www/myLaravelApp/vendor/laravel/framework/src/Illuminate/Session/Middleware/StartSession.php(63): Illuminate\\Routing\\Pipeline->Illuminate\\Routing\\{closure}(Object(Illuminate\\Http\\Request))
#38 /var/www/myLaravelApp/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(151): Illuminate\\Session\\Middleware\\StartSession->handle(Object(Illuminate\\Http\\Request), Object(Closure))
#39 /var/www/myLaravelApp/vendor/laravel/framework/src/Illuminate/Routing/Pipeline.php(53): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))
#40 /var/www/myLaravelApp/vendor/laravel/framework/src/Illuminate/Cookie/Middleware/AddQueuedCookiesToResponse.php(37): Illuminate\\Routing\\Pipeline->Illuminate\\Routing\\{closure}(Object(Illuminate\\Http\\Request))
#41 /var/www/myLaravelApp/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(151): Illuminate\\Cookie\\Middleware\\AddQueuedCookiesToResponse->handle(Object(Illuminate\\Http\\Request), Object(Closure))
#42 /var/www/myLaravelApp/vendor/laravel/framework/src/Illuminate/Routing/Pipeline.php(53): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))
#43 /var/www/myLaravelApp/vendor/laravel/framework/src/Illuminate/Cookie/Middleware/EncryptCookies.php(66): Illuminate\\Routing\\Pipeline->Illuminate\\Routing\\{closure}(Object(Illuminate\\Http\\Request))
#44 /var/www/myLaravelApp/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(151): Illuminate\\Cookie\\Middleware\\EncryptCookies->handle(Object(Illuminate\\Http\\Request), Object(Closure))
#45 /var/www/myLaravelApp/vendor/laravel/framework/src/Illuminate/Routing/Pipeline.php(53): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))
#46 /var/www/myLaravelApp/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(104): Illuminate\\Routing\\Pipeline->Illuminate\\Routing\\{closure}(Object(Illuminate\\Http\\Request))
#47 /var/www/myLaravelApp/vendor/laravel/framework/src/Illuminate/Routing/Router.php(684): Illuminate\\Pipeline\\Pipeline->then(Object(Closure))
#48 /var/www/myLaravelApp/vendor/laravel/framework/src/Illuminate/Routing/Router.php(659): Illuminate\\Routing\\Router->runRouteWithinStack(Object(Illuminate\\Routing\\Route), Object(Illuminate\\Http\\Request))
#49 /var/www/myLaravelApp/vendor/laravel/framework/src/Illuminate/Routing/Router.php(625): Illuminate\\Routing\\Router->runRoute(Object(Illuminate\\Http\\Request), Object(Illuminate\\Routing\\Route))
#50 /var/www/myLaravelApp/vendor/laravel/framework/src/Illuminate/Routing/Router.php(614): Illuminate\\Routing\\Router->dispatchToRoute(Object(Illuminate\\Http\\Request))
#51 /var/www/myLaravelApp/vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php(176): Illuminate\\Routing\\Router->dispatch(Object(Illuminate\\Http\\Request))
#52 /var/www/myLaravelApp/vendor/laravel/framework/src/Illuminate/Routing/Pipeline.php(30): Illuminate\\Foundation\\Http\\Kernel->Illuminate\\Foundation\\Http\\{closure}(Object(Illuminate\\Http\\Request))
#53 /var/www/myLaravelApp/vendor/barryvdh/laravel-debugbar/src/Middleware/InjectDebugbar.php(58): Illuminate\\Routing\\Pipeline->Illuminate\\Routing\\{closure}(Object(Illuminate\\Http\\Request))
#54 /var/www/myLaravelApp/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(151): Barryvdh\\Debugbar\\Middleware\\InjectDebugbar->handle(Object(Illuminate\\Http\\Request), Object(Closure))
#55 /var/www/myLaravelApp/vendor/laravel/framework/src/Illuminate/Routing/Pipeline.php(53): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))
#56 /var/www/myLaravelApp/vendor/fideloper/proxy/src/TrustProxies.php(57): Illuminate\\Routing\\Pipeline->Illuminate\\Routing\\{closure}(Object(Illuminate\\Http\\Request))
#57 /var/www/myLaravelApp/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(151): Fideloper\\Proxy\\TrustProxies->handle(Object(Illuminate\\Http\\Request), Object(Closure))
#58 /var/www/myLaravelApp/vendor/laravel/framework/src/Illuminate/Routing/Pipeline.php(53): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))
#59 /var/www/myLaravelApp/vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/TransformsRequest.php(31): Illuminate\\Routing\\Pipeline->Illuminate\\Routing\\{closure}(Object(Illuminate\\Http\\Request))
#60 /var/www/myLaravelApp/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(151): Illuminate\\Foundation\\Http\\Middleware\\TransformsRequest->handle(Object(Illuminate\\Http\\Request), Object(Closure))
#61 /var/www/myLaravelApp/vendor/laravel/framework/src/Illuminate/Routing/Pipeline.php(53): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))
#62 /var/www/myLaravelApp/vendor/chaseconey/laravel-datadog-helper/src/Middleware/LaravelDatadogMiddleware.php(22): Illuminate\\Routing\\Pipeline->Illuminate\\Routing\\{closure}(Object(Illuminate\\Http\\Request))
#63 /var/www/myLaravelApp/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(151): ChaseConey\\LaravelDatadogHelper\\Middleware\\LaravelDatadogMiddleware->handle(Object(Illuminate\\Http\\Request), Object(Closure))
#64 /var/www/myLaravelApp/vendor/laravel/framework/src/Illuminate/Routing/Pipeline.php(53): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))
#65 /var/www/myLaravelApp/vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/CheckForMaintenanceMode.php(62): Illuminate\\Routing\\Pipeline->Illuminate\\Routing\\{closure}(Object(Illuminate\\Http\\Request))
#66 /var/www/myLaravelApp/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(151): Illuminate\\Foundation\\Http\\Middleware\\CheckForMaintenanceMode->handle(Object(Illuminate\\Http\\Request), Object(Closure))
#67 /var/www/myLaravelApp/vendor/laravel/framework/src/Illuminate/Routing/Pipeline.php(53): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))
#68 /var/www/myLaravelApp/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(104): Illuminate\\Routing\\Pipeline->Illuminate\\Routing\\{closure}(Object(Illuminate\\Http\\Request))
#69 /var/www/myLaravelApp/vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php(151): Illuminate\\Pipeline\\Pipeline->then(Object(Closure))
#70 /var/www/myLaravelApp/vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php(116): Illuminate\\Foundation\\Http\\Kernel->sendRequestThroughRouter(Object(Illuminate\\Http\\Request))
#71 /var/www/myLaravelApp/public/index.php(55): Illuminate\\Foundation\\Http\\Kernel->handle(Object(Illuminate\\Http\\Request))
#72 {main}
"}

Need a toArray() fn that returns enum descriptions

@BenSampo thanks a ton for this module and your blog post, using enums has greatly simplified my code.

I'm using enums to populate html select fields and toArray() almost satisfies my requirement. However, populating select field values with enum descriptions is more readable than using enum keys.

eg. Instead of SADMIN, AUTHOR, the select field would show 'Super Administrator', 'Blog Author'.

I'm now repeating the same toArrayDescription() function in all of my Enum classes as shown below. Can we have a toArrayDescription() added to laravel-enum to address this use case?

final class UserType extends Enum
{
    const SADMIN = 0;
    const AUTHOR = 1;


    /**
     * Get the description for an enum value
     *
     * @param $value
     * @return string
     */
    public static function getDescription($value): string
    {
        switch ($value) {
            case self::SADMIN:
                return 'Super admin';
            case self::AUTHOR:
                return 'Blog author';
        }
        return self::getKey($value);
    }

// returns ['Super Admin' => 0, 'Blog Author', => 1]
    public static function toArrayDescription()
    {
        $arr = [];

        foreach (self::getValues() as $v) {
            $arr[self::getDescription($v)] = $v;
        }
        return $arr;
    }
}

Casting Enum to string

I've switched from the myclabs/php-enum package, and one of the things i've missed in the ability to cast an instance to string to get the value.

I was wondering if you would consider adding it to this library, so when you cast a Enum instance to a string you get the value (as a string).

For example:

final class MyEnum extends Enum
{
    const TEST = 'test';
    const TEST_INT = 1;
}

(string) MyEnum::TEST(); // = 'test' 
(string) MyEnum::TEST_INT(); // = '1'

This is useful in views as well, as you can do {{ $model->enum_casted_attr }}.

Happy to create a PR + tests/etc as well 😄

See:
https://github.com/myclabs/php-enum#documentation

Have to cast to int for getDescription to work

Display of description in blade fails unless cast to int
works - {{ \App\Enums\ProductStatus::getDescription((int)$product->status) }}
displays nothing - {{ \App\Enums\ProductStatus::getDescription($product->status) }}

Assume getDescription is taking it as string unless cast to int.

Unresolvable dependency resolving [Parameter #0 [ <required> $enumValue ]] in class BenSampo\Enum\Enum

Hello Ben!

I am updating my projects to use PHP 7.3 but I found a problem that seems to be in your package.
I'm using Laravel 5.6, and your package is at 1.17.1 version.
When I tried to use Blade Inject of classes it raises a exception:

The Code:
@inject('cstIcmsEnum', 'App\Enums\CstIcmsEnum')

The Exception:
Unresolvable dependency resolving [Parameter #0 [ $enumValue ]] in class BenSampo\Enum\Enum (View: C:\xampp\htdocs\hubdocs\resources\views\documentos\cteos.blade.php) {"userId":2,"exception":"[object] (ErrorException(code: 0): Unresolvable dependency resolving [Parameter #0 [ $enumValue ]] in class BenSampo\Enum\Enum (View: C:\xampp\htdocs\hubdocs
esources\views\documentos\cteos.blade.php) at C:\xampp\htdocs\hubdocs\vendor\laravel\framework\src\Illuminate\Container\Container.php:948, Illuminate\Contracts\Container\BindingResolutionException(code: 0): Unresolvable dependency resolving [Parameter #0 [ $enumValue ]] in class BenSampo\Enum\Enum at C:\xampp\htdocs\hubdocs\vendor\laravel\framework\src\Illuminate\Container\Container.php:948)

If I comment the Enum Default Contructor it works fine.

public function __construct($enumValue)
    {
        if (!static::hasValue($enumValue)) {
            throw new InvalidEnumMemberException($enumValue, $this);
        }

        $this->value = $enumValue;
        $this->key = static::getKey($enumValue);
        $this->description = static::getDescription($enumValue);
    }

I search in the releases versions and found that this contructor and didn't find why this was added.

Any advice for this issue?
Thanks!

Documentation error

the docs for "getValue" have sample code that is "getKey"

getValue(string $key): int
Returns the value for the given enum key.

UserType::getKey('Moderator'); // Returns 1

Can not store the key on db:seed

I'm using the attribute casting on my model.
On my UserTableSeed i tried to store the key of Countries Enum instead of the value like this:

country => Countries::getInstance(Countries::MA)->key;

But it throws an exception BenSampo\Enum\Exceptions\InvalidEnumMemberException : Value MA doesn't exist in

But if i store the value of Enum it works.

Any suggestions to correct this.

By the way thanks for your work.

Store more than numbers

Hi I'm checking this package to pair it with my model's enums in Laravel and it looks great. But I was wondering if there was a specific reason to limit the values to numbers. Why not just leave them as strings and allow both?. While normally you would use the pretty Enum::Key in your code and store numeric value in the database what if that which is stored comes from a legacy system and requires a specific alpha-numeric ugly value?.

For example:

final class LegacyCar extends Enum
{
    const Sedan = 'SE-020';
    const Crossover = 'CR-250';
    const SUV = 'SUV001';
}

Would it make sense to remove the numeric constrains?

Installing `bensampo/laravel-enum` into Laravel 6 removes `laravel/ui`

Not 100% sure if this belongs here, but reporting it here as it was installing this package that caused the issue.

Re-installing laravel/ui afterwards doesn't remove anything.

$ composer require bensampo/laravel-enum
Using version ^1.26 for bensampo/laravel-enum
./composer.json has been updated
Loading composer repositories with package information
Updating dependencies (including require-dev)
Package operations: 4 installs, 0 updates, 1 removal
  - Removing laravel/ui (v1.0.0)
  - Installing zendframework/zend-eventmanager (3.2.1): Downloading (100%)         
  - Installing zendframework/zend-code (3.3.2): Loading from cache
  - Installing hanneskod/classtools (1.2.0): Downloading (100%)         
  - Installing bensampo/laravel-enum (v1.26): Loading from cache
...snip...
Package manifest generated successfully.

is there any way to use with Laravel 5.3?

I have a huge project in L5.3, i expect to migrate in the next months but i want to know if i can use your package here.

What kind of dependencies are required from L5.4 not present in L5.3?

Thanks in advance.

Error: Undefined offset: 1

I have an Enum class with the following constants:

use BenSampo\Enum\Enum;

final class FretesComplementoFiltersEnum extends Enum
{
    const TRUE = 1;
    const FALSE = 2;

    /**
     * Get the description for an enum value
     *
     * @param  int  $value
     * @return string
     */
    public static function getDescription(int $value): string
    {
        switch ($value) {
            case self::TRUE:
                return 'Com Complemento';
            break;
            case self::FALSE:
                return 'Sem Complemento';
            break;
            default:
                return self::getKey($value);
        }
    }
}

And when I run FretesComplementoFiltersEnum::getValue(true), it returns Undefined offset: 1. And same FretesComplementoFiltersEnum::getDescription(1)

Enum Instance Support

A pull request (#45) was created by me to support enum instance instead of using the literal support which is error-prone, having the feature reduces bypassing of an enum constant value. One can easily typehint the enum on methods, constructors and functions.

E.g.

$userType = UserType::getInstance(UserType::Administrator);

// This way one is rest assured that the
// user's type is from the UserType enum.
createUser(array $data, UserType $userType)
{
    if ($userType->equals(UserType::Administrator)) {
        // ...;
    } else {
        // ...;
    }
}

Enum instance descriptions not switching locale

When switching locales on the fly, already created enum instances seems to ignore the locale change.

Here's an example of what i mean:

// the app locale is currently 'en'
$na = \App\Enums\Continent::NorthAmerica();
echo $na->description; // echoes "North America"

App::setLocale('fr');
echo $na->description; // still echoes "North America" - unexpected

$na = \App\Enums\Continent::NorthAmerica() // re-instantiating
echo $na->description; // echoes "Amérique du Nord" as i expected

Cannot use @INJECT in blades to access ENUMs

Hey Ben,
I've been using your package in a recent project and noticed when deploying to PROD, that using "composer install --no-dev" causes an error with you package. I wondering if that's due to the positioning of "laravel/framework": "5.8.*" under "require-dev"? I've removed the --no-dev in my docker build script, but it'd be nice to remove dev components for PROD environments.

Suggestions For Improvements (Discussion)

I just heard about this package (via The Laravel Podcast) and I think it is awesome what you have done! I do have some suggestions / feedback though that I wanted to share.

I don't have time to put in a PR, so I thought I would just share my thoughts.

  • I would love to see this more integrated with models, so you can utilize Laravel's mutators to save the values and get the descriptions with out having to use a separate class and static method.
  • I also think it would be beneficial to define your enum values directly on the model instead of in a separate class. Maybe as an array:
protected $enums = [
    'type' => [
        0 => 'Administrator',
        1 => 'PaidMember',
        2 => 'Member'
    ],
    'status' => [
        0 => 'Approved',
        1 => 'Not Approved'
    ]
];
  • You could also then use the model class as the main class you call so it could read more like this:
$this->validate($request, [
    'type' => ['required', Rule::in(User::EnumOptions('type'))],
]);

Just my 2 cents. Keep up the awesome work!

Simplify localisation

Rather than suggesting implementing the method for localising getDescription (outlined in the readme) it would be better to include it on the base enum class. Then there should be a way to toggle between using strings from keys or the default getDescription method.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.