Eager loading relationship from an Enum casted column returns error

115 views Asked by At

I created RoleEnum and cast it in User model. The role_id which is being cast to RoleEnum also has relationship to Role model.

<?php

namespace App\Enums;

enum RoleEnum:int
{
    case SYSTEM_ADMINISTRATOR = 1;
    case ADMINISTRATOR = 2;
    case SAMPLE_ROLE_ONE = 3;
    case SAMPLE_ROLE_TWO = 4;
    case SAMPLE_ROLE_THREE = 5;
    case SAMPLE_ROLE_FOUR = 6;
}

User Model

protected $casts = [
    'email_verified_at' => 'datetime',
    'password' => 'hashed',
    'role_id' => RoleEnum::class,
];

public function role(): BelongsTo
{
    return $this->belongsTo(Role::class);
}

And in my controller index

$users = User::with('role')
    ->paginate()
    ->withQueryString();

And I'm getting this error and it is pointing in paginate(). It must be using the class instead of the value.

Object of class App\Enums\RoleEnum could not be converted to string

Edit: After further testing, I found out that the error is caused by eager loading the role which is an Enum casted column and not by paginate(). I can simply remove the Enum casting and everything will work fine. But is there a way to cast an Enum and still use eager loading?

1

There are 1 answers

3
mrvivaldio On

I suggest you create a Role table with the fields id, name, slug, level The migration should look like this

public function up(): void
{
    Schema::create('roles', function (Blueprint $table) {
        $table->id();
        $table->string('slug')->unique();
        $table->string('name');
        $table->unsignedTinyInteger('level');
        $table->timestamps();
        $table->softDeletes();
    });
}

and the users table

public function up(): void
{
    Schema::create('users', function (Blueprint $table) {
        $table->bigIncrements('id');
        $table->unsignedTinyInteger('role_id')->index();
        $table->string('username')->unique();
        $table->string('email')->unique();
        $table->timestamp('email_verified_at')->nullable();
        $table->string('password');
        $table->rememberToken();
        $table->timestamps();
        $table->softDeletes();
    });
}

you are free to personalize everything

Then, the relationships on the models must be managed depending on what you want, in these examples a user only has one role and I put the level field in order to be able to prioritize your roles later.

In the Role model, place these lines

public function users(){
     return $this->hasMany(User::class);
}

In the User model, place these lines

public function role(){
     return $this->belongsTo(Role::class);
}

Then you can do

$users = User::with('role')
     ->paginate(10)
     ->withQueryString();