web-mooc/app/Http/Controllers/student/QuizController.php
2026-01-13 10:32:05 +07:00

241 lines
8.9 KiB
PHP

<?php
namespace App\Http\Controllers\student;
use App\Http\Controllers\Controller;
use App\Models\Enrollment;
use App\Models\Course;
use App\Models\Lesson;
use App\Models\Watch_history;
use App\Models\Certificate;
use App\Models\QuizSubmission;
use App\Models\Question;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Session;
class QuizController extends Controller
{
public function quiz_submit(Request $request)
{
$quiz = Lesson::findOrFail($request->quiz_id);
// 1. Cek Retake (Kesempatan mengulang)
$retake = $quiz->retake;
$submit_count = QuizSubmission::where('quiz_id', $quiz->id)
->where('user_id', auth()->user()->id)
->count();
if ($submit_count >= $retake) {
Session::flash('warning', get_phrase('Attempt has been over.'));
return redirect()->back();
}
// 2. Rapikan Input Jawaban
$inputs = $request->except(['_token', 'quiz_id']);
$submits = [];
// Loop input untuk membersihkan format data (terutama jika dari JS frontend)
foreach ($inputs as $question_id => $answer) {
if ($answer !== null) {
// Jika input berupa string JSON (kecuali 'true'/'false'), decode dulu
if (is_string($answer) && !in_array($answer, ['true', 'false'])) {
$decoded = json_decode($answer, true);
if (json_last_error() === JSON_ERROR_NONE && is_array($decoded)) {
// Ambil value jika strukturnya array of objects
$submits[$question_id] = array_column($decoded, 'value');
} else {
$submits[$question_id] = $answer;
}
} else {
$submits[$question_id] = $answer;
}
}
}
// 3. Ambil Soal dari Database
// Kita ambil soal berdasarkan key dari jawaban yang dikirim
$question_ids = array_keys($submits);
$questions = Question::whereIn('id', $question_ids)->get();
$right_answers = [];
$wrong_answers = [];
// 4. Proses Koreksi Jawaban
foreach ($questions as $question) {
// PENTING: Ambil jawaban user berdasarkan ID Soal, bukan urutan index loop
if (!isset($submits[$question->id])) {
continue;
}
$submitted = $submits[$question->id];
$correct_answer = json_decode($question->answer, true);
$isCorrect = false;
// Logika per tipe soal
if ($question->type == 'mcq') {
// Cek array diff (bolak-balik) untuk memastikan isi array sama persis
$isCorrect = empty(array_diff($correct_answer, $submitted))
&& empty(array_diff($submitted, $correct_answer));
} elseif ($question->type == 'fill_blanks') {
if (count($correct_answer) === count($submitted)) {
$isCorrect = true;
foreach ($correct_answer as $i => $ans) {
// Trim dan strtolower agar tidak case-sensitive
if (trim(strtolower($ans)) !== trim(strtolower($submitted[$i]))) {
$isCorrect = false;
break;
}
}
}
} elseif ($question->type == 'true_false') {
$isCorrect = strtolower(json_encode($correct_answer)) === strtolower($submitted);
}
// Masukkan ke bucket Benar/Salah
if ($isCorrect) {
$right_answers[] = $question->id;
} else {
$wrong_answers[] = $question->id;
}
}
// 5. Simpan Hasil Submission
QuizSubmission::create([
'quiz_id' => $quiz->id,
'user_id' => auth()->user()->id,
'correct_answer' => json_encode($right_answers),
'wrong_answer' => json_encode($wrong_answers),
'submits' => json_encode($submits),
]);
// 6. Hitung Nilai
$total_questions = $questions->count();
$mark_per_question = $total_questions > 0 ? ($quiz->total_mark / $total_questions) : 0;
$obtained_mark = count($right_answers) * $mark_per_question;
// 7. Cek Kelulusan
if ($obtained_mark >= $quiz->pass_mark) {
// PANGGIL FUNGSI YANG BERADA DI CLASS YANG SAMA
$this->update_watch_history2(
$quiz->id,
$quiz->course_id,
auth()->user()->id
);
Session::flash('success', get_phrase('Congratulations, you passed the quiz.'));
} else {
Session::flash('warning', get_phrase('You did not reach the minimum score.'));
}
return redirect()->back();
}
public function update_watch_history2($lesson_id, $course_id, $student_id)
{
// Validasi Course
$course = Course::where('id', $course_id)->first();
if (!$course) return;
// Validasi Enrollment
$enrollment = Enrollment::where('course_id', $course->id)
->where('user_id', $student_id)
->exists();
// Cek Role (Jika admin/instruktur boleh bypass enrollment check)
$currentUserRole = auth()->check() ? auth()->user()->role : 'student';
if (!$enrollment && ($currentUserRole != 'admin' && !is_course_instructor($course->id))) {
return;
}
// Ambil semua lesson ID untuk hitung progress manual
$total_lesson_ids = Lesson::where('course_id', $course_id)->pluck('id')->toArray();
// Ambil data history user
$watch_history = Watch_history::where('course_id', $course_id)
->where('student_id', $student_id)
->first();
$completed_lessons = [];
// Parse data lama
if ($watch_history && $watch_history->completed_lesson) {
$decoded = json_decode($watch_history->completed_lesson, true);
if (is_array($decoded)) {
$completed_lessons = $decoded;
}
}
// Tambahkan lesson_id baru jika belum ada
if (!in_array($lesson_id, $completed_lessons)) {
$completed_lessons[] = $lesson_id;
}
// Tentukan apakah course selesai
$is_completed = count($total_lesson_ids) <= count($completed_lessons);
$data = [
'course_id' => $course_id,
'student_id' => $student_id,
'watching_lesson_id' => $lesson_id,
'completed_lesson' => json_encode($completed_lessons),
'completed_date' => $is_completed ? time() : null,
];
// Simpan ke DB
if ($watch_history) {
Watch_history::where('id', $watch_history->id)->update($data);
} else {
// Gunakan create agar timestamp created_at terisi otomatis
Watch_history::create($data);
}
// --- LOGIKA SERTIFIKAT ---
// Hitung progress secara manual agar lebih akurat
$progress_percentage = 0;
if (count($total_lesson_ids) > 0) {
$progress_percentage = (count($completed_lessons) / count($total_lesson_ids)) * 100;
}
if ($progress_percentage >= 100) {
$certificateExists = Certificate::where('user_id', $student_id)
->where('course_id', $course_id)
->exists();
if (!$certificateExists) {
Certificate::create([
'user_id' => $student_id,
'course_id' => $course_id,
'identifier' => substr(md5(uniqid(mt_rand(), true)), 0, 10), // Generate random ID
]);
}
}
return true;
}
public function load_result(Request $request)
{
$page_data['quiz'] = Lesson::where('id', $request->quiz_id)->first();
$page_data['questions'] = Question::where('quiz_id', $request->quiz_id)->get();
$page_data['result'] = QuizSubmission::where('id', $request->submit_id)
->where('quiz_id', $request->quiz_id)
->where('user_id', auth()->user()->id)
->first();
return view('course_player.quiz.result', $page_data);
}
public function load_questions(Request $request)
{
$page_data['quiz'] = Lesson::where('id', $request->quiz_id)->first();
$page_data['questions'] = Question::where('quiz_id', $request->quiz_id)->get();
$page_data['submits'] = QuizSubmission::where('quiz_id', $request->quiz_id)
->where('user_id', auth()->user()->id)
->get();
$page_data['course_details'] = Course::where('id', $page_data['quiz']->course_id)->first();
return view('course_player.quiz.questions', $page_data);
}
}