Has anyone found a good solution to this +1 problem in Laravel/Eloquent? (getting parent model)

Posted 1 year ago by robjbrain

I regularly encounter this +1 problem in Eloquent and wandered if anyone had come up with a smart solution to it.

// Get a team and all its players
$team = Team::with('players')->find(1);

// List the team and all its players
<h2>{{ $team->name }}</h2>
@foreach($team->players as $player)
    <a href="{{ $player->url }}">{{ $player->name }}</a>
@endforeach

This looks simple enough right, however what if the url looks like this:

domain.com/team-name/player-name

In order to build the url we'll probably have a method like this:

public function getUrlAttribute() {
    return URL::to($player->team->name . '/' . $player->name);
}

However now what happens is that every time we want to list the players we also have to load the team again in order for it to be accessible to the $player model. This creates a +1 problem.

We could do this instead:

$team = Team::with('players.team')->find(1);

But that seems pointless?

We could also do something like this:

$player->url($team)

But that assumes we always have the $team, which might not always be true, it's also a bit messier.

I was thinking a better way might be to set the inverse relationship wherever possible when you eager load a model. However this is problematic, since you might only load some of a relationship, not all of it.

Another option might be to set some sort of "parents" array when eager loading a model, so when we do $player->team we see if $team is set within the parents array first before trying to load it.

All of these have complications though, not least with the variety of different relationships a model might have.

Has anyone sought to handle this situation? I'd be interested in your solutions or just for a good discussion :)

Please sign in or create an account to participate in this conversation.

Reply to

Use Markdown with GitHub-flavored code blocks.