How To Work With Enumerations in Laravel Framework 9

Laravel 9 was released on February 8th, 2022 and it came with some nice new features that we want to highlight.

In this article, we’ll discuss how to work with enumerations in Laravel Framework 9+

Enums were our favorite new feature added in PHP 8.1 so we’re so glad to see them being included already in Laravel.

That being said you must be using PHP 8.1 for the new Enum features to work.

Enum Eloquent Attribute Casting

A new feature was added to Eloquent’s attribute casting to support casting values from a database value to an enum.

For this example we’ll create an article model with four potential published states. We’ll be using an enum to store the values.

Out of the box, Laravel doesn’t have an “Enums” folder but it seems to make sense to create one inside of our “app” directory. Then we’re not mixing models that interface with the database with enums that don’t.

namespace App\Enums;

enum PublishedState: string {
    case NotPublished = '1';
    case Scheduled = '2';
    case Published = '3';
    case Deleted = '4';
}

Now let’s create our model.

$ php artisan make:model -m Article
Model created successfully.
Created Migration: 2022_02_19_180106_create_articles_table

Inside our migration we’ll create a column named “state_id” with a default value of PublishedState::NotPublished.

public function up()
{
    Schema::create('articles', function (Blueprint $table) {
        $table->id();
        $table->timestamps();
        $table->string('title');
        $table->text('article_body');
        $table->integer('state_id')->nullable(false);
    });
}

Now inside our model we’ll specify that we can fill our state_id and in our casts attribute we’ll define how the state_id should be the PublishedState enum (it says class but it’s not).

<?php

namespace App\Models;

use App\Enums\PublishedState;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;

class Article extends Model
{
    use HasFactory;

    protected $fillable = [
        'state_id',
        'title',
        'article_body'
    ];

    protected $casts = [
        'state_id' => PublishedState::class,
    ];
}

Now when we create a new Article we can specify

$article = \App\Models\Article::create([
    'title' => 'Enums in Laravel 9!',
    'article_body' => 'Something',
    'state_id' => \App\Enums\PublishedState::NotPublished,
]);

When we var_dump the value of state_id out we can see that it’s the enum and not the value of the enum.

var_dump($article->state_id);
enum(App\Enums\PublishedState::NotPublished)

Now the great part about enums is that we’re not supposed to be able to set one to an invalid value. Look what happens when we try.

$article->state_id = 12;
12 is not a valid backing value for enum "App\Enums\PublishedState"

So glad these have been added.

Implicit Route Bindings With Enums

The next piece of enum logic we want to use is the fact that we can now use Enums in our routing table to only allow specific values.

Let’s look at an example where we want to filter our list of articles based on their current state. We can define a route like so.

Route::get('/articles/{state}', function (int $state) {
    return $state;
});

Again the downside to this is that we can pass any value we want into the route and have it work. For example, we can visit “/articles/77” and it will route. We’ll filter out our results but they’ll be empty because it’s an invalid state_id.

If we change the route definition to look for our enum it will look like the following.

Route::get('/articles/{state}', function (\App\Enums\PublishedState $state) {
    return $state->value;
});

And our “/articles/1” will still work but when we attempt to access “/articles/77” we’ll get a 404 error. We’re still struggling with if this is how we want our application to behave but it’s a good start.

What You Need to Know

  • Laravel 9 added support for enums
  • Must be using PHP 8.1 or higher
  • Can cast to an enum
  • Can use for routes