Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

kevinwakhisi's avatar

Accessors in a relationship

How can i get the attribue from a related model Quried a user as

 public function render()
    {
        return view('livewire.admin.users', [
            'users' => \App\Models\User::with('roles')
                ->paginate($this->perPage)
        ]);
    }

The type of accessor i have in my role model

public function getRoleColorAttribute()
    {
        # code...
        return [
            'super-admin' => 'primary',
            'vicar' => 'danger',
            'council' => 'info',
            'user' => 'default',
        ][$this->name] ?? 'warning';
    }

now on my user table getting the role_color appears to be blank. But works when i only query the role in its separate table

<tbody class="text-gray-600 fw-bold">
@foreach ($users as $user)
	<tr>
      <td>
	     @foreach ($user->roles as $role)
		     <a href="#" class="badge badge-light-{{ $role->role_color }}">
			    {{ $role->name }}
              </a>
         @endforeach
		</td>
	</tr>
	@endforeach
</tbody>
0 likes
28 replies
Tray2's avatar

This works for me

public function getRoleColorAttribute()
    {
        return match($this->role) {
            'super-admin' => 'primary',
            'admin' => 'secondary'

    }
kevinwakhisi's avatar

version 8.0. This works well when querying roles but when in a relationship with users it does't work

Tray2's avatar

@kevinwakhisi Then you are doing something wrong.

I have a Book model that has a many to one relation with formats.

    public function format()
    {
        return $this->belongsTo(Format::class);
    }

So I can get the format of the book by doing $book->format->format. Then I add this to the Format model.

public function getFormatColorAttribute()
    {
        return match($this->format) {
            'Paperback' => 'primary',
            'Hardcover' => 'secondary'

        };
    }

Then I call can do this

$book = Book::find(4);

$book->format format;  //(Paperback)

$book->format->format_color; //(primary)
1 like
kevinwakhisi's avatar

@Tray2 in my case i am using spatie permissionsand i wouldn't want to add a column to display colors so resulted to accessors. Now i dug deep into it and the relationship belongs to many.

/**
     * A role belongs to some users of the model associated with its guard.
     */
    public function users(): BelongsToMany
    {
        return $this->morphedByMany(
            getModelForGuard($this->attributes['guard_name']),
            'model',
            config('permission.table_names.model_has_roles'),
            PermissionRegistrar::$pivotRole,
            config('permission.column_names.model_morph_key')
        );
    }

I just added the method

public function getRoleColorAttribute()
    {
        # code...
        return match($this->name) {
            'super-admin' => 'primary',
            'admin' => 'secondary'
        };
    }

works fine when i query the roles only in a table but when i try to query users with roles relationship it does show the roles but the colors are not available

Sinnbeck's avatar

How isn't your code working? Error? Always warning class?

kevinwakhisi's avatar

@Sinnbeck it doesn't display any class. works fine when fetching roles only but when fetching users with roles doesn't show

kevinwakhisi's avatar

@Sinnbeck

<?php

namespace Spatie\Permission\Models;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
use Spatie\Permission\Contracts\Role as RoleContract;
use Spatie\Permission\Exceptions\GuardDoesNotMatch;
use Spatie\Permission\Exceptions\RoleAlreadyExists;
use Spatie\Permission\Exceptions\RoleDoesNotExist;
use Spatie\Permission\Guard;
use Spatie\Permission\PermissionRegistrar;
use Spatie\Permission\Traits\HasPermissions;
use Spatie\Permission\Traits\RefreshesPermissionCache;

class Role extends Model implements RoleContract
{
    use HasPermissions;
    use RefreshesPermissionCache;

    protected $guarded = [];

    public function __construct(array $attributes = [])
    {
        $attributes['guard_name'] = $attributes['guard_name'] ?? config('auth.defaults.guard');

        parent::__construct($attributes);

        $this->guarded[] = $this->primaryKey;
    }

    public function getTable()
    {
        return config('permission.table_names.roles', parent::getTable());
    }

    public static function create(array $attributes = [])
    {
        $attributes['guard_name'] = $attributes['guard_name'] ?? Guard::getDefaultName(static::class);

        $params = ['name' => $attributes['name'], 'guard_name' => $attributes['guard_name']];
        if (PermissionRegistrar::$teams) {
            if (array_key_exists(PermissionRegistrar::$teamsKey, $attributes)) {
                $params[PermissionRegistrar::$teamsKey] = $attributes[PermissionRegistrar::$teamsKey];
            } else {
                $attributes[PermissionRegistrar::$teamsKey] = app(PermissionRegistrar::class)->getPermissionsTeamId();
            }
        }
        if (static::findByParam($params)) {
            throw RoleAlreadyExists::create($attributes['name'], $attributes['guard_name']);
        }

        return static::query()->create($attributes);
    }

    /**
     * A role may be given various permissions.
     */
    public function permissions(): BelongsToMany
    {
        return $this->belongsToMany(
            config('permission.models.permission'),
            config('permission.table_names.role_has_permissions'),
            PermissionRegistrar::$pivotRole,
            PermissionRegistrar::$pivotPermission
        );
    }

    /**
     * A role belongs to some users of the model associated with its guard.
     */
    public function users(): BelongsToMany
    {
        return $this->morphedByMany(
            getModelForGuard($this->attributes['guard_name']),
            'model',
            config('permission.table_names.model_has_roles'),
            PermissionRegistrar::$pivotRole,
            config('permission.column_names.model_morph_key')
        );
    }

    /**
     * Find a role by its name and guard name.
     *
     * @param string $name
     * @param string|null $guardName
     *
     * @return \Spatie\Permission\Contracts\Role|\Spatie\Permission\Models\Role
     *
     * @throws \Spatie\Permission\Exceptions\RoleDoesNotExist
     */
    public static function findByName(string $name, $guardName = null): RoleContract
    {
        $guardName = $guardName ?? Guard::getDefaultName(static::class);

        $role = static::findByParam(['name' => $name, 'guard_name' => $guardName]);

        if (! $role) {
            throw RoleDoesNotExist::named($name);
        }

        return $role;
    }

    public static function findById(int $id, $guardName = null): RoleContract
    {
        $guardName = $guardName ?? Guard::getDefaultName(static::class);

        $role = static::findByParam(['id' => $id, 'guard_name' => $guardName]);

        if (! $role) {
            throw RoleDoesNotExist::withId($id);
        }

        return $role;
    }

    /**
     * Find or create role by its name (and optionally guardName).
     *
     * @param string $name
     * @param string|null $guardName
     *
     * @return \Spatie\Permission\Contracts\Role
     */
    public static function findOrCreate(string $name, $guardName = null): RoleContract
    {
        $guardName = $guardName ?? Guard::getDefaultName(static::class);

        $role = static::findByParam(['name' => $name, 'guard_name' => $guardName]);

        if (! $role) {
            return static::query()->create(['name' => $name, 'guard_name' => $guardName] + (PermissionRegistrar::$teams ? [PermissionRegistrar::$teamsKey => app(PermissionRegistrar::class)->getPermissionsTeamId()] : []));
        }

        return $role;
    }

    protected static function findByParam(array $params = [])
    {
        $query = static::when(PermissionRegistrar::$teams, function ($q) use ($params) {
            $q->where(function ($q) use ($params) {
                $q->whereNull(PermissionRegistrar::$teamsKey)
                    ->orWhere(PermissionRegistrar::$teamsKey, $params[PermissionRegistrar::$teamsKey] ?? app(PermissionRegistrar::class)->getPermissionsTeamId());
            });
        });
        unset($params[PermissionRegistrar::$teamsKey]);
        foreach ($params as $key => $value) {
            $query->where($key, $value);
        }

        return $query->first();
    }

    /**
     * Determine if the user may perform the given permission.
     *
     * @param string|Permission $permission
     *
     * @return bool
     *
     * @throws \Spatie\Permission\Exceptions\GuardDoesNotMatch
     */
    public function hasPermissionTo($permission): bool
    {
        if (config('permission.enable_wildcard_permission', false)) {
            return $this->hasWildcardPermission($permission, $this->getDefaultGuardName());
        }

        $permissionClass = $this->getPermissionClass();

        if (is_string($permission)) {
            $permission = $permissionClass->findByName($permission, $this->getDefaultGuardName());
        }

        if (is_int($permission)) {
            $permission = $permissionClass->findById($permission, $this->getDefaultGuardName());
        }

        if (! $this->getGuardNames()->contains($permission->guard_name)) {
            throw GuardDoesNotMatch::create($permission->guard_name, $this->getGuardNames());
        }

        return $this->permissions->contains('id', $permission->id);
    }
}

but since this is a package i added this model to it

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Spatie\Permission\Models\Role as ModelsRole;

class Role extends ModelsRole
{
    use HasFactory;


    public function getRoleColorAttribute()
    {
        # code...
        return [
            'super-admin' => 'primary',
            'vicar' => 'danger',
            'council' => 'info',
            'user' => 'default'
        ][$this->name] ?? 'warning';

    }
}
Tray2's avatar

@kevinwakhisi What does your User model look like?

And what happens if you call the role relationship.

dd($user->role);
//or 
dd($user->roles);

//depending on how you defined the relationship to the Role model. 
kevinwakhisi's avatar

@Tray2

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use Laravel\Sanctum\HasApiTokens;
use Spatie\Permission\Traits\HasRoles;

class User extends Authenticatable
{
    use HasApiTokens, HasFactory, Notifiable, HasRoles;

    /**
     * The attributes that are mass assignable.
     *
     * @var string[]
     */
    protected $fillable = [
        'name',
        'email',
        'password',
        'prefix',
        'gender',
        'phone',
    ];

    /**
     * The attributes that should be hidden for serialization.
     *
     * @var array
     */
    protected $hidden = [
        'password',
        'remember_token',
    ];

    /**
     * The attributes that should be cast.
     *
     * @var array
     */
    protected $casts = [
        'email_verified_at' => 'datetime',
    ];

    public function avatarUrl()
    {
        # code...
        return 'https://www.gravatar.com/avatar/' . md5(strtolower(trim($this->email)));
    }

    public function getDateForHumansAttribute()
    {
        # code...
        return $this->created_at->format('d, M Y');
    }


}

that's my user model

kevinwakhisi's avatar

@Tray2 well in spatie it does work fine since i am using traits but let me try this

Tray2's avatar

@kevinwakhisi If the dd($user->roles) or dd($user->role). gives you a role instance then you are good, if it doesn't you need to add it.

It might be that it gives you an array and then you need to adapt you accessor to handle that.

kevinwakhisi's avatar

@Sinnbeck

<tbody class="text-gray-600 fw-bold">
                                @forelse ($users as $user)
                                    <tr wire:loading.class='opacity-50'>
                                        <!--begin::Checkbox-->
                                        <td>
                                            <div class="form-check form-check-sm form-check-custom form-check-solid">
                                                <input wire:model='selectedUsers' class="form-check-input"
                                                    type="checkbox" value="{{ $user->id }}">
                                            </div>
                                        </td>
                                        <!--end::Checkbox-->
                                        <!--begin::User=-->
                                        <td class="d-flex align-items-center">
                                            <!--begin:: Avatar -->
                                            <div class="symbol symbol-circle symbol-50px overflow-hidden me-3">
                                                <a href="/rider-html-pro/apps/user-management/users/view.html">
                                                    <div class="symbol-label">
                                                        <img src="{{ $user->avatarUrl() }}" alt="{{ $user->name }}"
                                                            class="w-100">
                                                    </div>
                                                </a>
                                            </div>
                                            <!--end::Avatar-->
                                            <!--begin::User details-->
                                            <div class="d-flex flex-column">
                                                <a href="/rider-html-pro/apps/user-management/users/view.html"
                                                    class="text-gray-800 text-hover-primary mb-1">{{ $user->name }}</a>
                                                <span>{{ $user->email }}</span>
                                            </div>
                                            <!--begin::User details-->
                                        </td>
                                        <!--end::User=-->
                                        <!--begin::Role=-->
                                        <td>
                                            @foreach ($user->roles as $role)
                                                <a href="#" class="badge badge-light-{{$role->role_color}}">
                                                    {{ $role->name }} color {{$role->role_color}}
                                                </a>
                                            @endforeach
                                        </td>
                                        <!--end::Role=-->
                                        <!--begin::Last login=-->
                                        <td data-order="2021-12-02T20:12:38+03:00">
                                            <div class="badge badge-light fw-bolder">Yesterday</div>
                                        </td>
                                        <!--end::Last login=-->
                                        <!--begin::Two step=-->
                                        <td></td>
                                        <!--end::Two step=-->
                                        <!--begin::Joined-->
                                        <td data-order="2021-12-20T17:30:00+03:00">{{ $user->date_for_humans }}</td>
                                        <!--begin::Joined-->
                                        <!--begin::Action=-->
                                        <td class="text-end">
                                            <a href="#" class="btn btn-light btn-active-light-primary btn-sm"
                                                data-kt-menu-trigger="click" data-kt-menu-placement="bottom-end">Actions
                                                <!--begin::Svg Icon | path: icons/duotune/arrows/arr072.svg-->
                                                <span class="svg-icon svg-icon-5 m-0">
                                                    <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24"
                                                        viewBox="0 0 24 24" fill="none">
                                                        <path
                                                            d="M11.4343 12.7344L7.25 8.55005C6.83579 8.13583 6.16421 8.13584 5.75 8.55005C5.33579 8.96426 5.33579 9.63583 5.75 10.05L11.2929 15.5929C11.6834 15.9835 12.3166 15.9835 12.7071 15.5929L18.25 10.05C18.6642 9.63584 18.6642 8.96426 18.25 8.55005C17.8358 8.13584 17.1642 8.13584 16.75 8.55005L12.5657 12.7344C12.2533 13.0468 11.7467 13.0468 11.4343 12.7344Z"
                                                            fill="black">
                                                        </path>
                                                    </svg>
                                                </span>
                                                <!--end::Svg Icon-->
                                            </a>
                                            <!--begin::Menu-->
                                            <div class="menu menu-sub menu-sub-dropdown menu-column menu-rounded menu-gray-600 menu-state-bg-light-primary fw-bold fs-7 w-125px py-4"
                                                data-kt-menu="true">
                                                <!--begin::Menu item-->
                                                <div class="menu-item px-3">
                                                    <a href="/rider-html-pro/apps/user-management/users/view.html"
                                                        class="menu-link px-3">Edit</a>
                                                </div>
                                                <!--end::Menu item-->
                                                <!--begin::Menu item-->
                                                <div class="menu-item px-3">
                                                    <a href="#" class="menu-link px-3"
                                                        data-kt-users-table-filter="delete_row">Delete</a>
                                                </div>
                                                <!--end::Menu item-->
                                            </div>
                                            <!--end::Menu-->
                                        </td>
                                        <!--end::Action=-->
                                    </tr>
                                @empty
                                    <tr>
                                        <td colspan="7">
                                            <div class="alert alert-warning d-flex align-items-center p-5 mb-10">
                                                <!--begin::Svg Icon | path: icons/duotune/general/gen048.svg-->
                                                <span class="svg-icon svg-icon-2hx svg-icon-warning me-4">
                                                    <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24"
                                                        viewBox="0 0 24 24" fill="none">
                                                        <rect opacity="0.3" x="2" y="2" width="20" height="20" rx="10"
                                                            fill="black"></rect>
                                                        <rect x="11" y="14" width="7" height="2" rx="1"
                                                            transform="rotate(-90 11 14)" fill="black"></rect>
                                                        <rect x="11" y="17" width="2" height="2" rx="1"
                                                            transform="rotate(-90 11 17)" fill="black"></rect>
                                                    </svg>
                                                </span>
                                                <!--end::Svg Icon-->
                                                <div class="d-flex flex-column">
                                                    <h4 class="mb-1 text-warning">Not Found</h4>
                                                    <span>Information doesn't exist</span>
                                                </div>
                                            </div>
                                        </td>
                                    </tr>
                                @endforelse
                            </tbody>

Thats the whole table but the main focus is on this part is the table data

<td>
@foreach ($user->roles as $role)
  <a href="#" class="badge badge-light-{{$role->role_color}}">
{{ $role->name }} color {{$role->role_color}}
</a>
@endforeach
 </td>

sorry the code appears un-formatted

Sinnbeck's avatar

Wait. Where did you set it to use your custom model in the relationship? If you don't overwrite it, it will use the default one

Please or to participate in this conversation.