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

JoeCianflone's avatar

Map Data on a hasMany Relationship

Hello,

So imagine I have a user and that user has many roles and they can also belongToMany workspaces (think of a workspace like a slack workspace)

    public function roles(): HasMany
    {
        return $this->hasMany(Role::class);
    }

   public function workspaces(): BelongsToMany
    {
        return $this->belongsToMany(Workspace::class);
    }

Now when you log into a workspace I want to be able to display your role on the page....now you could have 100 different roles across 100 different sites so what I'm doing is creating a new method on the User where I first map the roles based on workspace ID.

    public function workspaceRoles() {
        return $this->roles->flatMap(function($item) {
            return [$item->workspace_id => $item];
        });
    }

Then when I need to get this specific role for the specific workspace I just call it like so:

$member->workspaceRoles()->get(123);

This all works...but I freaking hate it. What I would love to do is just have the roles() method return all the data mapped the way I want, but I'm not sure if there's a good way to do this...or if there's some hidden pitfall if I do.

So, does anyone do this? Is there a clean way to remap the data on the hasMany relationship?

0 likes
1 reply
JoeCianflone's avatar
JoeCianflone
OP
Best Answer
Level 1

OK so I don't think there's a much better way to do this, but I did tweak the original code a bit to now just be the following:

    public function role(string $workspaceID): Role
    {
        return $this->roles->filter(function($role) use ($workspaceID) {
            return $role->workspace_id == $workspaceID || $role->workspace_id == null;
        })->first();
    }

Basically, roles() has my relationship on it and role() allows me to grab a single role and I just filter the content. There may be something better out there, I really don't know, but for now this works.

Please or to participate in this conversation.