/**
  * Fetch random exercise of lesson
  *
  * Exercise that user knows less have more chance to be returned.
  * Exercise that user knows more have less chance to be returned.
  *
  * @param int $lessonId
  * @param int $userId
  * @param int|null $previousExerciseId
  * @return Exercise
  * @throws Exception
  * @throws NotEnoughExercisesException
  */
 public function fetchRandomExerciseOfLesson(int $lessonId, int $userId, int $previousExerciseId = null) : Exercise
 {
     /** @var Exercise[]|Collection $exercises */
     $exercises = Exercise::select('exercises.*')->with('results')->join('lessons', 'lessons.id', '=', 'exercises.lesson_id')->where('lessons.id', '=', $lessonId)->where('exercises.id', '!=', $previousExerciseId)->get();
     if ($exercises->count() == 1) {
         return $exercises->first();
     }
     if ($exercises->isEmpty()) {
         throw new NotEnoughExercisesException();
     }
     $tmp = [];
     foreach ($exercises as $exercise) {
         if ($exercise->results->isEmpty()) {
             /*
              * If results relation is not loaded, that means user has no answers for this exercises yet,
              * so we know that percent of good answers is 0
              */
             $percentOfGoodAnswers = 0;
         } else {
             /*
              * Using already loaded relation (so no extra db call is required) check percent of good answers
              * of a user
              */
             $percentOfGoodAnswers = $exercise->results->filter(function ($item) use($userId) {
                 return $item->user_id == $userId;
             })->first()->percent_of_good_answers;
         }
         /*
          * Fill $tmp array with $exercises multiplied by number of points.
          *
          * This way exercises with higher number of points (so lower user knowledge),
          * will have bigger chance to be returned.
          */
         for ($i = $this->calculateNumberOfPoints($percentOfGoodAnswers); $i > 0; $i--) {
             $tmp[] = $exercise;
         }
     }
     // do randomization
     shuffle($tmp);
     return $tmp[array_rand($tmp)];
 }
 /**
  * @param UpdateExerciseRequest $request
  * @param Exercise $exercise
  * @return JsonResponse
  */
 public function updateExercise(UpdateExerciseRequest $request, Exercise $exercise)
 {
     $exercise->update($request->all());
     return $this->response($exercise);
 }
 public function test_handleBadAnswer()
 {
     $this->exerciseRepository->expects($this->once())->method('handleBadAnswer')->with($this->exercise->id, $this->user->id);
     $this->exercise->handleBadAnswer($this->user->id);
 }
 /**
  * @param Exercise $exercise
  * @param UpdateExerciseRequest $request
  * @return RedirectResponse
  */
 public function update(Exercise $exercise, UpdateExerciseRequest $request) : RedirectResponse
 {
     $exercise->update($request->all());
     return redirect('/lessons/' . $exercise->lesson_id);
 }
 /**
  * @param Exercise $exercise
  */
 public function handleBadAnswer(Exercise $exercise)
 {
     $this->authorizeForUser($this->user(), 'learn', $exercise->lesson);
     $exercise->handleBadAnswer($this->user()->id);
 }