Я начал разрабатывать веб-сайт с использованием Laravel, и я почти все нахожу через официальную документацию и ответы, которые я нахожу здесь. Однако есть одна вещь, которую - хотя я нашел способ сделать - у меня есть ощущение, что это можно сделать другим, более оптимизированным способом, чем тот, который я делаю прямо сейчас. Позволь мне объяснить.
На моем веб-сайте у меня есть таблица под названием «игроки», в которой содержатся данные о некоторых игроках, извлеченные из футбольного матча. Допустим, структура такая:
ID (int, первичный ключ, A_I)
GameID (int, unique) // что использует игра
Имя игрока
Данные (в основном много разных столбцов)
Поскольку цель моего веб-сайта - позволить пользователям вносить изменения в контент игры, у меня также есть еще одна таблица, которую я называю «userplayers», которую я использую для внесения изменений в игроков, которые существуют в исходной таблице, или для добавления новые. Структура похожа на таблицу «игроков», но только с одним добавленным столбцом, называемым идентификатором пользователя, который должен определять, какая модификация принадлежит какому пользователю.
ID (int, первичный ключ, A_I)
GameID (int, уникальный вместе с userID)
Имя игрока
Данные (в основном много разных столбцов)
UserID (int, уникальный вместе с GameID)
Если я добавляю запись в таблицу userplayers, если эта запись имеет тот же GameID, что и любая запись в таблице игроков (и пользователь, создавший ее, входит в систему), то во время выполнения она перезаписывает запись таблицы игроков. Если GameID новой записи не существует в исходной таблице игроков, он просто добавляется к ней.
Если пользователь не вошел в систему, я просто возвращаю таблицу игроков.
Используя красноречивую модель laravel, я могу легко получить таблицу игроков, когда пользователь не вошел в систему. Однако я не могу найти эффективный способ вернуть всю БД + созданный пользователем контент, просто используя основные функции красноречивой модели.
Раньше (без Laravel) я использовал этот запрос к БД:
SELECT * FROM (SELECT *, NULL FROM players WHERE NOT EXISTS (SELECT * FROM userplayers WHERE players.gameid=userplayers.gameid AND userId=$userId) UNION (SELECT * FROM userplayers WHERE userId=$userId)) AS pl;
И способ, которым я «нашел» что-то подобное в Laravel, - это добавление локальной области видимости внутри модели Players следующим образом:
public function scopeIncludeCustom($query, $user)
{
return \DB::select('SELECT * FROM (SELECT *, NULL FROM players WHERE NOT EXISTS (SELECT * FROM userplayers WHERE userplayers.gameid=players.gameid AND userId='.$user.') UNION (SELECT * FROM userplayers WHERE userId='.$user.')) AS players_full);
}
Однако вы можете понять, что это не возвращает $ query, как предполагалось областями, а просто массив php, который я возвращаю обратно, и я думаю, что это неправильный способ сделать это. Например, когда я просто ищу в таблице игроков (без использования содержимого, созданного пользователем), для возврата результатов требуется гораздо меньше времени, чем для возврата результатов с настраиваемым содержимым.
Любые идеи очень ценятся.
@JonasStaudenmeir Да, я определил обе эти модели, но я, кажется, не понимаю, как я могу представить указанный выше синтаксис mysql через отношения, такие как whereHas()
Вы можете использовать запрос UNION с Eloquent, но все результаты будут экземплярами модели Player: если вам нужны экземпляры Player и UserPlayer, вы должны выполнять отдельные запросы.






Итак, после нескольких дней изучения моей проблемы и возможных решений я пришел к этому решению.
Итак, давайте рассмотрим это шаг за шагом.
У меня была модель «Игрок», которая извлекала данные из таблицы «игроки».
У меня также была модель «Пользователь», которая извлекала данные из таблицы «пользователи».
Мне пришлось создать связь между этими двумя моделями. Запись в таблице «игроки» может иметь много записей, связанных с ними в таблице «пользователи». Итак, в модели Игрок я добавил это:
public function userplayers()
{
return $this->hasMany('App\Userplayer', 'gameid', 'gameid');
}
В модели Пользователь я добавил это:
public function player()
{
return $this->belongsTo('App\Player', 'gameid', 'gameid');
}
При запросе данных первым шагом было удаление каждой строки из таблицы «игроки», которая имела такой же «GameId», что и любая строка, возвращенная из таблицы «пользователи», которая также имела ограничение, что «userId» в каждой строке эта таблица должна быть конкретной.
Это код, который делает это в моем SearchPlayerController:
$orig_players = \App\Player::whereDoesntHave('userplayers', function ($query) use($user)
{
$query->where('userId', $user);
})->get();
В то же время мне нужно получить каждую строку из таблицы "userplayers", в которой есть "ID пользователя", который я хочу
$userplayers = \App\Userplayer::where([
['pesid', $search]
])->get();
Теперь я просто объединяю 2 результата (я не могу использовать UNION, потому что данные, которые я получаю из таблицы «игроки», имеют на один столбец меньше).
$players = $orig_players->merge($userplayers)
->sortBy('registeredName')
->take($limit);
И все работает отлично и намного быстрее, чем раньше!
Уже определились модели
PlayerиUserPlayer? Вы знакомы с Eloquent Relations иwhereHas()?