Home Supercharged Backed Enums with Collection

Enter a search term to find articles.
supercharged-backed-enums-with-collection
2022-04-18
343

Supercharged Backed Enums with Collection

If you've been using PHP 8.1, chances are you already know about this new feature called Enumerations or "Enums". If not, then I suggest that you check it out as it is, in my opinion, one of the most powerful new feature PHP has added to the language. It might solve a lot of your use-cases as it did for me.

As an example, let's say that we have a backed enum class that holds the cases for the status of the ticket in our app:

enum TicketStatus : string
{
    case Draft = 'draft';
    case Open = 'open';
    case Ongoing = 'ongoing';
    case Closed = 'closed';
}

One cool thing about enumerations is that you can call a cases() method on it to list all the cases like so:

$result = TicketStatus::cases();

dd($result);

[
     TicketStatus {
       +name: "Draft",
       +value: "draft",
     },
     TicketStatus {
       +name: "Open",
       +value: "open",
     },
     TicketStatus {
       +name: "Ongoing",
       +value: "ongoing",
     },
     TicketStatus {
       +name: "Closed",
       +value: "closed",
     },
]

As you can see, each element in the result is an instance of TicketStatus class with properties name and value. So it begs the question, what if I just want to get just the names or just the values? Unfortunately, this isn't something that comes out of the box and calling TicketStatus::names() or TicketStatus::values() would cause an error.

One solution is to use Illuminate\Support\Collection class.

$names = collect(TicketStatus::cases())->pluck('name');

dd($names);

Illuminate\Support\Collection {
     all: [
       "Draft",
       "Open",
       "Ongoing",
       "Closed",
     ],
}

$values = collect(TicketStatus::cases())->pluck('values');

dd($values);

Illuminate\Support\Collection {
     all: [
       "draft",
       "open",
       "ongoing",
       "closed",
     ],
}

Okay, now we're talking! Let's refactor that as methods in our enum class, like so:

enum TicketStatus : string
{
    case Draft = 'draft';
    case Open = 'open';
    case Ongoing = 'ongoing';
    case Closed = 'closed';

    public static function names()
    {
        return collect(self::cases())->pluck('name');
    }

    public static function values()
    {
        return collect(self::cases())->pluck('value');
    }
}

Now, calling TicketStatus::names() or TicketStatus::values() would definitely work!

But wait, there's more! Since we are already using Collection class here, we might as well see to it that we are able to take advantage of the full features it can offer. How about refactoring to have something like TicketStatus::collection() ? Let's do it!

enum TicketStatus : string
{
    case Draft = 'draft';
    case Open = 'open';
    case Ongoing = 'ongoing';
    case Closed = 'closed';

    public static function names()
    {
        return self::collection()->pluck('name');
    }

    public static function values()
    {
        return self::collection()->pluck('value');
    }

    public static function collection()
    {
        return collect(self::cases());
    }
}

Cool! Now we can take full advantage of collection features within our enum. In the future we can do something like TicketStatus::collection()->map(...) or TicketStatus::collection()->each(...) should we need to. It is now up to you if you want to add more convenience methods or just chain from the collection() method.

Last thing that we would want to do is to be able to share these convenient functions with other enum classes. So let's wrap it within a trait...

trait Collectible
{
    public static function names()
    {
        return self::collection()->pluck('name');
    }

    public static function values()
    {
        return self::collection()->pluck('value');
    }

    public static function collection()
    {
        return collect(self::cases());
    }
}

And just use the trait within your enum classes like so

enum TicketStatus : string
{
    use Collectible;

    case Draft = 'draft';
    case Open = 'open';
    case Ongoing = 'ongoing';
    case Closed = 'closed';
}

And there you have it! You have supercharged your backed enum classes using collection. Hope you enjoy!

Marvin Quezon

Full Stack Web Developer
Marvin Quezon · Copyright © 2024 · Privacy · Sitemap