MDL-29794 Initial support for re-using a shared grading form
[moodle.git] / grade / querylib.php
1 <?php
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/>.
18 /**
19  * Returns the aggregated or calculated course grade(s) in given course.
20  * @public
21  * @param int $courseid id of course
22  * @param int $userid_or_ids optional id of the graded user or array of ids; if userid not used, returns only information about grade_item
23  * @return information about course grade item scaleid, name, grade and locked status, etc. + user grades
24  */
25 function grade_get_course_grades($courseid, $userid_or_ids=null) {
27     $grade_item = grade_item::fetch_course_item($courseid);
29     if ($grade_item->needsupdate) {
30         grade_regrade_final_grades($courseid);
31     }
33     $item = new stdClass();
34     $item->scaleid    = $grade_item->scaleid;
35     $item->name       = $grade_item->get_name();
36     $item->grademin   = $grade_item->grademin;
37     $item->grademax   = $grade_item->grademax;
38     $item->gradepass  = $grade_item->gradepass;
39     $item->locked     = $grade_item->is_locked();
40     $item->hidden     = $grade_item->is_hidden();
41     $item->grades     = array();
43     switch ($grade_item->gradetype) {
44         case GRADE_TYPE_NONE:
45             continue;
47         case GRADE_TYPE_VALUE:
48             $item->scaleid = 0;
49             break;
51         case GRADE_TYPE_TEXT:
52             $item->scaleid   = 0;
53             $item->grademin   = 0;
54             $item->grademax   = 0;
55             $item->gradepass  = 0;
56             break;
57     }
59     if (empty($userid_or_ids)) {
60         $userids = array();
62     } else if (is_array($userid_or_ids)) {
63         $userids = $userid_or_ids;
65     } else {
66         $userids = array($userid_or_ids);
67     }
69     if ($userids) {
70         $grade_grades = grade_grade::fetch_users_grades($grade_item, $userids, true);
71         foreach ($userids as $userid) {
72             $grade_grades[$userid]->grade_item =& $grade_item;
74             $grade = new stdClass();
75             $grade->grade          = $grade_grades[$userid]->finalgrade;
76             $grade->locked         = $grade_grades[$userid]->is_locked();
77             $grade->hidden         = $grade_grades[$userid]->is_hidden();
78             $grade->overridden     = $grade_grades[$userid]->overridden;
79             $grade->feedback       = $grade_grades[$userid]->feedback;
80             $grade->feedbackformat = $grade_grades[$userid]->feedbackformat;
81             $grade->usermodified   = $grade_grades[$userid]->usermodified;
82             $grade->dategraded     = $grade_grades[$userid]->get_dategraded();
84             // create text representation of grade
85             if ($grade_item->needsupdate) {
86                 $grade->grade          = false;
87                 $grade->str_grade      = get_string('error');
88                 $grade->str_long_grade = $grade->str_grade;
90             } else if (is_null($grade->grade)) {
91                 $grade->str_grade      = '-';
92                 $grade->str_long_grade = $grade->str_grade;
94             } else {
95                 $grade->str_grade = grade_format_gradevalue($grade->grade, $grade_item);
96                 if ($grade_item->gradetype == GRADE_TYPE_SCALE or $grade_item->get_displaytype() != GRADE_DISPLAY_TYPE_REAL) {
97                     $grade->str_long_grade = $grade->str_grade;
98                 } else {
99                     $a = new stdClass();
100                     $a->grade = $grade->str_grade;
101                     $a->max   = grade_format_gradevalue($grade_item->grademax, $grade_item);
102                     $grade->str_long_grade = get_string('gradelong', 'grades', $a);
103                 }
104             }
106             // create html representation of feedback
107             if (is_null($grade->feedback)) {
108                 $grade->str_feedback = '';
109             } else {
110                 $grade->str_feedback = format_text($grade->feedback, $grade->feedbackformat);
111             }
113             $item->grades[$userid] = $grade;
114         }
115     }
117     return $item;
120 /**
121  * Returns the aggregated or calculated course grade for the given user(s).
122  * @public
123  * @param int $userid
124  * @param int $courseid optional id of course or array of ids, empty means all uses courses (returns array if not present)
125  * @return mixed grade info or grades array including item info, false if error
126  */
127 function grade_get_course_grade($userid, $courseid_or_ids=null) {
129     if (!is_array($courseid_or_ids)) {
130         if (empty($courseid_or_ids)) {
131             if (!$courses = enrol_get_users_courses($userid)) {
132                 return false;
133             }
134             $courseids = array_keys($courses);
135             return grade_get_course_grade($userid, $courseids);
136         }
137         if (!is_numeric($courseid_or_ids)) {
138             return false;
139         }
140         if (!$grades = grade_get_course_grade($userid, array($courseid_or_ids))) {
141             return false;
142         } else {
143             // only one grade - not array
144             $grade = reset($grades);
145             return $grade;
146         }
147     }
149     foreach ($courseid_or_ids as $courseid) {
150         $grade_item = grade_item::fetch_course_item($courseid);
151         $course_items[$grade_item->courseid] = $grade_item;
152     }
154     $grades = array();
155     foreach ($course_items as $grade_item) {
156         if ($grade_item->needsupdate) {
157             grade_regrade_final_grades($courseid);
158         }
160         $item = new stdClass();
161         $item->scaleid    = $grade_item->scaleid;
162         $item->name       = $grade_item->get_name();
163         $item->grademin   = $grade_item->grademin;
164         $item->grademax   = $grade_item->grademax;
165         $item->gradepass  = $grade_item->gradepass;
166         $item->locked     = $grade_item->is_locked();
167         $item->hidden     = $grade_item->is_hidden();
169         switch ($grade_item->gradetype) {
170             case GRADE_TYPE_NONE:
171                 continue;
173             case GRADE_TYPE_VALUE:
174                 $item->scaleid = 0;
175                 break;
177             case GRADE_TYPE_TEXT:
178                 $item->scaleid   = 0;
179                 $item->grademin   = 0;
180                 $item->grademax   = 0;
181                 $item->gradepass  = 0;
182                 break;
183         }
184         $grade_grade = new grade_grade(array('userid'=>$userid, 'itemid'=>$grade_item->id));
185         $grade_grade->grade_item =& $grade_item;
187         $grade = new stdClass();
188         $grade->grade          = $grade_grade->finalgrade;
189         $grade->locked         = $grade_grade->is_locked();
190         $grade->hidden         = $grade_grade->is_hidden();
191         $grade->overridden     = $grade_grade->overridden;
192         $grade->feedback       = $grade_grade->feedback;
193         $grade->feedbackformat = $grade_grade->feedbackformat;
194         $grade->usermodified   = $grade_grade->usermodified;
195         $grade->dategraded     = $grade_grade->get_dategraded();
196         $grade->item           = $item;
198         // create text representation of grade
199         if ($grade_item->needsupdate) {
200             $grade->grade          = false;
201             $grade->str_grade      = get_string('error');
202             $grade->str_long_grade = $grade->str_grade;
204         } else if (is_null($grade->grade)) {
205             $grade->str_grade      = '-';
206             $grade->str_long_grade = $grade->str_grade;
208         } else {
209             $grade->str_grade = grade_format_gradevalue($grade->grade, $grade_item);
210             if ($grade_item->gradetype == GRADE_TYPE_SCALE or $grade_item->get_displaytype() != GRADE_DISPLAY_TYPE_REAL) {
211                 $grade->str_long_grade = $grade->str_grade;
212             } else {
213                 $a = new stdClass();
214                 $a->grade = $grade->str_grade;
215                 $a->max   = grade_format_gradevalue($grade_item->grademax, $grade_item);
216                 $grade->str_long_grade = get_string('gradelong', 'grades', $a);
217             }
218         }
220         // create html representation of feedback
221         if (is_null($grade->feedback)) {
222             $grade->str_feedback = '';
223         } else {
224             $grade->str_feedback = format_text($grade->feedback, $grade->feedbackformat);
225         }
227         $grades[$grade_item->courseid] = $grade;
228     }
230     return $grades;
233 /**
234  * Returns all grade items (including outcomes) or main item for a given activity identified by $cm object.
235  *
236  * @param object $cm A course module object (preferably with modname property)
237  * @return mixed - array of grade item instances (one if $only_main_item true), false if error or not found
238  */
239 function grade_get_grade_items_for_activity($cm, $only_main_item=false) {
240     global $CFG, $DB;
242     if (!isset($cm->modname)) {
243         $params = array($cm->id);
244         $cm = $DB->get_record_sql("SELECT cm.*, m.name, md.name as modname
245                                     FROM {course_modules} cm,
246                                          {modules} md,
247                                    WHERE cm.id = ? AND md.id = cm.module", $params);
248     }
251     if (empty($cm) or empty($cm->instance) or empty($cm->course)) {
252         debugging("Incorrect cm parameter in grade_get_grade_items_for_activity()!");
253         return false;
254     }
256     if ($only_main_item) {
257         return grade_item::fetch_all(array('itemtype'=>'mod', 'itemmodule'=>$cm->modname, 'iteminstance'=>$cm->instance, 'courseid'=>$cm->course, 'itemnumber'=>0));
258     } else {
259         return grade_item::fetch_all(array('itemtype'=>'mod', 'itemmodule'=>$cm->modname, 'iteminstance'=>$cm->instance, 'courseid'=>$cm->course));
260     }
263 /**
264  * Returns whether or not user received grades in main grade item for given activity.
265  *
266  * @param object $cm
267  * @param int $userid
268  * @return bool True if graded false if user not graded yet
269  */
270 function grade_is_user_graded_in_activity($cm, $userid) {
272     $grade_items = grade_get_grade_items_for_activity($cm, true);
273     if (empty($grade_items)) {
274         return false;
275     }
277     $grade_item = reset($grade_items);
279     if ($grade_item->gradetype == GRADE_TYPE_NONE) {
280         return false;
281     }
283     if ($grade_item->needsupdate) {
284         // activity items should never fail to regrade
285         grade_regrade_final_grades($grade_item->courseid);
286     }
288     if (!$grade = $grade_item->get_final($userid)) {
289         return false;
290     }
292     if (is_null($grade->finalgrade)) {
293         return false;
294     }
296     return true;
299 /**
300  * Returns an array of activities (defined as $cm objects) which are gradeable from gradebook, outcomes are ignored.
301  *
302  * @param int $courseid If provided then restrict to one course.
303  * @param string $modulename If defined (could be 'forum', 'assignment' etc) then only that type are returned.
304  * @return array $cm objects
305  */
306 function grade_get_gradable_activities($courseid, $modulename='') {
307     global $CFG, $DB;
309     if (empty($modulename)) {
310         if (!$modules = $DB->get_records('modules', array('visible' => '1'))) {
311             return false;
312         }
313         $result = array();
314         foreach ($modules as $module) {
315             if ($cms = grade_get_gradable_activities($courseid, $module->name)) {
316                 $result =  $result + $cms;
317             }
318         }
319         if (empty($result)) {
320             return false;
321         } else {
322             return $result;
323         }
324     }
326     $params = array($courseid, $modulename, GRADE_TYPE_NONE, $modulename);
327     $sql = "SELECT cm.*, m.name, md.name as modname
328               FROM {grade_items} gi, {course_modules} cm, {modules} md, {$modulename} m
329              WHERE gi.courseid = ? AND
330                    gi.itemtype = 'mod' AND
331                    gi.itemmodule = ? AND
332                    gi.itemnumber = 0 AND
333                    gi.gradetype != ? AND
334                    gi.iteminstance = cm.instance AND
335                    cm.instance = m.id AND
336                    md.name = ? AND
337                    md.id = cm.module";
339     return $DB->get_records_sql($sql, $params);