Differences Between: [Versions 310 and 400] [Versions 310 and 401] [Versions 310 and 402] [Versions 310 and 403] [Versions 39 and 310]
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::div(html_writer::table($table), 'table-responsive'); 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->attributes['class'] = 'standardtable generaltable'; 231 $stattable->data[] = array($data->avescore, $data->avetime, $data->highscore, $data->lowscore, $data->hightime, $data->lowtime); 232 233 } else { 234 // Display simple stats for the lesson. 235 echo $OUTPUT->heading(get_string('lessonstats', 'lesson'), 3); 236 $stattable = new html_table(); 237 $stattable->head = array(get_string('averagetime', 'lesson'), get_string('hightime', 'lesson'), 238 get_string('lowtime', 'lesson')); 239 $stattable->align = array('center', 'center', 'center'); 240 $stattable->attributes['class'] = 'standardtable generaltable'; 241 $stattable->data[] = array($data->avetime, $data->hightime, $data->lowtime); 242 } 243 244 echo html_writer::table($stattable); 245 } else if ($action === 'reportdetail') { 246 /************************************************************************** 247 this action is for a student detailed view and for the general detailed view 248 249 General flow of this section of the code 250 1. Generate a object which holds values for the statistics for each question/answer 251 2. Cycle through all the pages to create a object. Foreach page, see if the student actually answered 252 the page. Then process the page appropriatly. Display all info about the question, 253 Highlight correct answers, show how the user answered the question, and display statistics 254 about each page 255 3. Print out info about the try (if needed) 256 4. Print out the object which contains all the try info 257 258 **************************************************************************/ 259 echo $lessonoutput->header($lesson, $cm, $action, false, null, get_string('detailedstats', 'lesson')); 260 groups_print_activity_menu($cm, $url); 261 262 $course_context = context_course::instance($course->id); 263 if (has_capability('gradereport/grader:view', $course_context) && has_capability('moodle/grade:viewall', $course_context)) { 264 $seeallgradeslink = new moodle_url('/grade/report/grader/index.php', array('id'=>$course->id)); 265 $seeallgradeslink = html_writer::link($seeallgradeslink, get_string('seeallcoursegrades', 'grades')); 266 echo $OUTPUT->box($seeallgradeslink, 'allcoursegrades'); 267 } 268 269 $formattextdefoptions = new stdClass; 270 $formattextdefoptions->para = false; //I'll use it widely in this page 271 $formattextdefoptions->overflowdiv = true; 272 273 $userid = optional_param('userid', null, PARAM_INT); // if empty, then will display the general detailed view 274 $try = optional_param('try', null, PARAM_INT); 275 276 list($answerpages, $userstats) = lesson_get_user_detailed_report_data($lesson, $userid, $try); 277 278 /// actually start printing something 279 $table = new html_table(); 280 $table->wrap = array(); 281 $table->width = "60%"; 282 if (!empty($userid)) { 283 // if looking at a students try, print out some basic stats at the top 284 285 // print out users name 286 //$headingobject->lastname = $students[$userid]->lastname; 287 //$headingobject->firstname = $students[$userid]->firstname; 288 //$headingobject->attempt = $try + 1; 289 //print_heading(get_string("studentattemptlesson", "lesson", $headingobject)); 290 echo $OUTPUT->heading(get_string('attempt', 'lesson', $try+1), 3); 291 292 $table->head = array(); 293 $table->align = array('right', 'left'); 294 $table->attributes['class'] = 'table table-striped'; 295 296 if (empty($userstats->gradeinfo)) { 297 $table->align = array("center"); 298 299 $table->data[] = array(get_string("notcompleted", "lesson")); 300 } else { 301 $user = $DB->get_record('user', array('id' => $userid)); 302 303 $gradeinfo = lesson_grade($lesson, $try, $user->id); 304 305 $table->data[] = array(get_string('name').':', $OUTPUT->user_picture($user, array('courseid'=>$course->id)).fullname($user, true)); 306 $table->data[] = array(get_string("timetaken", "lesson").":", format_time($userstats->timetotake)); 307 $table->data[] = array(get_string("completed", "lesson").":", userdate($userstats->completed)); 308 $table->data[] = array(get_string('rawgrade', 'lesson').':', $userstats->gradeinfo->earned.'/'.$userstats->gradeinfo->total); 309 $table->data[] = array(get_string("grade", "lesson").":", $userstats->grade."%"); 310 } 311 echo html_writer::table($table); 312 313 // Don't want this class for later tables 314 $table->attributes['class'] = ''; 315 } 316 317 foreach ($answerpages as $page) { 318 $table->align = array('left', 'left'); 319 $table->size = array('70%', null); 320 $table->attributes['class'] = 'table table-striped'; 321 unset($table->data); 322 if ($page->grayout) { // set the color of text 323 $fontstart = html_writer::start_tag('span', array('class' => 'dimmed_text')); 324 $fontend = html_writer::end_tag('span'); 325 $fontstart2 = $fontstart; 326 $fontend2 = $fontend; 327 } else { 328 $fontstart = ''; 329 $fontend = ''; 330 $fontstart2 = ''; 331 $fontend2 = ''; 332 } 333 334 $table->head = array($fontstart2.$page->qtype.": ".format_string($page->title).$fontend2, $fontstart2.get_string("classstats", "lesson").$fontend2); 335 $table->data[] = array($fontstart.get_string("question", "lesson").": <br />".$fontend.$fontstart2.$page->contents.$fontend2, " "); 336 $table->data[] = array($fontstart.get_string("answer", "lesson").":".$fontend, ' '); 337 // apply the font to each answer 338 if (!empty($page->answerdata) && !empty($page->answerdata->answers)) { 339 foreach ($page->answerdata->answers as $answer){ 340 $modified = array(); 341 foreach ($answer as $single) { 342 // need to apply a font to each one 343 $modified[] = $fontstart2.$single.$fontend2; 344 } 345 $table->data[] = $modified; 346 } 347 if (isset($page->answerdata->response)) { 348 $table->data[] = array($fontstart.get_string("response", "lesson").": <br />".$fontend 349 .$fontstart2.$page->answerdata->response.$fontend2, " "); 350 } 351 $table->data[] = array($page->answerdata->score, " "); 352 } else { 353 $table->data[] = array(get_string('didnotanswerquestion', 'lesson'), " "); 354 } 355 echo html_writer::start_tag('div', ['class' => 'no-overflow table-responsive']); 356 echo html_writer::table($table); 357 echo html_writer::end_tag('div'); 358 } 359 } else { 360 print_error('unknowaction'); 361 } 362 363 /// Finish the page 364 echo $OUTPUT->footer();
title
Description
Body
title
Description
Body
title
Description
Body
title
Body