3 // This script uses installed report plugins to print quiz reports
5 require_once("../../config.php");
6 require_once("lib.php");
8 $id = optional_param('id', 0, PARAM_INT
); // Course Module ID, or
9 $hp = optional_param('hp', 0, PARAM_INT
); // hotpot ID
12 if (! $cm = get_coursemodule_from_id('hotpot', $id)) {
13 error("Course Module ID was incorrect");
15 if (! $course = get_record("course", "id", $cm->course
)) {
16 error("Course is misconfigured");
18 if (! $hotpot = get_record("hotpot", "id", $cm->instance
)) {
19 error("Course module is incorrect");
23 if (! $hotpot = get_record("hotpot", "id", $hp)) {
24 error("Course module is incorrect");
26 if (! $course = get_record("course", "id", $hotpot->course
)) {
27 error("Course is misconfigured");
29 if (! $cm = get_coursemodule_from_instance("hotpot", $hotpot->id
, $course->id
)) {
30 error("Course Module ID was incorrect");
34 // get the roles context for this course
35 $sitecontext = get_context_instance(CONTEXT_SYSTEM
, SITEID
);
36 $modulecontext = get_context_instance(CONTEXT_MODULE
, $cm->id
);
38 // set homeurl of couse (for error messages)
39 $course_homeurl = "$CFG->wwwroot/course/view.php?id=$course->id";
41 require_login($course->id
);
44 if (has_capability('mod/hotpot:viewreport',$modulecontext)) {
45 $mode = optional_param('mode', 'overview', PARAM_ALPHA
);
47 // ordinary students have no choice
51 // assemble array of form data
54 'reportusers' => has_capability('mod/hotpot:viewreport',$modulecontext) ?
optional_param('reportusers', get_user_preferences('hotpot_reportusers', 'allusers'), PARAM_ALPHA
) : 'this',
55 'reportattempts' => optional_param('reportattempts', get_user_preferences('hotpot_reportattempts', 'all'), PARAM_ALPHA
),
56 'reportformat' => optional_param('reportformat', 'htm', PARAM_ALPHA
),
57 'reportshowlegend' => optional_param('reportshowlegend', get_user_preferences('hotpot_reportshowlegend', '0'), PARAM_INT
),
58 'reportencoding' => optional_param('reportencoding', get_user_preferences('hotpot_reportencoding', ''), PARAM_ALPHANUM
),
59 'reportwrapdata' => optional_param('reportwrapdata', get_user_preferences('hotpot_reportwrapdata', '1'), PARAM_INT
),
62 foreach ($formdata as $name=>$value) {
63 set_user_preference("hotpot_$name", $value);
68 add_to_log($course->id
, "hotpot", "report", "report.php?id=$cm->id&mode=$mode", "$hotpot->id", "$cm->id");
70 // print page header. if required
71 if ($formdata['reportformat']=='htm') {
72 hotpot_print_report_heading($course, $cm, $hotpot, $mode);
73 if (has_capability('mod/hotpot:viewreport',$modulecontext)) {
74 hotpot_print_report_selector($course, $hotpot, $formdata);
78 // delete selected attempts, if any
79 if (has_capability('mod/hotpot:deleteattempt',$modulecontext)) {
80 $del = optional_param('del', '', PARAM_ALPHA
);
81 hotpot_delete_selected_attempts($hotpot, $del);
85 if (preg_match('/^group(\d*)$/', $formdata['reportusers'], $matches)) {
86 $formdata['reportusers'] = 'group';
87 $formdata['reportgroupid'] = 0;
89 if ($groups = groups_get_groups_names($course->id
)) {
90 if (isset($groups[$matches[1]])) {
91 $formdata['reportgroupid'] = $matches[1];
99 switch ($formdata['reportusers']) {
102 // anyone who has ever attempted this hotpot
103 if ($records = get_records_select('hotpot_attempts', "hotpot=$hotpot->id", '', 'id,userid')) {
104 foreach ($records as $record) {
105 $users[$record->userid
] = 0; // "0" means user is NOT currently allowed to attempt this HotPot
113 if ($memberids = groups_get_members($formdata['reportgroupid'])) { //TODO:check.
114 foreach ($memberids as $memberid) {
115 $users[$memberid] = 1; // "1" signifies currently recognized participant
120 case 'allparticipants':
121 // anyone currently allowed to attempt this HotPot
122 if ($records = get_users_by_capability($modulecontext, 'mod/hotpot:attempt', 'u.id,u.id', 'u.id')) {
123 foreach ($records as $record) {
124 $users[$record->id
] = 1; // "1" means user is allowed to do this HotPot
130 case 'existingstudents':
131 // anyone currently allowed to attempt this HotPot who is not a teacher
132 $teachers = get_users_by_capability($modulecontext, 'mod/hotpot:viewreport', 'u.id,u.id', 'u.id');
133 if ($records = get_users_by_capability($modulecontext, 'mod/hotpot:attempt', 'u.id,u.id', 'u.id')) {
134 foreach ($records as $record) {
135 if (empty($teachers[$record->id
])) {
136 $users[$record->id
] = 1;
142 case 'this': // current user only
143 $user_ids = $USER->id
;
146 default: // specific user selected by teacher
147 if (is_numeric($formdata['reportusers'])) {
148 $user_ids = $formdata['reportusers'];
151 if (empty($user_ids) && count($users)) {
153 $user_ids = join(',', array_keys($users));
155 if (empty($user_ids)) {
156 print_heading(get_string('nousersyet'));
160 // database table and selection conditions
161 $table = "{$CFG->prefix}hotpot_attempts a";
162 $select = "a.hotpot=$hotpot->id AND a.userid IN ($user_ids)";
163 if ($mode!='overview') {
164 $select .= ' AND a.status<>'.HOTPOT_STATUS_INPROGRESS
;
167 // confine attempts if necessary
168 switch ($formdata['reportattempts']) {
171 $fieldnames = array('score', 'id', 'clickreportid');
176 $fieldnames = array('timefinish', 'id', 'clickreportid');
177 $default_value = time();
181 $fieldnames = array('timefinish', 'id', 'clickreportid');
182 $defaultvalue = time();
184 default: // 'all' and any others
186 $fieldnames = array();
190 if (empty($function) ||
empty($fieldnames)) {
191 // do nothing (i.e. get ALL attempts)
194 $records = hotpot_get_records_groupby($function, $fieldnames, $table, $select, $groupby);
197 foreach ($records as $record) {
198 $ids[] = $record->clickreportid
;
200 $select = "a.clickreportid IN (".join(',', $ids).")";
203 // pick out last attempt in each clickreport series
204 $cr_attempts = hotpot_get_records_groupby('MAX', array('timefinish', 'id'), $table, $select, 'clickreportid');
206 $fields = 'a.*, u.firstname, u.lastname, u.picture';
207 if ($mode=='click') {
208 $fields .= ', u.idnumber';
210 // overview, simple and detailed reports
211 // get last attempt record in clickreport series
213 foreach ($cr_attempts as $cr_attempt) {
214 $ids[] = $cr_attempt->id
;
219 $ids = array_unique($ids);
221 $select = "a.id IN (".join(',', $ids).")";
228 // add user information to SQL query
229 $select .= ' AND a.userid = u.id';
230 $table .= ", {$CFG->prefix}user u";
231 $order = "u.lastname, a.attempt, a.timefinish";
232 // get the attempts (at last!)
233 $attempts = get_records_sql("SELECT $fields FROM $table WHERE $select ORDER BY $order");
236 // stop now if no attempts were found
237 if (empty($attempts)) {
238 print_heading(get_string('noattemptstoshow','quiz'));
243 if (!$questions = get_records_select('hotpot_questions', "hotpot='$hotpot->id'")) {
244 $questions = array();
248 $grades = hotpot_get_grades($hotpot, $user_ids);
250 // get list of attempts by user and set reference to last attempt in clickreport series
252 foreach ($attempts as $id=>$attempt) {
254 $userid = $attempt->userid
;
256 if (!isset($users[$userid])) {
257 $users[$userid]->grade
= isset($grades[$userid]) ?
$grades[$userid] : ' ';
258 $users[$userid]->attempts
= array();
261 $users[$userid]->attempts
[] = &$attempts[$id];
263 if ($mode=='click') {
264 // shortcut to clickreportid (=the id of the FIRST attempt in this clickreport series)
265 $clickreportid = $attempt->clickreportid
;
266 if (isset($cr_attempts[$clickreportid])) {
267 // store id and finish time of LAST attempt in this clickreport series
268 $attempts[$id]->cr_lastclick
= $cr_attempts[$clickreportid]->id
;
269 $attempts[$id]->cr_timefinish
= $cr_attempts[$clickreportid]->timefinish
;
274 if ($mode!='overview') {
276 // initialise details of responses to questions in these attempts
277 foreach ($attempts as $a=>$attempt) {
278 $attempts[$a]->responses
= array();
280 foreach ($questions as $q=>$question) {
281 $questions[$q]->attempts
= array();
284 // get reponses to these attempts
285 $attempt_ids = join(',',array_keys($attempts));
286 if (!$responses = get_records_sql("SELECT * FROM {$CFG->prefix}hotpot_responses WHERE attempt IN ($attempt_ids)")) {
287 $responses = array();
290 // ids of questions used in these responses
291 $questionids = array();
293 foreach ($responses as $response) {
294 // shortcuts to the attempt and question ids
295 $a = $response->attempt
;
296 $q = $response->question
;
298 // check the attempt and question objects exist
299 // (if they don't exist, something is very wrong!)
300 if (isset($attempts[$a]) ||
isset($questions[$q])) {
302 // add the response for this attempt
303 $attempts[$a]->responses
[$q] = $response;
305 // add a reference from the question to the attempt which includes this question
306 $questions[$q]->attempts
[] = &$attempts[$a];
308 // flag this id as being used
309 $questionids[$q] = true;
313 // remove unused questions
314 $questionids = array_keys($questionids);
315 foreach ($questions as $id=>$question) {
316 if (!in_array($id, $questionids)) {
317 unset($questions[$id]);
322 /// Open the selected hotpot report and display it
324 if (! is_readable("report/$mode/report.php")) {
325 error("Report not known (".clean_text($mode).")", $course_homeurl);
328 include("report/default.php"); // Parent class
329 include("report/$mode/report.php");
331 $report = new hotpot_report();
333 if (! $report->display($hotpot, $cm, $course, $users, $attempts, $questions, $formdata)) {
334 error("Error occurred during report processing!", $course_homeurl);
337 if ($formdata['reportformat']=='htm') {
338 print_footer($course);
341 //////////////////////////////////////////////
342 /// functions to delete attempts and responses
344 function hotpot_grade_heading($hotpot, $formdata) {
346 global $HOTPOT_GRADEMETHOD;
347 $grademethod = $HOTPOT_GRADEMETHOD[$hotpot->grademethod
];
349 if ($hotpot->grade
!=100) {
350 $grademethod = "$hotpot->grade x $grademethod/100";
352 if ($formdata['reportformat']=='htm') {
353 $grademethod = '<font size="1">'.$grademethod.'</font>';
355 $nl = $formdata['reportformat']=='htm' ?
'<br />' : "\n";
356 return get_string('grade')."$nl($grademethod)";
358 function hotpot_delete_selected_attempts(&$hotpot, $del) {
363 $select = "hotpot='$hotpot->id'";
366 $select = "hotpot='$hotpot->id' AND status=".HOTPOT_STATUS_ABANDONED
;
369 $ids = (array)data_submitted();
373 $select = "hotpot='$hotpot->id' AND clickreportid IN (".implode(',', $ids).")";
378 // delete attempts using $select, if it is set
381 $table = 'hotpot_attempts';
382 if ($attempts = get_records_select($table, $select)) {
384 hotpot_delete_and_notify($table, $select, get_string('attempts', 'quiz'));
386 $select = 'attempt IN ('.implode(',', array_keys($attempts)).')';
387 hotpot_delete_and_notify('hotpot_details', $select, get_string('rawdetails', 'hotpot'));
388 hotpot_delete_and_notify('hotpot_responses', $select, get_string('answer', 'quiz'));
394 //////////////////////////////////////////////
395 /// functions to print the report headings and
396 /// report selector menus
398 function hotpot_print_report_heading(&$course, &$cm, &$hotpot, &$mode) {
399 $strmodulenameplural = get_string("modulenameplural", "hotpot");
400 $strmodulename = get_string("modulename", "hotpot");
402 $title = format_string($course->shortname
) . ": $hotpot->name";
403 $heading = $course->fullname
;
406 $navlinks[] = array('name' => $strmodulenameplural, 'link' => 'index.php?id='.$course->id
, 'type' => 'activity');
407 $navlinks[] = array('name' => $hotpot->name
, 'link' => "view.php?id=$cm->id", 'type' => 'activityinstance');
410 $modulecontext = get_context_instance(CONTEXT_MODULE
, $cm->id
);
411 if (has_capability('mod/hotpot:viewreport',$modulecontext)) {
412 if ($mode=='overview' ||
$mode=='simplestat' ||
$mode=='fullstat') {
418 $navlinks[] = array('name' => get_string("report$mode", $module), 'link' => '', 'type' => 'title');
423 $navlinks[] = array('name' => get_string("report", "quiz"), 'link' => '', 'type' => 'title');
426 $button = update_module_button($cm->id
, $course->id
, $strmodulename);
427 $navigation = build_navigation($navlinks);
428 print_header($title, $heading, $navigation, "", "", true, $button, navmenu($course, $cm));
430 print_heading($hotpot->name
);
432 function hotpot_print_report_selector(&$course, &$hotpot, &$formdata) {
436 $reports = hotpot_get_report_names('overview,simplestat,fullstat');
438 print '<form method="post" action="'."$CFG->wwwroot/mod/hotpot/report.php?hp=$hotpot->id".'">';
439 print '<table cellpadding="2" align="center">';
443 $menus['mode'] = array();
444 foreach ($reports as $name) {
445 if ($name=='overview' ||
$name=='simplestat' ||
$name=='fullstat') {
446 $module = "quiz"; // standard reports
447 } else if ($name=='click' && empty($hotpot->clickreporting
)) {
448 $module = ""; // clickreporting is disabled
450 $module = "hotpot"; // custom reports
453 $menus['mode'][$name] = get_string("report$name", $module);
457 $menus['reportusers'] = array(
458 'allusers' => get_string('allusers', 'hotpot'),
459 'allparticipants' => get_string('allparticipants')
463 if ($groups = groups_get_groups_names($course->id
)) { //TODO:check.
464 foreach ($groups as $gid => $gname) {
465 $menus['reportusers']["group$gid"] = get_string('group').': '.$gname;
469 // get users who have ever atetmpted this HotPot
470 $users = get_records_sql("
472 u.id, u.firstname, u.lastname
474 {$CFG->prefix}user u,
475 {$CFG->prefix}hotpot_attempts ha
477 u.id = ha.userid AND ha.hotpot=$hotpot->id
483 $cm = get_coursemodule_from_instance('hotpot', $hotpot->id
);
484 $modulecontext = get_context_instance(CONTEXT_MODULE
, $cm->id
);
486 // get teachers enrolled students
487 $teachers = get_users_by_capability($modulecontext, 'mod/hotpot:viewreport', 'u.id,u.firstname,u.lastname', 'u.lastname');
488 $students = get_users_by_capability($modulecontext, 'mod/hotpot:attempt', 'u.id,u.firstname,u.lastname', 'u.lastname');
491 if (!empty($students)) {
493 foreach ($students as $user) {
494 if (isset($users[$user->id
])) {
496 $firsttime = false; // so we only do this once
497 $menus['reportusers']['existingstudents'] = get_string('existingstudents');
498 $menus['reportusers'][] = '------';
500 $menus['reportusers']["$user->id"] = fullname($user);
501 unset($users[$user->id
]);
505 // others (former students, teachers, admins, course creators)
506 if (!empty($users)) {
508 foreach ($users as $user) {
510 $firsttime = false; // so we only do this once
511 $menus['reportusers'][] = '======';
513 $menus['reportusers']["$user->id"] = fullname($user);
517 $menus['reportattempts'] = array(
518 'all' => get_string('attemptsall', 'hotpot'),
519 'best' => get_string('attemptsbest', 'hotpot'),
520 'first' => get_string('attemptsfirst', 'hotpot'),
521 'last' => get_string('attemptslast', 'hotpot')
525 helpbutton('reportcontent', get_string('reportcontent', 'hotpot'), 'hotpot');
526 print '</td><th align="right" scope="col">'.get_string('reportcontent', 'hotpot').':</th><td colspan="7">';
527 foreach ($menus as $name => $options) {
528 $value = $formdata[$name];
529 print choose_from_menu($options, $name, $value, "", "", 0, true);
531 print '<input type="submit" value="'.get_string('reportbutton', 'hotpot').'" /></td></tr>';
535 $menus['reportformat'] = array();
536 $menus['reportformat']['htm'] = get_string('reportformathtml', 'hotpot');
537 if (file_exists("$CFG->libdir/excel") ||
file_exists("$CFG->libdir/excellib.class.php")) {
538 $menus['reportformat']['xls'] = get_string('reportformatexcel', 'hotpot');
540 $menus['reportformat']['txt'] = get_string('reportformattext', 'hotpot');
542 if (trim($CFG->hotpot_excelencodings
)) {
543 $menus['reportencoding'] = array(get_string('none')=>'');
545 $encodings = explode(',', $CFG->hotpot_excelencodings
);
546 foreach ($encodings as $encoding) {
548 $encoding = trim($encoding);
550 $menus['reportencoding'][$encoding] = $encoding;
554 $menus['reportwrapdata'] = array(
555 '1' => get_string('yes'),
556 '0' => get_string('no'),
558 $menus['reportshowlegend'] = array(
559 '1' => get_string('yes'),
560 '0' => get_string('no'),
564 helpbutton('reportformat', get_string('reportformat', 'hotpot'), 'hotpot');
566 foreach ($menus as $name => $options) {
567 $value = $formdata[$name];
568 print '<th align="right" scope="col">'.get_string($name, 'hotpot').':</th><td>'.choose_from_menu($options, $name, $value, "", "", 0, true).'</td>';
574 print '<hr size="1" noshade="noshade" />';
575 print '</form>'."\n";
577 function hotpot_get_report_names($names='') {
578 // $names : optional list showing required order reports names
582 // convert $names to an array, if necessary (usually is)
583 if (!is_array($names)) {
584 $names = explode(',', $names);
587 $plugins = get_list_of_plugins('mod/hotpot/report');
588 foreach($names as $name) {
589 if (is_numeric($i = array_search($name, $plugins))) {
595 // append remaining plugins
596 $reports = array_merge($reports, $plugins);
600 function hotpot_get_report_users($course, $formdata) {
603 /// Check to see if groups are being used in this module
604 $groupmode = groupmode($course, $cm); //TODO: there is no $cm defined!
605 $currentgroup = setup_and_print_groups($course, $groupmode, "report.php?id=$cm->id&mode=simple");
607 $sort = "u.lastname ASC";
609 switch ($formdata['reportusers']) {
612 $users = get_group_students($currentgroup, $sort);
614 $users = get_course_students($course->id
, $sort);
619 $users = get_group_users($currentgroup, $sort);
621 $users = get_course_users($course->id
, $sort);
628 function hotpot_get_records_groupby($function, $fieldnames, $table, $select, $groupby) {
629 // $function is an SQL aggregate function (MAX or MIN)
631 $fields = sql_concat_join("'_'", $fieldnames);
632 $fields = "$groupby, $function($fields) AS joinedvalues";
635 $records = get_records_sql("SELECT $fields FROM $table WHERE $select GROUP BY $groupby");
638 if (empty($fields) ||
empty($records)) {
642 $fieldcount = count($fieldnames);
644 foreach ($records as $id=>$record) {
645 if (empty($record->joinedvalues
)) {
646 unset($records[$id]);
648 $values = explode('_', $record->joinedvalues
);
650 for ($i=0; $i<$fieldcount; $i++
) {
651 $fieldname = $fieldnames[$i];
652 $records[$id]->$fieldname = $values[$i];
655 unset($record->joinedvalues
);