Я создаю систему викторин в Ларавель 5.7, и теперь я извлекаю вопросы из базы данных, и я должен применить условие, что если пользователь попытался задать вопрос, то не показывать этот вопрос пользователю снова, для этого я создал базу данных с именем как attempted_questions и два поля там как user_id и question_id и применил следующий код в контроллере:
class NewTestController extends Controller
{
protected $question_id;
public function nextQuestion(Request $request) {
$attempted_questions = new AttemptedQuestion;
$attempted_questions->user_id = Auth::id();
$attempted_questions->question_id = $request->attempted;
$attempted_questions->save();
$question = Question::inRandomOrder()->first();
$attempted = AttemptedQuestion::all();
foreach ($attempted as $attempted) {
while ($question->id == $attempted->question_id) {
$question = Question::inRandomOrder()->first();
$this->question_id = $question->id;
}
}
return $this->question_id;
}
}
Здесь сначала я получаю попытку вопроса от AJAX, а затем сохраняю текущего пользователя и question_id в базе данных, а после этого я получаю случайные вопросы из базы данных и после этого проверяю, есть ли уже заданный вопрос в базе данных? если нет, то покажите, иначе отобразите сообщение, но проблема здесь в том, что он также вызывает вопрос, который уже занят
нет, братан, я проверяю, если вопрос, который был взят, уже находится в базе данных попыток вопросов? если да, то снова ответьте на вопрос из БД, иначе нет!






У вас есть какая-то логическая ошибка. Вы задаете новый случайный вопрос в цикле while, избегая предыдущих вопросов, вот что я имею в виду:
Предположим, у вас есть 3 вопроса [1,2,3] и 2 попытки задать вопрос [1, 2].
Таким образом, в вашем цикле foreach вы зацикливаетесь на [1, 2], теперь вы находитесь на первой попытке вопроса, у которого question_id равен 1, в этот момент вы берете новый вопрос, скажем, его question_id равен 2. затем переходите к следующей итерации , второй attempted_question, у которого question_id равен 2.
здесь вы сравниваете последний результат с текущим attempted_question, и он равен, поэтому он удовлетворяет условию $question->id == $attempted->question_id, поэтому вы выбираете новый вопрос и случайно получили идентификатор вопроса 1. в этот момент вы не собираетесь проверять, равен ли он к первому attempted_question, потому что мы уже пропустили его из массива $attempted_questions.
лучшим решением было бы следующее:
возьмите все идентификаторы attempted_questions и используйте whereNotIn, чтобы получить все вопросы, которые не были предприняты.
$attempted = AttemptedQuestion::pluck('question_id');
$question = Question::whereNotIn('id', $attempted)->inRandomOrder()->first();
теперь у вас есть вопрос, который вы ищете.
Но вы экранируете, пытался ли текущий пользователь ответить на него или нет, поэтому вам, возможно, придется добавить некоторые операторы where для AttemptedQuestion для текущего пользователя следующим образом:
$attempted = AttemptedQuestion::where('user_id', Auth::id())->pluck('question_id');
Таким образом, вы можете получить что-то вроде этого:
class NewTestController extends Controller
{
public function nextQuestion(Request $request) {
$attempted_questions = new AttemptedQuestion;
$attempted_questions->user_id = Auth::id();
$attempted_questions->question_id = $request->attempted;
$attempted_questions->save();
$attempted = AttemptedQuestion::where('user_id', Auth::id())->pluck('question_id');
$question = Question::whereNotIn('id', $attempted)->inRandomOrder()->first();
return $question->id;
}
}
Но это не проверено.
Надеюсь, поможет
Спасибо, братан, но я немного запутался, можешь отредактировать мой код?
p.s. вы можете проверить наличие $question==null и отправить сообщение пользователю, например, "Больше нет вопросов, пожалуйста, вернитесь позже" или что-то в этом роде.
ОМГ ОМГ ОМГ ОМГ ОМГ!!!!!!!! Люблю тебя брооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооолив
рад, что это помогает ^^
На самом деле это довольно плохое решение. Потому что он извлекает все идентификаторы предпринятых вопросов. Поэтому, когда пользователь ответил на множество вопросов, это не будет масштабироваться... См. Мой ответ для обновленной версии.
вы должны игнорировать идентификатор текущего вопроса в вопросе о модели, также я не могу его увидеть, я так думаю
1
'Вопрос' => ['обязательно', 'описание', Rule::unique('user')->игнорировать($question->id)]
надеюсь, что это поможет!
Я бы пошел на следующее решение:
Question::whereDoestHave('attempts', function($query) {
$query->where('user_id', Auth::id());
})->inRandomOrder()->take(1)->get();
Это будет работать, если вы определили следующее в своей модели вопросов:
public function attempts() {
return $this->hasMany('App\Models\AttemptedQuestion');
}
не должно ли это условие быть while ($question->id != $attempted->question_id) { .