See Release Notes
Long Term Support Release
Differences Between: [Versions 39 and 310] [Versions 39 and 311] [Versions 39 and 400] [Versions 39 and 401] [Versions 39 and 402] [Versions 39 and 403]
1 <?php 2 3 // This file is part of Moodle - http://moodle.org/ 4 // 5 // Moodle is free software: you can redistribute it and/or modify 6 // it under the terms of the GNU General Public License as published by 7 // the Free Software Foundation, either version 3 of the License, or 8 // (at your option) any later version. 9 // 10 // Moodle is distributed in the hope that it will be useful, 11 // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 // GNU General Public License for more details. 14 // 15 // You should have received a copy of the GNU General Public License 16 // along with Moodle. If not, see <http://www.gnu.org/licenses/>. 17 18 /** 19 * Displays the lesson statistics. 20 * 21 * @package mod_lesson 22 * @copyright 1999 onwards Martin Dougiamas {@link http://moodle.com} 23 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or late 24 **/ 25 26 require_once('../../config.php'); 27 require_once($CFG->dirroot.'/mod/lesson/locallib.php'); 28 29 $id = required_param('id', PARAM_INT); // Course Module ID 30 $pageid = optional_param('pageid', null, PARAM_INT); // Lesson Page ID 31 $action = optional_param('action', 'reportoverview', PARAM_ALPHA); // action to take 32 $nothingtodisplay = false; 33 34 $cm = get_coursemodule_from_id('lesson', $id, 0, false, MUST_EXIST); 35 $course = $DB->get_record('course', array('id' => $cm->course), '*', MUST_EXIST); 36 $lesson = new lesson($DB->get_record('lesson', array('id' => $cm->instance), '*', MUST_EXIST)); 37 38 require_login($course, false, $cm); 39 40 $currentgroup = groups_get_activity_group($cm, true); 41 42 $context = context_module::instance($cm->id); 43 require_capability('mod/lesson:viewreports', $context); 44 45 $url = new moodle_url('/mod/lesson/report.php', array('id'=>$id)); 46 $url->param('action', $action); 47 if ($pageid !== null) { 48 $url->param('pageid', $pageid); 49 } 50 $PAGE->set_url($url); 51 if ($action == 'reportoverview') { 52 $PAGE->navbar->add(get_string('reports', 'lesson')); 53 $PAGE->navbar->add(get_string('overview', 'lesson')); 54 } 55 56 $lessonoutput = $PAGE->get_renderer('mod_lesson'); 57 58 if ($action === 'delete') { 59 /// Process any form data before fetching attempts, grades and times 60 if (has_capability('mod/lesson:edit', $context) and $form = data_submitted() and confirm_sesskey()) { 61 /// Cycle through array of userids with nested arrays of tries 62 if (!empty($form->attempts)) { 63 foreach ($form->attempts as $userid => $tries) { 64 // Modifier IS VERY IMPORTANT! What does it do? 65 // Well, it is for when you delete multiple attempts for the same user. 66 // If you delete try 1 and 3 for a user, then after deleting try 1, try 3 then 67 // becomes try 2 (because try 1 is gone and all tries after try 1 get decremented). 68 // So, the modifier makes sure that the submitted try refers to the current try in the 69 // database - hope this all makes sense :) 70 $modifier = 0; 71 72 foreach ($tries as $try => $junk) { 73 $try -= $modifier; 74 75 /// Clean up the timer table by removing using the order - this is silly, it should be linked to specific attempt (skodak) 76 $timers = $lesson->get_user_timers($userid, 'starttime', 'id', $try, 1); 77 if ($timers) { 78 $timer = reset($timers); 79 $DB->delete_records('lesson_timer', array('id' => $timer->id)); 80 } 81 82 $params = array ("userid" => $userid, "lessonid" => $lesson->id); 83 // Remove the grade from the grades tables - this is silly, it should be linked to specific attempt (skodak). 84 $grades = $DB->get_records_sql("SELECT id FROM {lesson_grades} 85 WHERE userid = :userid AND lessonid = :lessonid 86 ORDER BY completed", $params, $try, 1); 87 88 if ($grades) { 89 $grade = reset($grades); 90 $DB->delete_records('lesson_grades', array('id' => $grade->id)); 91 } 92 93 /// Remove attempts and update the retry number 94 $DB->delete_records('lesson_attempts', array('userid' => $userid, 'lessonid' => $lesson->id, 'retry' => $try)); 95 $DB->execute("UPDATE {lesson_attempts} SET retry = retry - 1 WHERE userid = ? AND lessonid = ? AND retry > ?", array($userid, $lesson->id, $try)); 96 97 /// Remove seen branches and update the retry number 98 $DB->delete_records('lesson_branch', array('userid' => $userid, 'lessonid' => $lesson->id, 'retry' => $try)); 99 $DB->execute("UPDATE {lesson_branch} SET retry = retry - 1 WHERE userid = ? AND lessonid = ? AND retry > ?", array($userid, $lesson->id, $try)); 100 101 /// update central gradebook 102 lesson_update_grades($lesson, $userid); 103 104 $modifier++; 105 } 106 } 107 } 108 } 109 redirect(new moodle_url($PAGE->url, array('action'=>'reportoverview'))); 110 111 } else if ($action === 'reportoverview') { 112 /************************************************************************** 113 this action is for default view and overview view 114 **************************************************************************/ 115 116 // Get the table and data for build statistics. 117 list($table, $data) = lesson_get_overview_report_table_and_data($lesson, $currentgroup); 118 119 if ($table === false) { 120 echo $lessonoutput->header($lesson, $cm, $action, false, null, get_string('nolessonattempts', 'lesson')); 121 if (!empty($currentgroup)) { 122 $groupname = groups_get_group_name($currentgroup); 123 echo $OUTPUT->notification(get_string('nolessonattemptsgroup', 'lesson', $groupname)); 124 } else { 125 echo $OUTPUT->notification(get_string('nolessonattempts', 'lesson')); 126 } 127 groups_print_activity_menu($cm, $url); 128 echo $OUTPUT->footer(); 129 exit(); 130 } 131 132 echo $lessonoutput->header($lesson, $cm, $action, false, null, get_string('overview', 'lesson')); 133 groups_print_activity_menu($cm, $url); 134 135 $course_context = context_course::instance($course->id); 136 if (has_capability('gradereport/grader:view', $course_context) && has_capability('moodle/grade:viewall', $course_context)) { 137 $seeallgradeslink = new moodle_url('/grade/report/grader/index.php', array('id'=>$course->id)); 138 $seeallgradeslink = html_writer::link($seeallgradeslink, get_string('seeallcoursegrades', 'grades')); 139 echo $OUTPUT->box($seeallgradeslink, 'allcoursegrades'); 140 } 141 142 // The attempts table. 143 $attemptstable = html_writer::table($table); 144 145 // The HTML that we will be displaying which includes the attempts table and bulk actions menu, if necessary. 146 $attemptshtml = $attemptstable; 147 148 // Show bulk actions when user has capability to edit the lesson. 149 if (has_capability('mod/lesson:edit', $context)) { 150 $reporturl = new moodle_url('/mod/lesson/report.php'); 151 $formid = 'mod-lesson-report-form'; 152 153 // Sesskey hidden input. 154 $formcontents = html_writer::empty_tag('input', ['type' => 'hidden', 'name' => 'sesskey', 'value' => sesskey()]); 155 156 // CMID hidden input. 157 $formcontents .= html_writer::empty_tag('input', ['type' => 'hidden', 'name' => 'id', 'value' => $cm->id]); 158 159 // Attempts table. 160 $formcontents .= $attemptstable; 161 162 // Bulk actions menu. 163 $attemptsactions = [ 164 'delete' => get_string('deleteselected') 165 ]; 166 $bulkactions = new single_select($reporturl, 'action', $attemptsactions, '', ['' => 'choosedots'], $formid); 167 $bulkactions->set_label(get_string('withselectedattempts', 'lesson')); 168 $bulkactions->disabled = true; 169 $bulkactions->attributes = [ 170 'data-action' => 'toggle', 171 'data-togglegroup' => 'lesson-attempts', 172 'data-toggle' => 'action', 173 ]; 174 $bulkactionshtml = $OUTPUT->render($bulkactions); 175 $formcontents .= $OUTPUT->box($bulkactionshtml, 'center'); 176 177 // Build the attempts form. 178 $formattributes = [ 179 'id' => $formid, 180 'method' => 'post', 181 ]; 182 $attemptshtml = html_writer::tag('form', $formcontents, $formattributes); 183 } 184 185 // Show the attempts HTML. 186 echo $attemptshtml; 187 188 // Calculate the Statistics. 189 if ($data->avetime == null) { 190 $data->avetime = get_string("notcompleted", "lesson"); 191 } else { 192 $data->avetime = format_float($data->avetime / $data->numofattempts, 0); 193 $data->avetime = format_time($data->avetime); 194 } 195 if ($data->hightime == null) { 196 $data->hightime = get_string("notcompleted", "lesson"); 197 } else { 198 $data->hightime = format_time($data->hightime); 199 } 200 if ($data->lowtime == null) { 201 $data->lowtime = get_string("notcompleted", "lesson"); 202 } else { 203 $data->lowtime = format_time($data->lowtime); 204 } 205 206 if ($data->lessonscored) { 207 if ($data->numofattempts == 0) { 208 $data->avescore = get_string("notcompleted", "lesson"); 209 } else { 210 $data->avescore = format_float($data->avescore, 2) . '%'; 211 } 212 if ($data->highscore === null) { 213 $data->highscore = get_string("notcompleted", "lesson"); 214 } else { 215 $data->highscore .= '%'; 216 } 217 if ($data->lowscore === null) { 218 $data->lowscore = get_string("notcompleted", "lesson"); 219 } else { 220 $data->lowscore .= '%'; 221 } 222 223 // Display the full stats for the lesson. 224 echo $OUTPUT->heading(get_string('lessonstats', 'lesson'), 3); 225 $stattable = new html_table(); 226 $stattable->head = array(get_string('averagescore', 'lesson'), get_string('averagetime', 'lesson'), 227 get_string('highscore', 'lesson'), get_string('lowscore', 'lesson'), 228 get_string('hightime', 'lesson'), get_string('lowtime', 'lesson')); 229 $stattable->align = array('center', 'center', 'center', 'center', 'center', 'center'); 230 $stattable->wrap = array('nowrap', 'nowrap', 'nowrap', 'nowrap', 'nowrap', 'nowrap'); 231 $stattable->attributes['class'] = 'standardtable generaltable'; 232 $stattable->data[] = array($data->avescore, $data->avetime, $data->highscore, $data->lowscore, $data->hightime, $data->lowtime); 233 234 } else { 235 // Display simple stats for the lesson. 236 echo $OUTPUT->heading(get_string('lessonstats', 'lesson'), 3); 237 $stattable = new html_table(); 238 $stattable->head = array(get_string('averagetime', 'lesson'), get_string('hightime', 'lesson'), 239 get_string('lowtime', 'lesson')); 240 $stattable->align = array('center', 'center', 'center'); 241 $stattable->wrap = array('nowrap', 'nowrap', 'nowrap'); 242 $stattable->attributes['class'] = 'standardtable generaltable'; 243 $stattable->data[] = array($data->avetime, $data->hightime, $data->lowtime); 244 } 245 246 echo html_writer::table($stattable); 247 } else if ($action === 'reportdetail') { 248 /************************************************************************** 249 this action is for a student detailed view and for the general detailed view 250 251 General flow of this section of the code 252 1. Generate a object which holds values for the statistics for each question/answer 253 2. Cycle through all the pages to create a object. Foreach page, see if the student actually answered 254 the page. Then process the page appropriatly. Display all info about the question, 255 Highlight correct answers, show how the user answered the question, and display statistics 256 about each page 257 3. Print out info about the try (if needed) 258 4. Print out the object which contains all the try info 259 260 **************************************************************************/ 261 echo $lessonoutput->header($lesson, $cm, $action, false, null, get_string('detailedstats', 'lesson')); 262 groups_print_activity_menu($cm, $url); 263 264 $course_context = context_course::instance($course->id); 265 if (has_capability('gradereport/grader:view', $course_context) && has_capability('moodle/grade:viewall', $course_context)) { 266 $seeallgradeslink = new moodle_url('/grade/report/grader/index.php', array('id'=>$course->id)); 267 $seeallgradeslink = html_writer::link($seeallgradeslink, get_string('seeallcoursegrades', 'grades')); 268 echo $OUTPUT->box($seeallgradeslink, 'allcoursegrades'); 269 } 270 271 $formattextdefoptions = new stdClass; 272 $formattextdefoptions->para = false; //I'll use it widely in this page 273 $formattextdefoptions->overflowdiv = true; 274 275 $userid = optional_param('userid', null, PARAM_INT); // if empty, then will display the general detailed view 276 $try = optional_param('try', null, PARAM_INT); 277 278 list($answerpages, $userstats) = lesson_get_user_detailed_report_data($lesson, $userid, $try); 279 280 /// actually start printing something 281 $table = new html_table(); 282 $table->wrap = array(); 283 $table->width = "60%"; 284 if (!empty($userid)) { 285 // if looking at a students try, print out some basic stats at the top 286 287 // print out users name 288 //$headingobject->lastname = $students[$userid]->lastname; 289 //$headingobject->firstname = $students[$userid]->firstname; 290 //$headingobject->attempt = $try + 1; 291 //print_heading(get_string("studentattemptlesson", "lesson", $headingobject)); 292 echo $OUTPUT->heading(get_string('attempt', 'lesson', $try+1), 3); 293 294 $table->head = array(); 295 $table->align = array('right', 'left'); 296 $table->attributes['class'] = 'generaltable'; 297 298 if (empty($userstats->gradeinfo)) { 299 $table->align = array("center"); 300 301 $table->data[] = array(get_string("notcompleted", "lesson")); 302 } else { 303 $user = $DB->get_record('user', array('id' => $userid)); 304 305 $gradeinfo = lesson_grade($lesson, $try, $user->id); 306 307 $table->data[] = array(get_string('name').':', $OUTPUT->user_picture($user, array('courseid'=>$course->id)).fullname($user, true)); 308 $table->data[] = array(get_string("timetaken", "lesson").":", format_time($userstats->timetotake)); 309 $table->data[] = array(get_string("completed", "lesson").":", userdate($userstats->completed)); 310 $table->data[] = array(get_string('rawgrade', 'lesson').':', $userstats->gradeinfo->earned.'/'.$userstats->gradeinfo->total); 311 $table->data[] = array(get_string("grade", "lesson").":", $userstats->grade."%"); 312 } 313 echo html_writer::table($table); 314 315 // Don't want this class for later tables 316 $table->attributes['class'] = ''; 317 } 318 319 foreach ($answerpages as $page) { 320 $table->align = array('left', 'left'); 321 $table->size = array('70%', null); 322 $table->attributes['class'] = 'generaltable'; 323 unset($table->data); 324 if ($page->grayout) { // set the color of text 325 $fontstart = html_writer::start_tag('span', array('class' => 'dimmed_text')); 326 $fontend = html_writer::end_tag('span'); 327 $fontstart2 = $fontstart; 328 $fontend2 = $fontend; 329 } else { 330 $fontstart = ''; 331 $fontend = ''; 332 $fontstart2 = ''; 333 $fontend2 = ''; 334 } 335 336 $table->head = array($fontstart2.$page->qtype.": ".format_string($page->title).$fontend2, $fontstart2.get_string("classstats", "lesson").$fontend2); 337 $table->data[] = array($fontstart.get_string("question", "lesson").": <br />".$fontend.$fontstart2.$page->contents.$fontend2, " "); 338 $table->data[] = array($fontstart.get_string("answer", "lesson").":".$fontend, ' '); 339 // apply the font to each answer 340 if (!empty($page->answerdata) && !empty($page->answerdata->answers)) { 341 foreach ($page->answerdata->answers as $answer){ 342 $modified = array(); 343 foreach ($answer as $single) { 344 // need to apply a font to each one 345 $modified[] = $fontstart2.$single.$fontend2; 346 } 347 $table->data[] = $modified; 348 } 349 if (isset($page->answerdata->response)) { 350 $table->data[] = array($fontstart.get_string("response", "lesson").": <br />".$fontend 351 .$fontstart2.$page->answerdata->response.$fontend2, " "); 352 } 353 $table->data[] = array($page->answerdata->score, " "); 354 } else { 355 $table->data[] = array(get_string('didnotanswerquestion', 'lesson'), " "); 356 } 357 echo html_writer::start_tag('div', array('class' => 'no-overflow')); 358 echo html_writer::table($table); 359 echo html_writer::end_tag('div'); 360 } 361 } else { 362 print_error('unknowaction'); 363 } 364 365 /// Finish the page 366 echo $OUTPUT->footer();
title
Description
Body
title
Description
Body
title
Description
Body
title
Body