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

Lipiniak's avatar

Multirelations with 3 tables

Hi,

I have 3 tables - users, games and platforms. I wrote relation many-to-many for games and platforms via pivot table games_platforms, and it works just fine. But i have no idea how to create relations with those 3 tables with pivot table like user_id, game_id, platform_id.

I need to show user games and its platforms but user can have only some platforms for the game. So user have game on specific platform. Not game on all platforms.

Im thinking of using hasManyThrough but I dont realy understand how it works.

0 likes
8 replies
xmarks's avatar

does this currently not work?

// Get all data - This would be in the controller
$user = User::find($id)->with('games.platforms');

// Get User Games
$user->games;

// Get Platform for each game - This could be converted into blade for the view to Render games and their Platforms
foreach($user->games as $game) {
    foreach($game->platforms as $platform) {
        echo $platform->name;
    }
}
Lipiniak's avatar

I got error on this:

Undefined property: Illuminate\Database\Eloquent\Builder::$games

In User model i got relations like this now:

public function games() {
        return $this->belongsToMany('App\Games','users_games_platforms');
    }
xmarks's avatar

As far as I understand, you should have these relations:

  • User Model:
public function games() {
    return $this->hasMany(Game::class);
}
  • Game Model:
public function user() {
    return $this->belongsTo(User::class);
}

public function platforms() {
    return $this->belongsToMany(Platform::class);
}
  • Platform Model:
public function games() {
    return $this->belongsToMany(Game::class);
}

Your users table should have:

  • id => primary Key

Your games table should have:

  • id => Primary Key
  • user_id => Foreign Key, related to users table

Your platforms table should have:

  • id => Primary Key

You should have a Pivot Table game_platform for the relation between games and platforms, which should have these fields:

  • game_id => Foreign Key to games Table
  • platform_id => Foreign Key to platforms Table

With these relations and table-structure, everything should work as I have mentioned on my previous reply. If you are using different Table Names and Primary / Foreign Key names, then the relations here should be changed to match those table names and Primary / Foreign Key names.

lostdreamer_nl's avatar

Small bugfix on the first reply:

$user = User::find($id)->with('games.platforms');

Should be

$user = User::with('games.platforms')->find($id);
// OR
$user = User::find($id)->load('games.platforms');

Giving you back a user object instead of a Query Builder.

Looking at the rest of the code posted, after this change it should work.

Lipiniak's avatar

Hi,

Sorry for late answer. You misunderstand me.

I got tables: user

  • id => user id

games

  • id => game id

platforms

  • id => platrofm id

and pivot table

user_games_platforms

  • user_id => user id from user table
  • games_id => game id from games table
  • platform_id => platform id from platform tables

So i need a 3 way relation i think.

I made relations in models:

UserModel

public function games() {
        return $this->belongsToMany('App\Games','users_games_platforms');
    }

and GamesModel

 public function userPlatforms() {
        return $this->belongsToMany('App\Platforms','users_games_platforms');
    }

It works half way because when a call $games->platforms i get all rows from database not only from current user.

I belive that sql for that will look like this:

SELECT * FROM `users_games_platforms` 
left join users on user_id = users.id 
left join games on games_id = games.id 
left join platforms on platforms_id = platforms.id where user_id = 1
xmarks's avatar

Well first of all, I must say it is my personal opinion that this relation makes no sense. There is no reason the users table is connected to the platforms table directly. It should connect only through the games table, as I have described above.

Next, as far as I know, Laravel does not support this. So you are probably going to have to write every method yourself to Keep these data in Synchronization.

Still, if you want to continue with this method, I think this might work out for your case. But again this would simply simulate three 2-way pivot tables: game_user, platform_user and game_platform. These are all ManyToMany Relations.

A Many To Many Relation is declared like this:

return $this->belongsToMany('App\Model', 'foreign_key', 'local_key', 'table_name');

So for your case, the User Model is like this:

public function games() {
    return $this->belongsToMany(Games::class, 'user_id', 'id', 'users_games_platforms');
}

public function platforms() {
    return $this->belongsToMany(Platform::class, 'user_id', 'id', 'users_games_platforms');
}

The Game Model:

public function users() {
    return $this->belongsToMany(User::class, 'game_id', 'id', 'users_games_platforms');
}

public function platforms() {
    return $this->belongsToMany(Platform::class, 'game_id', 'id', 'users_games_platforms');
}

The Platform Model:

public function users() {
    return $this->belongsToMany(User::class, 'platform_id', 'id', 'users_games_platforms');
}

public function games() {
    return $this->belongsToMany(Game::class, 'platform_id', 'id', 'users_games_platforms');
}

So now, if the above works, you should be able to do the following:

  • $user = User::find($id)->with('platforms'); to get the Platforms of a User
  • $user = User::find($id)->with('games'); to get the Games of a User
  • $game = Game::find($id)->with('users'); to get the Users of a Game
  • $platform = Platform::find($id)->with('users'); to get the Users of a Platform

But again I seriously advise against going though with this method and follow the one I posted previously.

Lipiniak's avatar

So if my thinking is wrong and your thinking is better how do u think to show game with only 1 platform. Quick example.

I have 1 game like FIFA. FIFA can be runned on PC, XBOX and PS4. but i got only PC version. So i check checkbox for FIFA => PC Platform. I dont have other platforms.

Is there other way to relation this without 3 way relations or duplicating row in games and platforms tables?

Im not good in programing so if this post offense you that im realy sorry.

xmarks's avatar

I am not that great with programming myself. As I stated above, this is my "Personal Opinion". You can follow your own goals or wait for someone else to give their opinion which might support yours.

Games and Platforms are fine to have a relation. Did you read my post above?

Again:

Your users table should have:

  • id => primary Key

Your games table should have:

  • id => Primary Key
  • user_id => Foreign Key, related to users table // If you are saving a list of games for a User, otherwise, you can remove this as well.

Your platforms table should have:

  • id => Primary Key

You should have a Pivot Table game_platform for the relation between games and platforms, which should have these fields:

  • game_id => Foreign Key to games Table
  • platform_id => Foreign Key to platforms Table

If you want games under PC Platform then you will end up with something like:

// In your Controller
$platform = Platform::where('name', '=', 'PC')->with('games')->get();

// In your View
<ul>
    @foreach($platform->games as $game)
        <li>{{ $game->name }}</li>
    @endforeach 
</ul>

If you want users, who own a game, under PC Platform:

// Your Controller
$platform = Platform::where('name', '=', 'PC')->with('games.users')->get();

// Your View
<ul>
    <!-- list of games -->
    @foreach($platform->games as $game)
        <li>{{ $game->name }}</li>
        
        <!-- For Each Game, list of users who own it -->
        <ul>
            @foreach($game->users as $user)
                <li>{{ $user->name }}
            @endforeach 
        </ul>
    @endforeach 
</ul>

And there you have it.

If you wish you might have a many-to-many relation between games and users as well, so there is no redundancy in the games field. Again depends on your project and what you wish to achieve.

So you can have: users <=> game_user <=> games <=> game_platform <=> platforms

So you will have to change these table structures:

  • users table => | id | name |
  • games table => | id | name |
  • game_user table => | game_id | user_id |

The Queries will still work the same after you have declared the Relations on the Models.

Edit

What do you plan to do in this case:

  • You add a New Game
  • You add Platforms for the game => will populate your games_users_platforms => what user_id will you add in this example? No User owns this new game yet, it was just added to the system.

Please or to participate in this conversation.