#php #laravel #eloquent #eloquent-relationship
Вопрос:
Ларавель/Красноречивый новичок здесь. Я внедряю простую настольную игру. В каждой игре участвуют 4 игрока. Структура таблиц состоит из таблицы игроков и игрового стола:
SELECT * FROM players;
id | name |
---------------------
1 | John |
2 | Mary |
3 | Linda |
4 | Alex |
5 | Chris |
6 | Ron |
7 | Dave |
SELECT * FROM games;
id | player1_id | player2_id | player3_id player4_id
---------------------------------------------------------------------
1 | 1 | 2 | 3 | 4
2 | 3 | 5 | 6 | 7
3 | 2 | 3 | 5 | 6
4 | 2 | 4 | 5 | 7
Цель: Я хочу иметь возможность получить все игры, в которых участвовал игрок.
Для этого я пытаюсь написать функцию games()
в модели плеера. Для игрока с идентификатором 2 это должно возвращать игры 1, 3, 4 / для игрока с идентификатором 3 это должно возвращать игры 1, 2, 3 и так далее.
С помощью необработанного SQL я бы сделал что-то вроде этого:
SELECT * FROM games WHERE
(player1_id = 2 OR player2_id = 2 OR player3_id = 2 OR player4_id = 2)
Но с Красноречивым мне трудно понять, как нужно выстраивать эти отношения, чтобы достичь этого.
Эквивалентно, я также хотел бы иметь возможность сделать обратное — вернуть всех игроков в игру — с помощью функции players()
в Game
модели.
Модели:
// Models/Player.php
//...
class Player extends Model
{
public function games(){
//?
}
}
// Models/Game.php
//...
class Game extends Model
{
public function players(){
//?
}
}
Комментарии:
1. Это отношение N к N, вы должны нормализовать.
2.
DB::table('games')->where('player1_id', '=',
ID)->orwhere('player2_id', '=', 'id')->orwhere('player3_id', '=', 'id')->orwhere('player4_id', '=', 'id')->get();
3. @HassaanAli Нет !!!!!! Используйте отношения, остановитесь
DB::something
, подумайте, чтоDB::something
их не существует для простых операций !!!!!!!!!4. Я согласен. Это не конвенция. Но для простоты решение есть. 🙂
Ответ №1:
Без изменения структуры базы данных вы можете неправильно hasMany
использовать объявление, чтобы получить всех 4 игроков.
class Game extends Model
{
public function players()
{
return $this->hasMany(Player::class, 'id', 'player1_id')
->orWhere('id', $this->player2_id)
->orWhere('id', $this->player3_id)
->orWhere('id', $this->player4_id);
}
}
class Player extends Model
{
public function games()
{
return $this->hasMany(Game::class, 'player1_id', 'id')
->orWhere('player2_id', $this->id)
->orWhere('player3_id', $this->id)
->orWhere('player4_id', $this->id);
}
}
Однако это не идеально.
У вас должна быть третья таблица, чтобы правильно сопоставить это отношение «многие ко многим».
table 1 - players: id (pk), name
table 2 - games: id (pk)
table 3 - game_player: id (pk), game_id (fk), player_id (fk), unique([game_id, player_id])
class Game extends Model
{
public function players()
{
return $this->belongsToMany(Player::class, 'game_player');
}
}
class Player extends Model
{
public function games()
{
return $this->belongsToMany(Game::class, 'game_player');
}
}
Комментарии:
1. На самом деле это именно то, что я искал. По общему признанию, более подходящим решением (а также лучшим дизайном) действительно была бы нормализация базы данных с помощью сводной таблицы. Однако в интересах простоты дизайна с одной записью за игру я, скорее всего, выберу этот подход. Большое спасибо.