From 80ac83db92d6293403702ae4c38abb46bdfdab64 Mon Sep 17 00:00:00 2001 From: Kumi Date: Mon, 25 Nov 2024 10:09:36 +0100 Subject: [PATCH] feat: Add XLSX export for user grades report Introduces XLSX export functionality to the user grades report. Adds a checkbox for selecting XLSX export in the form interface. Uses PhpSpreadsheet to generate and download detailed Excel files containing user grades and quiz attempts. Enhancement enables convenient data export for offline analysis and sharing. --- classes/usergrades_form.php | 3 + details.php | 191 +++++++++++++++++++++++++--------- lang/en/report_usergrades.php | 5 +- version.php | 2 +- 4 files changed, 147 insertions(+), 54 deletions(-) diff --git a/classes/usergrades_form.php b/classes/usergrades_form.php index e725b07..6099e16 100644 --- a/classes/usergrades_form.php +++ b/classes/usergrades_form.php @@ -15,6 +15,9 @@ class usergrades_form extends moodleform $mform->addElement('select', 'userid', get_string('selectuser', 'report_usergrades'), $users[get_string('users')]); + // XLSX Export checkbox + $mform->addElement('checkbox', 'exportxls', get_string('exportxls', 'report_usergrades')); + // Add form action buttons $this->add_action_buttons(false, get_string('showgrades', 'report_usergrades')); } diff --git a/details.php b/details.php index b2ac120..3ff8fb7 100644 --- a/details.php +++ b/details.php @@ -8,97 +8,184 @@ require_once($CFG->dirroot . '/user/selector/lib.php'); require_once('classes/user_selector.php'); require_once('classes/usergrades_form.php'); -// Set up the page context and other configurations +use PhpOffice\PhpSpreadsheet\Spreadsheet; +use PhpOffice\PhpSpreadsheet\Writer\Xlsx; + admin_externalpage_setup('report_usergrades_details', '', null, '', array('capability' => 'report/usergrades:view')); // Instantiate the form $mform = new usergrades_form(); -echo $OUTPUT->header(); -echo $OUTPUT->heading(get_string('usergradesreport', 'report_usergrades')); -// Form processing and displaying is done here -if ($mform->is_cancelled()) { - // Handle form cancellation, if necessary - redirect(new moodle_url('/admin/report.php')); -} else if ($data = $mform->get_data()) { +// Check if form data is submitted +if ($data = $mform->get_data()) { $userid = $data->userid; - // Fetch and display user grades if a user is selected if (!empty($userid)) { $user = $DB->get_record('user', array('id' => $userid), '*', MUST_EXIST); $courses = enrol_get_users_courses($user->id, true); $questions = $DB->get_records('question'); - // User details + if (isset($data->exportxls)) { // Assume a form field named 'exportxls' for Excel export action + // Create a new Spreadsheet object + $spreadsheet = new Spreadsheet(); + $sheet = $spreadsheet->getActiveSheet(); + $row = 1; - echo $OUTPUT->heading(get_string('userdetails', 'report_usergrades'), 3); + // Add the user details + $sheet->setCellValue('A' . $row, get_string('username', 'report_usergrades')); + $sheet->setCellValue('B' . $row, $user->username); + $row++; + $sheet->setCellValue('A' . $row, get_string('firstname', 'report_usergrades')); + $sheet->setCellValue('B' . $row, $user->firstname); + $row++; + $sheet->setCellValue('A' . $row, get_string('lastname', 'report_usergrades')); + $sheet->setCellValue('B' . $row, $user->lastname); + $row++; + $sheet->setCellValue('A' . $row, get_string('email', 'report_usergrades')); + $sheet->setCellValue('B' . $row, $user->email); + $row += 2; // Extra space before courses - $user_table = new html_table(); - $user_table->head = array(get_string('field', 'report_usergrades'), get_string('value', 'report_usergrades')); + // Start iterating the courses + foreach ($courses as $course) { + $sheet->setCellValue('A' . $row, get_string('course', 'report_usergrades') . ': ' . $course->fullname); + $row++; - $user_table->data[] = array(get_string('username', 'report_usergrades'), $user->username); - $user_table->data[] = array(get_string('firstname', 'report_usergrades'), $user->firstname); - $user_table->data[] = array(get_string('lastname', 'report_usergrades'), $user->lastname); - $user_table->data[] = array(get_string('email', 'report_usergrades'), $user->email); + $quizzes = $DB->get_records('quiz', array('course' => $course->id)); - echo html_writer::table($user_table); + if ($quizzes) { + foreach ($quizzes as $quiz) { + $quiz_attempts = $DB->get_records('quiz_attempts', array('quiz' => $quiz->id, 'userid' => $user->id)); - foreach ($courses as $course) { - echo $OUTPUT->heading($course->fullname, 3); + if ($quiz_attempts) { + $sheet->setCellValue('A' . $row, get_string('quiz', 'report_usergrades') . ': ' . $quiz->name); + $row++; - $quizzes = $DB->get_records('quiz', array('course' => $course->id)); + foreach ($quiz_attempts as $attempt) { + $sheet->setCellValue('A' . $row, get_string('attempt', 'report_usergrades') . ' ' . $attempt->attempt); + $row++; - if ($quizzes) { - echo $OUTPUT->heading(get_string('quizzes', 'report_usergrades'), 4); + $sheet->setCellValue('A' . $row, get_string('question', 'report_usergrades')); + $sheet->setCellValue('B' . $row, get_string('response', 'report_usergrades')); + $sheet->setCellValue('C' . $row, get_string('grade', 'report_usergrades')); + $row++; - foreach ($quizzes as $quiz) { - $quiz_questions = $DB->get_records('quiz_slots', array('quizid' => $quiz->id)); - $quiz_attempts = $DB->get_records('quiz_attempts', array('quiz' => $quiz->id, 'userid' => $user->id)); + $question_usages = $DB->get_records('question_usages', array('id' => $attempt->uniqueid)); - if ($quiz_attempts) { - echo $OUTPUT->heading($quiz->name, 5); + foreach ($question_usages as $question_usage) { + $question_attempts = $DB->get_records('question_attempts', array('questionusageid' => $question_usage->id)); - foreach ($quiz_attempts as $attempt) { - echo $OUTPUT->heading(get_string('attempt', 'report_usergrades') . ' ' . $attempt->attempt, 6); + foreach ($question_attempts as $question_attempt) { + $question = $questions[$question_attempt->questionid]; + $response = $question_attempt->responsesummary; - $attempt_table = new html_table(); - $attempt_table->head = array(get_string('question', 'report_usergrades'), get_string('response', 'report_usergrades'), get_string('grade', 'report_usergrades')); + $question_grades = $DB->get_records('question_attempt_steps', array('questionattemptid' => $question_attempt->id)); - $question_usages = $DB->get_records('question_usages', array('id' => $attempt->uniqueid)); - - foreach ($question_usages as $question_usage) { - $question_attempts = $DB->get_records('question_attempts', array('questionusageid' => $question_usage->id)); - - foreach ($question_attempts as $question_attempt) { - $question = $questions[$question_attempt->questionid]; - $response = $question_attempt->responsesummary; - - $question_grades = $DB->get_records('question_attempt_steps', array('questionattemptid' => $question_attempt->id)); - - foreach ($question_grades as $question_grade) { - if ($question_grade->fraction) { - $attempt_table->data[] = array($question->name . ': ' . $question->questiontext, $response, $question_grade->fraction); + foreach ($question_grades as $question_grade) { + if ($question_grade->fraction) { + $sheet->setCellValue('A' . $row, $question->name . ': ' . $question->questiontext); + $sheet->setCellValue('B' . $row, $response); + $sheet->setCellValue('C' . $row, $question_grade->fraction); + $row++; + } } } } + + $total_grade = $DB->get_record('quiz_grades', array('quiz' => $quiz->id, 'userid' => $user->id)); + $sheet->setCellValue('A' . $row, get_string('totalgrade', 'report_usergrades') . ': ' . $total_grade->grade . ' / ' . $quiz->grade); + $row += 2; // Extra space before next attempt or quiz } + } + } + } + $row += 2; // Extra space between courses + } - echo html_writer::table($attempt_table); + // Create writer and output the file + $writer = new Xlsx($spreadsheet); + $filename = 'user_grades_' . $user->id . '.xlsx'; - $total_grade = $DB->get_record('quiz_grades', array('quiz' => $quiz->id, 'userid' => $user->id)); + // Redirect output to a client’s web browser (Excel2007) + header('Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'); + header('Content-Disposition: attachment;filename="' . $filename . '"'); + header('Cache-Control: max-age=0'); - echo $OUTPUT->heading(get_string('totalgrade', 'report_usergrades') . ': ' . $total_grade->grade . ' / ' . $quiz->grade, 6); + $writer->save('php://output'); + exit(); + } else { + // HTML output if not exporting + echo $OUTPUT->header(); + echo $OUTPUT->heading(get_string('usergradesreport', 'report_usergrades')); + + echo $OUTPUT->heading(get_string('userdetails', 'report_usergrades'), 3); + + $user_table = new html_table(); + $user_table->head = array(get_string('field', 'report_usergrades'), get_string('value', 'report_usergrades')); + $user_table->data[] = array(get_string('username', 'report_usergrades'), $user->username); + $user_table->data[] = array(get_string('firstname', 'report_usergrades'), $user->firstname); + $user_table->data[] = array(get_string('lastname', 'report_usergrades'), $user->lastname); + $user_table->data[] = array(get_string('email', 'report_usergrades'), $user->email); + + echo html_writer::table($user_table); + + foreach ($courses as $course) { + echo $OUTPUT->heading($course->fullname, 3); + + $quizzes = $DB->get_records('quiz', array('course' => $course->id)); + + if ($quizzes) { + echo $OUTPUT->heading(get_string('quizzes', 'report_usergrades'), 4); + + foreach ($quizzes as $quiz) { + $quiz_questions = $DB->get_records('quiz_slots', array('quizid' => $quiz->id)); + $quiz_attempts = $DB->get_records('quiz_attempts', array('quiz' => $quiz->id, 'userid' => $user->id)); + + if ($quiz_attempts) { + echo $OUTPUT->heading($quiz->name, 5); + + foreach ($quiz_attempts as $attempt) { + echo $OUTPUT->heading(get_string('attempt', 'report_usergrades') . ' ' . $attempt->attempt, 6); + + $attempt_table = new html_table(); + $attempt_table->head = array(get_string('question', 'report_usergrades'), get_string('response', 'report_usergrades'), get_string('grade', 'report_usergrades')); + + $question_usages = $DB->get_records('question_usages', array('id' => $attempt->uniqueid)); + + foreach ($question_usages as $question_usage) { + $question_attempts = $DB->get_records('question_attempts', array('questionusageid' => $question_usage->id)); + + foreach ($question_attempts as $question_attempt) { + $question = $questions[$question_attempt->questionid]; + $response = $question_attempt->responsesummary; + + $question_grades = $DB->get_records('question_attempt_steps', array('questionattemptid' => $question_attempt->id)); + + foreach ($question_grades as $question_grade) { + if ($question_grade->fraction) { + $attempt_table->data[] = array($question->name . ': ' . $question->questiontext, $response, $question_grade->fraction); + } + } + } + } + + echo html_writer::table($attempt_table); + + $total_grade = $DB->get_record('quiz_grades', array('quiz' => $quiz->id, 'userid' => $user->id)); + + echo $OUTPUT->heading(get_string('totalgrade', 'report_usergrades') . ': ' . $total_grade->grade . ' / ' . $quiz->grade, 6); + } } } } } + echo $OUTPUT->footer(); } } else { echo $OUTPUT->notification(get_string('nouserselected', 'report_usergrades'), 'notifyproblem'); } } else { - // Display form if no data is submitted + // Show the form + echo $OUTPUT->header(); $mform->display(); + echo $OUTPUT->footer(); } - -echo $OUTPUT->footer(); diff --git a/lang/en/report_usergrades.php b/lang/en/report_usergrades.php index 986896b..d65cdc8 100644 --- a/lang/en/report_usergrades.php +++ b/lang/en/report_usergrades.php @@ -18,4 +18,7 @@ $string['firstname'] = 'First Name'; $string['lastname'] = 'Last Name'; $string['email'] = 'Email'; $string['field'] = 'Field'; -$string['value'] = 'Value'; \ No newline at end of file +$string['value'] = 'Value'; +$string['exportxls'] = 'Export to XLSX'; +$string['course'] = 'Course'; +$string['quiz'] = 'Quiz'; \ No newline at end of file diff --git a/version.php b/version.php index ff6d82a..edb8b63 100644 --- a/version.php +++ b/version.php @@ -2,7 +2,7 @@ defined('MOODLE_INTERNAL') || die(); $plugin->component = 'report_usergrades'; -$plugin->version = 2024112101; +$plugin->version = 2024112500; $plugin->requires = 2022041900; $plugin->maturity = MATURITY_ALPHA; $plugin->release = 'v1.0';