MDL-66132 Search: Behat tests should use simpledb, fix mock count
[moodle.git] / report / completion / user.php
blob47af8428958a64be58b411acf633c4962f40621c
1 <?php
2 // This file is part of Moodle - http://moodle.org/
3 //
4 // Moodle is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU General Public License as published by
6 // the Free Software Foundation, either version 3 of the License, or
7 // (at your option) any later version.
8 //
9 // Moodle is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU General Public License for more details.
14 // You should have received a copy of the GNU General Public License
15 // along with Moodle. If not, see <http://www.gnu.org/licenses/>.
17 /**
18 * Display user completion report
20 * @package report
21 * @subpackage completion
22 * @copyright 2009 Catalyst IT Ltd
23 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
26 require('../../config.php');
27 require_once($CFG->dirroot.'/report/completion/lib.php');
28 require_once($CFG->libdir.'/completionlib.php');
30 $userid = required_param('id', PARAM_INT);
31 $courseid = required_param('course', PARAM_INT);
33 $user = $DB->get_record('user', array('id'=>$userid, 'deleted'=>0), '*', MUST_EXIST);
34 $course = $DB->get_record('course', array('id'=>$courseid), '*', MUST_EXIST);
36 $coursecontext = context_course::instance($course->id);
37 $personalcontext = context_user::instance($user->id);
39 if ($USER->id != $user->id and has_capability('moodle/user:viewuseractivitiesreport', $personalcontext)
40 and !is_enrolled($coursecontext, $USER) and is_enrolled($coursecontext, $user)) {
41 //TODO: do not require parents to be enrolled in courses - this is a hack!
42 require_login();
43 $PAGE->set_course($course);
44 } else {
45 require_login($course);
48 if (!report_completion_can_access_user_report($user, $course)) {
49 // this should never happen
50 print_error('nocapability', 'report_completion');
53 $stractivityreport = get_string('activityreport');
55 $PAGE->set_pagelayout('admin');
56 $PAGE->set_url('/report/completion/user.php', array('id'=>$user->id, 'course'=>$course->id));
57 $PAGE->navigation->extend_for_user($user);
58 $PAGE->navigation->set_userid_for_parent_checks($user->id); // see MDL-25805 for reasons and for full commit reference for reversal when fixed.
59 $PAGE->set_title("$course->shortname: $stractivityreport");
60 $PAGE->set_heading($course->fullname);
61 echo $OUTPUT->header();
64 // Display course completion user report
66 // Grab all courses the user is enrolled in and their completion status
67 $sql = "
68 SELECT DISTINCT
69 c.id AS id
70 FROM
71 {course} c
72 INNER JOIN
73 {context} con
74 ON con.instanceid = c.id
75 INNER JOIN
76 {role_assignments} ra
77 ON ra.contextid = con.id
78 INNER JOIN
79 {enrol} e
80 ON c.id = e.courseid
81 INNER JOIN
82 {user_enrolments} ue
83 ON e.id = ue.enrolid AND ra.userid = ue.userid
84 AND ra.userid = {$user->id}
87 // Get roles that are tracked by course completion
88 if ($roles = $CFG->gradebookroles) {
89 $sql .= '
90 AND ra.roleid IN ('.$roles.')
94 $sql .= '
95 WHERE
96 con.contextlevel = '.CONTEXT_COURSE.'
97 AND c.enablecompletion = 1
101 // If we are looking at a specific course
102 if ($course->id != 1) {
103 $sql .= '
104 AND c.id = '.(int)$course->id.'
108 // Check if result is empty
109 $rs = $DB->get_recordset_sql($sql);
110 if (!$rs->valid()) {
112 if ($course->id != 1) {
113 $error = get_string('nocompletions', 'report_completion'); // TODO: missing string
114 } else {
115 $error = get_string('nocompletioncoursesenroled', 'report_completion'); // TODO: missing string
118 echo $OUTPUT->notification($error);
119 $rs->close(); // not going to loop (but break), close rs
120 echo $OUTPUT->footer();
121 die();
124 // Categorize courses by their status
125 $courses = array(
126 'inprogress' => array(),
127 'complete' => array(),
128 'unstarted' => array()
131 // Sort courses by the user's status in each
132 foreach ($rs as $course_completion) {
133 $c_info = new completion_info((object)$course_completion);
135 // Is course complete?
136 $coursecomplete = $c_info->is_course_complete($user->id);
138 // Has this user completed any criteria?
139 $criteriacomplete = $c_info->count_course_user_data($user->id);
141 if ($coursecomplete) {
142 $courses['complete'][] = $c_info;
143 } else if ($criteriacomplete) {
144 $courses['inprogress'][] = $c_info;
145 } else {
146 $courses['unstarted'][] = $c_info;
149 $rs->close(); // after loop, close rs
151 // Loop through course status groups
152 foreach ($courses as $type => $infos) {
154 // If there are courses with this status
155 if (!empty($infos)) {
157 echo '<h1 align="center">'.get_string($type, 'report_completion').'</h1>';
158 echo '<table class="generaltable boxaligncenter">';
159 echo '<tr class="ccheader">';
160 echo '<th class="c0 header" scope="col">'.get_string('course').'</th>';
161 echo '<th class="c1 header" scope="col">'.get_string('requiredcriteria', 'completion').'</th>';
162 echo '<th class="c2 header" scope="col">'.get_string('status').'</th>';
163 echo '<th class="c3 header" scope="col" width="15%">'.get_string('info').'</th>';
165 if ($type === 'complete') {
166 echo '<th class="c4 header" scope="col">'.get_string('completiondate', 'report_completion').'</th>';
169 echo '</tr>';
171 // For each course
172 foreach ($infos as $c_info) {
174 // Get course info
175 $c_course = $DB->get_record('course', array('id' => $c_info->course_id));
176 $course_context = context_course::instance($c_course->id, MUST_EXIST);
177 $course_name = format_string($c_course->fullname, true, array('context' => $course_context));
179 // Get completions
180 $completions = $c_info->get_completions($user->id);
182 // Save row data
183 $rows = array();
185 // For aggregating activity completion
186 $activities = array();
187 $activities_complete = 0;
189 // For aggregating prerequisites
190 $prerequisites = array();
191 $prerequisites_complete = 0;
193 // Loop through course criteria
194 foreach ($completions as $completion) {
195 $criteria = $completion->get_criteria();
196 $complete = $completion->is_complete();
198 // Activities are a special case, so cache them and leave them till last
199 if ($criteria->criteriatype == COMPLETION_CRITERIA_TYPE_ACTIVITY) {
200 $activities[$criteria->moduleinstance] = $complete;
202 if ($complete) {
203 $activities_complete++;
206 continue;
209 // Prerequisites are also a special case, so cache them and leave them till last
210 if ($criteria->criteriatype == COMPLETION_CRITERIA_TYPE_COURSE) {
211 $prerequisites[$criteria->courseinstance] = $complete;
213 if ($complete) {
214 $prerequisites_complete++;
217 continue;
220 $row = array();
221 $row['title'] = $criteria->get_title();
222 $row['status'] = $completion->get_status();
223 $rows[] = $row;
226 // Aggregate activities
227 if (!empty($activities)) {
229 $row = array();
230 $row['title'] = get_string('activitiescomplete', 'report_completion');
231 $row['status'] = $activities_complete.' of '.count($activities);
232 $rows[] = $row;
235 // Aggregate prerequisites
236 if (!empty($prerequisites)) {
238 $row = array();
239 $row['title'] = get_string('prerequisitescompleted', 'completion');
240 $row['status'] = $prerequisites_complete.' of '.count($prerequisites);
241 array_splice($rows, 0, 0, array($row));
244 $first_row = true;
246 // Print table
247 foreach ($rows as $row) {
249 // Display course name on first row
250 if ($first_row) {
251 echo '<tr><td class="c0"><a href="'.$CFG->wwwroot.'/course/view.php?id='.$c_course->id.'">'.$course_name.'</a></td>';
252 } else {
253 echo '<tr><td class="c0"></td>';
256 echo '<td class="c1">';
257 echo $row['title'];
258 echo '</td><td class="c2">';
260 switch ($row['status']) {
261 case 'Yes':
262 echo get_string('complete');
263 break;
265 case 'No':
266 echo get_string('incomplete', 'report_completion');
267 break;
269 default:
270 echo $row['status'];
273 // Display link on first row
274 echo '</td><td class="c3">';
275 if ($first_row) {
276 echo '<a href="'.$CFG->wwwroot.'/blocks/completionstatus/details.php?course='.$c_course->id.'&user='.$user->id.'">'.get_string('detailedview', 'report_completion').'</a>';
278 echo '</td>';
280 // Display completion date for completed courses on first row
281 if ($type === 'complete' && $first_row) {
282 $params = array(
283 'userid' => $user->id,
284 'course' => $c_course->id
287 $ccompletion = new completion_completion($params);
288 echo '<td class="c4">'.userdate($ccompletion->timecompleted, '%e %B %G').'</td>';
291 $first_row = false;
292 echo '</tr>';
296 echo '</table>';
301 echo $OUTPUT->footer();
302 // Trigger a user report viewed event.
303 $event = \report_completion\event\user_report_viewed::create(array('context' => $coursecontext, 'relateduserid' => $userid));
304 $event->trigger();