| 1 | efrain | 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.
 | 
        
           |  |  | 13 | //
 | 
        
           |  |  | 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/>.
 | 
        
           |  |  | 16 |   | 
        
           |  |  | 17 | /**
 | 
        
           |  |  | 18 |  * Functions used by gradebook plugins and reports.
 | 
        
           |  |  | 19 |  *
 | 
        
           |  |  | 20 |  * @package   core_grades
 | 
        
           |  |  | 21 |  * @copyright 2009 Petr Skoda and Nicolas Connault
 | 
        
           |  |  | 22 |  * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
 | 
        
           |  |  | 23 |  */
 | 
        
           |  |  | 24 |   | 
        
           |  |  | 25 | require_once($CFG->libdir . '/gradelib.php');
 | 
        
           |  |  | 26 | require_once($CFG->dirroot . '/grade/export/lib.php');
 | 
        
           |  |  | 27 |   | 
        
           |  |  | 28 | use \core_grades\output\action_bar;
 | 
        
           |  |  | 29 | use \core_grades\output\general_action_bar;
 | 
        
           | 1441 | ariadna | 30 | use \core\output\single_select;
 | 
        
           | 1 | efrain | 31 |   | 
        
           |  |  | 32 | /**
 | 
        
           |  |  | 33 |  * This class iterates over all users that are graded in a course.
 | 
        
           |  |  | 34 |  * Returns detailed info about users and their grades.
 | 
        
           |  |  | 35 |  *
 | 
        
           |  |  | 36 |  * @author Petr Skoda <skodak@moodle.org>
 | 
        
           |  |  | 37 |  * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
 | 
        
           |  |  | 38 |  */
 | 
        
           |  |  | 39 | class graded_users_iterator {
 | 
        
           |  |  | 40 |   | 
        
           |  |  | 41 |     /**
 | 
        
           |  |  | 42 |      * The couse whose users we are interested in
 | 
        
           |  |  | 43 |      */
 | 
        
           |  |  | 44 |     protected $course;
 | 
        
           |  |  | 45 |   | 
        
           |  |  | 46 |     /**
 | 
        
           |  |  | 47 |      * An array of grade items or null if only user data was requested
 | 
        
           |  |  | 48 |      */
 | 
        
           |  |  | 49 |     protected $grade_items;
 | 
        
           |  |  | 50 |   | 
        
           |  |  | 51 |     /**
 | 
        
           |  |  | 52 |      * The group ID we are interested in. 0 means all groups.
 | 
        
           |  |  | 53 |      */
 | 
        
           |  |  | 54 |     protected $groupid;
 | 
        
           |  |  | 55 |   | 
        
           |  |  | 56 |     /**
 | 
        
           |  |  | 57 |      * A recordset of graded users
 | 
        
           |  |  | 58 |      */
 | 
        
           |  |  | 59 |     protected $users_rs;
 | 
        
           |  |  | 60 |   | 
        
           |  |  | 61 |     /**
 | 
        
           |  |  | 62 |      * A recordset of user grades (grade_grade instances)
 | 
        
           |  |  | 63 |      */
 | 
        
           |  |  | 64 |     protected $grades_rs;
 | 
        
           |  |  | 65 |   | 
        
           |  |  | 66 |     /**
 | 
        
           |  |  | 67 |      * Array used when moving to next user while iterating through the grades recordset
 | 
        
           |  |  | 68 |      */
 | 
        
           |  |  | 69 |     protected $gradestack;
 | 
        
           |  |  | 70 |   | 
        
           |  |  | 71 |     /**
 | 
        
           |  |  | 72 |      * The first field of the users table by which the array of users will be sorted
 | 
        
           |  |  | 73 |      */
 | 
        
           |  |  | 74 |     protected $sortfield1;
 | 
        
           |  |  | 75 |   | 
        
           |  |  | 76 |     /**
 | 
        
           |  |  | 77 |      * Should sortfield1 be ASC or DESC
 | 
        
           |  |  | 78 |      */
 | 
        
           |  |  | 79 |     protected $sortorder1;
 | 
        
           |  |  | 80 |   | 
        
           |  |  | 81 |     /**
 | 
        
           |  |  | 82 |      * The second field of the users table by which the array of users will be sorted
 | 
        
           |  |  | 83 |      */
 | 
        
           |  |  | 84 |     protected $sortfield2;
 | 
        
           |  |  | 85 |   | 
        
           |  |  | 86 |     /**
 | 
        
           |  |  | 87 |      * Should sortfield2 be ASC or DESC
 | 
        
           |  |  | 88 |      */
 | 
        
           |  |  | 89 |     protected $sortorder2;
 | 
        
           |  |  | 90 |   | 
        
           |  |  | 91 |     /**
 | 
        
           |  |  | 92 |      * Should users whose enrolment has been suspended be ignored?
 | 
        
           |  |  | 93 |      */
 | 
        
           |  |  | 94 |     protected $onlyactive = false;
 | 
        
           |  |  | 95 |   | 
        
           |  |  | 96 |     /**
 | 
        
           |  |  | 97 |      * Enable user custom fields
 | 
        
           |  |  | 98 |      */
 | 
        
           |  |  | 99 |     protected $allowusercustomfields = false;
 | 
        
           |  |  | 100 |   | 
        
           |  |  | 101 |     /**
 | 
        
           |  |  | 102 |      * List of suspended users in course. This includes users whose enrolment status is suspended
 | 
        
           |  |  | 103 |      * or enrolment has expired or not started.
 | 
        
           |  |  | 104 |      */
 | 
        
           |  |  | 105 |     protected $suspendedusers = array();
 | 
        
           |  |  | 106 |   | 
        
           |  |  | 107 |     /**
 | 
        
           |  |  | 108 |      * Constructor
 | 
        
           |  |  | 109 |      *
 | 
        
           |  |  | 110 |      * @param object $course A course object
 | 
        
           |  |  | 111 |      * @param array  $grade_items array of grade items, if not specified only user info returned
 | 
        
           |  |  | 112 |      * @param int    $groupid iterate only group users if present
 | 
        
           |  |  | 113 |      * @param string $sortfield1 The first field of the users table by which the array of users will be sorted
 | 
        
           |  |  | 114 |      * @param string $sortorder1 The order in which the first sorting field will be sorted (ASC or DESC)
 | 
        
           |  |  | 115 |      * @param string $sortfield2 The second field of the users table by which the array of users will be sorted
 | 
        
           |  |  | 116 |      * @param string $sortorder2 The order in which the second sorting field will be sorted (ASC or DESC)
 | 
        
           |  |  | 117 |      */
 | 
        
           |  |  | 118 |     public function __construct($course, $grade_items=null, $groupid=0,
 | 
        
           |  |  | 119 |                                           $sortfield1='lastname', $sortorder1='ASC',
 | 
        
           |  |  | 120 |                                           $sortfield2='firstname', $sortorder2='ASC') {
 | 
        
           |  |  | 121 |         $this->course      = $course;
 | 
        
           |  |  | 122 |         $this->grade_items = $grade_items;
 | 
        
           |  |  | 123 |         $this->groupid     = $groupid;
 | 
        
           |  |  | 124 |         $this->sortfield1  = $sortfield1;
 | 
        
           |  |  | 125 |         $this->sortorder1  = $sortorder1;
 | 
        
           |  |  | 126 |         $this->sortfield2  = $sortfield2;
 | 
        
           |  |  | 127 |         $this->sortorder2  = $sortorder2;
 | 
        
           |  |  | 128 |   | 
        
           |  |  | 129 |         $this->gradestack  = array();
 | 
        
           |  |  | 130 |     }
 | 
        
           |  |  | 131 |   | 
        
           |  |  | 132 |     /**
 | 
        
           |  |  | 133 |      * Initialise the iterator
 | 
        
           |  |  | 134 |      *
 | 
        
           |  |  | 135 |      * @return boolean success
 | 
        
           |  |  | 136 |      */
 | 
        
           |  |  | 137 |     public function init() {
 | 
        
           |  |  | 138 |         global $CFG, $DB;
 | 
        
           |  |  | 139 |   | 
        
           |  |  | 140 |         $this->close();
 | 
        
           |  |  | 141 |   | 
        
           |  |  | 142 |         export_verify_grades($this->course->id);
 | 
        
           |  |  | 143 |         $course_item = grade_item::fetch_course_item($this->course->id);
 | 
        
           |  |  | 144 |         if ($course_item->needsupdate) {
 | 
        
           |  |  | 145 |             // Can not calculate all final grades - sorry.
 | 
        
           |  |  | 146 |             return false;
 | 
        
           |  |  | 147 |         }
 | 
        
           |  |  | 148 |   | 
        
           |  |  | 149 |         $coursecontext = context_course::instance($this->course->id);
 | 
        
           |  |  | 150 |   | 
        
           |  |  | 151 |         list($relatedctxsql, $relatedctxparams) = $DB->get_in_or_equal($coursecontext->get_parent_context_ids(true), SQL_PARAMS_NAMED, 'relatedctx');
 | 
        
           |  |  | 152 |         list($gradebookroles_sql, $params) = $DB->get_in_or_equal(explode(',', $CFG->gradebookroles), SQL_PARAMS_NAMED, 'grbr');
 | 
        
           |  |  | 153 |         list($enrolledsql, $enrolledparams) = get_enrolled_sql($coursecontext, '', 0, $this->onlyactive);
 | 
        
           |  |  | 154 |   | 
        
           |  |  | 155 |         $params = array_merge($params, $enrolledparams, $relatedctxparams);
 | 
        
           |  |  | 156 |   | 
        
           |  |  | 157 |         if ($this->groupid) {
 | 
        
           |  |  | 158 |             $groupsql = "INNER JOIN {groups_members} gm ON gm.userid = u.id";
 | 
        
           |  |  | 159 |             $groupwheresql = "AND gm.groupid = :groupid";
 | 
        
           |  |  | 160 |             // $params contents: gradebookroles
 | 
        
           |  |  | 161 |             $params['groupid'] = $this->groupid;
 | 
        
           |  |  | 162 |         } else {
 | 
        
           |  |  | 163 |             $groupsql = "";
 | 
        
           |  |  | 164 |             $groupwheresql = "";
 | 
        
           |  |  | 165 |         }
 | 
        
           |  |  | 166 |   | 
        
           |  |  | 167 |         if (empty($this->sortfield1)) {
 | 
        
           |  |  | 168 |             // We must do some sorting even if not specified.
 | 
        
           |  |  | 169 |             $ofields = ", u.id AS usrt";
 | 
        
           |  |  | 170 |             $order   = "usrt ASC";
 | 
        
           |  |  | 171 |   | 
        
           |  |  | 172 |         } else {
 | 
        
           |  |  | 173 |             $ofields = ", u.$this->sortfield1 AS usrt1";
 | 
        
           |  |  | 174 |             $order   = "usrt1 $this->sortorder1";
 | 
        
           |  |  | 175 |             if (!empty($this->sortfield2)) {
 | 
        
           |  |  | 176 |                 $ofields .= ", u.$this->sortfield2 AS usrt2";
 | 
        
           |  |  | 177 |                 $order   .= ", usrt2 $this->sortorder2";
 | 
        
           |  |  | 178 |             }
 | 
        
           |  |  | 179 |             if ($this->sortfield1 != 'id' and $this->sortfield2 != 'id') {
 | 
        
           |  |  | 180 |                 // User order MUST be the same in both queries,
 | 
        
           |  |  | 181 |                 // must include the only unique user->id if not already present.
 | 
        
           |  |  | 182 |                 $ofields .= ", u.id AS usrt";
 | 
        
           |  |  | 183 |                 $order   .= ", usrt ASC";
 | 
        
           |  |  | 184 |             }
 | 
        
           |  |  | 185 |         }
 | 
        
           |  |  | 186 |   | 
        
           |  |  | 187 |         $userfields = 'u.*';
 | 
        
           |  |  | 188 |         $customfieldssql = '';
 | 
        
           |  |  | 189 |         if ($this->allowusercustomfields && !empty($CFG->grade_export_customprofilefields)) {
 | 
        
           |  |  | 190 |             $customfieldscount = 0;
 | 
        
           |  |  | 191 |             $customfieldsarray = grade_helper::get_user_profile_fields($this->course->id, $this->allowusercustomfields);
 | 
        
           |  |  | 192 |             foreach ($customfieldsarray as $field) {
 | 
        
           |  |  | 193 |                 if (!empty($field->customid)) {
 | 
        
           |  |  | 194 |                     $customfieldssql .= "
 | 
        
           |  |  | 195 |                             LEFT JOIN (SELECT * FROM {user_info_data}
 | 
        
           |  |  | 196 |                                 WHERE fieldid = :cf$customfieldscount) cf$customfieldscount
 | 
        
           |  |  | 197 |                             ON u.id = cf$customfieldscount.userid";
 | 
        
           |  |  | 198 |                     $userfields .= ", cf$customfieldscount.data AS customfield_{$field->customid}";
 | 
        
           |  |  | 199 |                     $params['cf'.$customfieldscount] = $field->customid;
 | 
        
           |  |  | 200 |                     $customfieldscount++;
 | 
        
           |  |  | 201 |                 }
 | 
        
           |  |  | 202 |             }
 | 
        
           |  |  | 203 |         }
 | 
        
           |  |  | 204 |   | 
        
           |  |  | 205 |         $users_sql = "SELECT $userfields $ofields
 | 
        
           |  |  | 206 |                         FROM {user} u
 | 
        
           |  |  | 207 |                         JOIN ($enrolledsql) je ON je.id = u.id
 | 
        
           |  |  | 208 |                              $groupsql $customfieldssql
 | 
        
           |  |  | 209 |                         JOIN (
 | 
        
           |  |  | 210 |                                   SELECT DISTINCT ra.userid
 | 
        
           |  |  | 211 |                                     FROM {role_assignments} ra
 | 
        
           |  |  | 212 |                                    WHERE ra.roleid $gradebookroles_sql
 | 
        
           |  |  | 213 |                                      AND ra.contextid $relatedctxsql
 | 
        
           |  |  | 214 |                              ) rainner ON rainner.userid = u.id
 | 
        
           |  |  | 215 |                          WHERE u.deleted = 0
 | 
        
           |  |  | 216 |                              $groupwheresql
 | 
        
           |  |  | 217 |                     ORDER BY $order";
 | 
        
           |  |  | 218 |         $this->users_rs = $DB->get_recordset_sql($users_sql, $params);
 | 
        
           |  |  | 219 |   | 
        
           |  |  | 220 |         if (!$this->onlyactive) {
 | 
        
           |  |  | 221 |             $context = context_course::instance($this->course->id);
 | 
        
           |  |  | 222 |             $this->suspendedusers = get_suspended_userids($context);
 | 
        
           |  |  | 223 |         } else {
 | 
        
           |  |  | 224 |             $this->suspendedusers = array();
 | 
        
           |  |  | 225 |         }
 | 
        
           |  |  | 226 |   | 
        
           |  |  | 227 |         if (!empty($this->grade_items)) {
 | 
        
           |  |  | 228 |             $itemids = array_keys($this->grade_items);
 | 
        
           |  |  | 229 |             list($itemidsql, $grades_params) = $DB->get_in_or_equal($itemids, SQL_PARAMS_NAMED, 'items');
 | 
        
           |  |  | 230 |             $params = array_merge($params, $grades_params);
 | 
        
           |  |  | 231 |   | 
        
           |  |  | 232 |             $grades_sql = "SELECT g.* $ofields
 | 
        
           |  |  | 233 |                              FROM {grade_grades} g
 | 
        
           |  |  | 234 |                              JOIN {user} u ON g.userid = u.id
 | 
        
           |  |  | 235 |                              JOIN ($enrolledsql) je ON je.id = u.id
 | 
        
           |  |  | 236 |                                   $groupsql
 | 
        
           |  |  | 237 |                              JOIN (
 | 
        
           |  |  | 238 |                                       SELECT DISTINCT ra.userid
 | 
        
           |  |  | 239 |                                         FROM {role_assignments} ra
 | 
        
           |  |  | 240 |                                        WHERE ra.roleid $gradebookroles_sql
 | 
        
           |  |  | 241 |                                          AND ra.contextid $relatedctxsql
 | 
        
           |  |  | 242 |                                   ) rainner ON rainner.userid = u.id
 | 
        
           |  |  | 243 |                               WHERE u.deleted = 0
 | 
        
           |  |  | 244 |                               AND g.itemid $itemidsql
 | 
        
           |  |  | 245 |                               $groupwheresql
 | 
        
           |  |  | 246 |                          ORDER BY $order, g.itemid ASC";
 | 
        
           |  |  | 247 |             $this->grades_rs = $DB->get_recordset_sql($grades_sql, $params);
 | 
        
           |  |  | 248 |         } else {
 | 
        
           |  |  | 249 |             $this->grades_rs = false;
 | 
        
           |  |  | 250 |         }
 | 
        
           |  |  | 251 |   | 
        
           |  |  | 252 |         return true;
 | 
        
           |  |  | 253 |     }
 | 
        
           |  |  | 254 |   | 
        
           |  |  | 255 |     /**
 | 
        
           |  |  | 256 |      * Returns information about the next user
 | 
        
           |  |  | 257 |      * @return mixed array of user info, all grades and feedback or null when no more users found
 | 
        
           |  |  | 258 |      */
 | 
        
           |  |  | 259 |     public function next_user() {
 | 
        
           |  |  | 260 |         if (!$this->users_rs) {
 | 
        
           |  |  | 261 |             return false; // no users present
 | 
        
           |  |  | 262 |         }
 | 
        
           |  |  | 263 |   | 
        
           |  |  | 264 |         if (!$this->users_rs->valid()) {
 | 
        
           |  |  | 265 |             if ($current = $this->_pop()) {
 | 
        
           |  |  | 266 |                 // this is not good - user or grades updated between the two reads above :-(
 | 
        
           |  |  | 267 |             }
 | 
        
           |  |  | 268 |   | 
        
           |  |  | 269 |             return false; // no more users
 | 
        
           |  |  | 270 |         } else {
 | 
        
           |  |  | 271 |             $user = $this->users_rs->current();
 | 
        
           |  |  | 272 |             $this->users_rs->next();
 | 
        
           |  |  | 273 |         }
 | 
        
           |  |  | 274 |   | 
        
           |  |  | 275 |         // find grades of this user
 | 
        
           |  |  | 276 |         $grade_records = array();
 | 
        
           |  |  | 277 |         while (true) {
 | 
        
           |  |  | 278 |             if (!$current = $this->_pop()) {
 | 
        
           |  |  | 279 |                 break; // no more grades
 | 
        
           |  |  | 280 |             }
 | 
        
           |  |  | 281 |   | 
        
           |  |  | 282 |             if (empty($current->userid)) {
 | 
        
           |  |  | 283 |                 break;
 | 
        
           |  |  | 284 |             }
 | 
        
           |  |  | 285 |   | 
        
           |  |  | 286 |             if ($current->userid != $user->id) {
 | 
        
           |  |  | 287 |                 // grade of the next user, we have all for this user
 | 
        
           |  |  | 288 |                 $this->_push($current);
 | 
        
           |  |  | 289 |                 break;
 | 
        
           |  |  | 290 |             }
 | 
        
           |  |  | 291 |   | 
        
           |  |  | 292 |             $grade_records[$current->itemid] = $current;
 | 
        
           |  |  | 293 |         }
 | 
        
           |  |  | 294 |   | 
        
           |  |  | 295 |         $grades = array();
 | 
        
           |  |  | 296 |         $feedbacks = array();
 | 
        
           |  |  | 297 |   | 
        
           |  |  | 298 |         if (!empty($this->grade_items)) {
 | 
        
           |  |  | 299 |             foreach ($this->grade_items as $grade_item) {
 | 
        
           |  |  | 300 |                 if (!isset($feedbacks[$grade_item->id])) {
 | 
        
           |  |  | 301 |                     $feedbacks[$grade_item->id] = new stdClass();
 | 
        
           |  |  | 302 |                 }
 | 
        
           |  |  | 303 |                 if (array_key_exists($grade_item->id, $grade_records)) {
 | 
        
           |  |  | 304 |                     $feedbacks[$grade_item->id]->feedback       = $grade_records[$grade_item->id]->feedback;
 | 
        
           |  |  | 305 |                     $feedbacks[$grade_item->id]->feedbackformat = $grade_records[$grade_item->id]->feedbackformat;
 | 
        
           |  |  | 306 |                     unset($grade_records[$grade_item->id]->feedback);
 | 
        
           |  |  | 307 |                     unset($grade_records[$grade_item->id]->feedbackformat);
 | 
        
           |  |  | 308 |                     $grades[$grade_item->id] = new grade_grade($grade_records[$grade_item->id], false);
 | 
        
           |  |  | 309 |                 } else {
 | 
        
           |  |  | 310 |                     $feedbacks[$grade_item->id]->feedback       = '';
 | 
        
           |  |  | 311 |                     $feedbacks[$grade_item->id]->feedbackformat = FORMAT_MOODLE;
 | 
        
           |  |  | 312 |                     $grades[$grade_item->id] =
 | 
        
           |  |  | 313 |                         new grade_grade(array('userid'=>$user->id, 'itemid'=>$grade_item->id), false);
 | 
        
           |  |  | 314 |                 }
 | 
        
           |  |  | 315 |                 $grades[$grade_item->id]->grade_item = $grade_item;
 | 
        
           |  |  | 316 |             }
 | 
        
           |  |  | 317 |         }
 | 
        
           |  |  | 318 |   | 
        
           |  |  | 319 |         // Set user suspended status.
 | 
        
           |  |  | 320 |         $user->suspendedenrolment = isset($this->suspendedusers[$user->id]);
 | 
        
           |  |  | 321 |         $result = new stdClass();
 | 
        
           |  |  | 322 |         $result->user      = $user;
 | 
        
           |  |  | 323 |         $result->grades    = $grades;
 | 
        
           |  |  | 324 |         $result->feedbacks = $feedbacks;
 | 
        
           |  |  | 325 |         return $result;
 | 
        
           |  |  | 326 |     }
 | 
        
           |  |  | 327 |   | 
        
           |  |  | 328 |     /**
 | 
        
           |  |  | 329 |      * Close the iterator, do not forget to call this function
 | 
        
           |  |  | 330 |      */
 | 
        
           |  |  | 331 |     public function close() {
 | 
        
           |  |  | 332 |         if ($this->users_rs) {
 | 
        
           |  |  | 333 |             $this->users_rs->close();
 | 
        
           |  |  | 334 |             $this->users_rs = null;
 | 
        
           |  |  | 335 |         }
 | 
        
           |  |  | 336 |         if ($this->grades_rs) {
 | 
        
           |  |  | 337 |             $this->grades_rs->close();
 | 
        
           |  |  | 338 |             $this->grades_rs = null;
 | 
        
           |  |  | 339 |         }
 | 
        
           |  |  | 340 |         $this->gradestack = array();
 | 
        
           |  |  | 341 |     }
 | 
        
           |  |  | 342 |   | 
        
           |  |  | 343 |     /**
 | 
        
           |  |  | 344 |      * Should all enrolled users be exported or just those with an active enrolment?
 | 
        
           |  |  | 345 |      *
 | 
        
           |  |  | 346 |      * @param bool $onlyactive True to limit the export to users with an active enrolment
 | 
        
           |  |  | 347 |      */
 | 
        
           |  |  | 348 |     public function require_active_enrolment($onlyactive = true) {
 | 
        
           |  |  | 349 |         if (!empty($this->users_rs)) {
 | 
        
           |  |  | 350 |             debugging('Calling require_active_enrolment() has no effect unless you call init() again', DEBUG_DEVELOPER);
 | 
        
           |  |  | 351 |         }
 | 
        
           |  |  | 352 |         $this->onlyactive  = $onlyactive;
 | 
        
           |  |  | 353 |     }
 | 
        
           |  |  | 354 |   | 
        
           |  |  | 355 |     /**
 | 
        
           |  |  | 356 |      * Allow custom fields to be included
 | 
        
           |  |  | 357 |      *
 | 
        
           |  |  | 358 |      * @param bool $allow Whether to allow custom fields or not
 | 
        
           |  |  | 359 |      * @return void
 | 
        
           |  |  | 360 |      */
 | 
        
           |  |  | 361 |     public function allow_user_custom_fields($allow = true) {
 | 
        
           |  |  | 362 |         if ($allow) {
 | 
        
           |  |  | 363 |             $this->allowusercustomfields = true;
 | 
        
           |  |  | 364 |         } else {
 | 
        
           |  |  | 365 |             $this->allowusercustomfields = false;
 | 
        
           |  |  | 366 |         }
 | 
        
           |  |  | 367 |     }
 | 
        
           |  |  | 368 |   | 
        
           |  |  | 369 |     /**
 | 
        
           |  |  | 370 |      * Add a grade_grade instance to the grade stack
 | 
        
           |  |  | 371 |      *
 | 
        
           |  |  | 372 |      * @param grade_grade $grade Grade object
 | 
        
           |  |  | 373 |      *
 | 
        
           |  |  | 374 |      * @return void
 | 
        
           |  |  | 375 |      */
 | 
        
           |  |  | 376 |     private function _push($grade) {
 | 
        
           |  |  | 377 |         array_push($this->gradestack, $grade);
 | 
        
           |  |  | 378 |     }
 | 
        
           |  |  | 379 |   | 
        
           |  |  | 380 |   | 
        
           |  |  | 381 |     /**
 | 
        
           |  |  | 382 |      * Remove a grade_grade instance from the grade stack
 | 
        
           |  |  | 383 |      *
 | 
        
           |  |  | 384 |      * @return grade_grade current grade object
 | 
        
           |  |  | 385 |      */
 | 
        
           |  |  | 386 |     private function _pop() {
 | 
        
           |  |  | 387 |         global $DB;
 | 
        
           |  |  | 388 |         if (empty($this->gradestack)) {
 | 
        
           |  |  | 389 |             if (empty($this->grades_rs) || !$this->grades_rs->valid()) {
 | 
        
           |  |  | 390 |                 return null; // no grades present
 | 
        
           |  |  | 391 |             }
 | 
        
           |  |  | 392 |   | 
        
           |  |  | 393 |             $current = $this->grades_rs->current();
 | 
        
           |  |  | 394 |   | 
        
           |  |  | 395 |             $this->grades_rs->next();
 | 
        
           |  |  | 396 |   | 
        
           |  |  | 397 |             return $current;
 | 
        
           |  |  | 398 |         } else {
 | 
        
           |  |  | 399 |             return array_pop($this->gradestack);
 | 
        
           |  |  | 400 |         }
 | 
        
           |  |  | 401 |     }
 | 
        
           |  |  | 402 | }
 | 
        
           |  |  | 403 |   | 
        
           |  |  | 404 | /**
 | 
        
           |  |  | 405 |  * Print a selection popup form of the graded users in a course.
 | 
        
           |  |  | 406 |  *
 | 
        
           |  |  | 407 |  * @deprecated since 2.0
 | 
        
           |  |  | 408 |  *
 | 
        
           |  |  | 409 |  * @param int    $course id of the course
 | 
        
           |  |  | 410 |  * @param string $actionpage The page receiving the data from the popoup form
 | 
        
           |  |  | 411 |  * @param int    $userid   id of the currently selected user (or 'all' if they are all selected)
 | 
        
           |  |  | 412 |  * @param int    $groupid id of requested group, 0 means all
 | 
        
           |  |  | 413 |  * @param int    $includeall bool include all option
 | 
        
           |  |  | 414 |  * @param bool   $return If true, will return the HTML, otherwise, will print directly
 | 
        
           |  |  | 415 |  * @return null
 | 
        
           | 1441 | ariadna | 416 |  * @todo Final deprecation on Moodle 6.0. See MDL-84680.
 | 
        
           | 1 | efrain | 417 |  */
 | 
        
           | 1441 | ariadna | 418 | #[\core\attribute\deprecated('grade_get_graded_users_select()', since: '5.0', mdl: 'MDL-84673')]
 | 
        
           | 1 | efrain | 419 | function print_graded_users_selector($course, $actionpage, $userid=0, $groupid=0, $includeall=true, $return=false) {
 | 
        
           | 1441 | ariadna | 420 |     \core\deprecation::emit_deprecation(__FUNCTION__);
 | 
        
           |  |  | 421 |     global $OUTPUT;
 | 
        
           | 1 | efrain | 422 |     return $OUTPUT->render(grade_get_graded_users_select(substr($actionpage, 0, strpos($actionpage, '/')), $course, $userid, $groupid, $includeall));
 | 
        
           |  |  | 423 | }
 | 
        
           |  |  | 424 |   | 
        
           | 1441 | ariadna | 425 | /**
 | 
        
           |  |  | 426 |  * Return a selection popup form of the graded users in a course.
 | 
        
           |  |  | 427 |  *
 | 
        
           |  |  | 428 |  * @param string $report name of the report
 | 
        
           |  |  | 429 |  * @param int    $course id of the course
 | 
        
           |  |  | 430 |  * @param int    $userid id of the currently selected user (or 'all' if they are all selected)
 | 
        
           |  |  | 431 |  * @param int    $groupid id of requested group, 0 means all
 | 
        
           |  |  | 432 |  * @param bool   $includeall bool include all option
 | 
        
           |  |  | 433 |  * @return single_select
 | 
        
           |  |  | 434 |  */
 | 
        
           | 1 | efrain | 435 | function grade_get_graded_users_select($report, $course, $userid, $groupid, $includeall) {
 | 
        
           |  |  | 436 |     global $USER, $CFG;
 | 
        
           |  |  | 437 |   | 
        
           |  |  | 438 |     if (is_null($userid)) {
 | 
        
           |  |  | 439 |         $userid = $USER->id;
 | 
        
           |  |  | 440 |     }
 | 
        
           |  |  | 441 |     $coursecontext = context_course::instance($course->id);
 | 
        
           |  |  | 442 |     $defaultgradeshowactiveenrol = !empty($CFG->grade_report_showonlyactiveenrol);
 | 
        
           |  |  | 443 |     $showonlyactiveenrol = get_user_preferences('grade_report_showonlyactiveenrol', $defaultgradeshowactiveenrol);
 | 
        
           |  |  | 444 |     $showonlyactiveenrol = $showonlyactiveenrol || !has_capability('moodle/course:viewsuspendedusers', $coursecontext);
 | 
        
           |  |  | 445 |     $menu = array(); // Will be a list of userid => user name
 | 
        
           |  |  | 446 |     $menususpendedusers = array(); // Suspended users go to a separate optgroup.
 | 
        
           |  |  | 447 |     $gui = new graded_users_iterator($course, null, $groupid);
 | 
        
           |  |  | 448 |     $gui->require_active_enrolment($showonlyactiveenrol);
 | 
        
           |  |  | 449 |     $gui->init();
 | 
        
           |  |  | 450 |     $label = get_string('selectauser', 'grades');
 | 
        
           |  |  | 451 |     if ($includeall) {
 | 
        
           |  |  | 452 |         $menu[0] = get_string('allusers', 'grades');
 | 
        
           |  |  | 453 |         $label = get_string('selectalloroneuser', 'grades');
 | 
        
           |  |  | 454 |     }
 | 
        
           |  |  | 455 |     while ($userdata = $gui->next_user()) {
 | 
        
           |  |  | 456 |         $user = $userdata->user;
 | 
        
           |  |  | 457 |         $userfullname = fullname($user);
 | 
        
           |  |  | 458 |         if ($user->suspendedenrolment) {
 | 
        
           |  |  | 459 |             $menususpendedusers[$user->id] = $userfullname;
 | 
        
           |  |  | 460 |         } else {
 | 
        
           |  |  | 461 |             $menu[$user->id] = $userfullname;
 | 
        
           |  |  | 462 |         }
 | 
        
           |  |  | 463 |     }
 | 
        
           |  |  | 464 |     $gui->close();
 | 
        
           |  |  | 465 |   | 
        
           |  |  | 466 |     if ($includeall) {
 | 
        
           |  |  | 467 |         $menu[0] .= " (" . (count($menu) + count($menususpendedusers) - 1) . ")";
 | 
        
           |  |  | 468 |     }
 | 
        
           |  |  | 469 |   | 
        
           |  |  | 470 |     if (!empty($menususpendedusers)) {
 | 
        
           |  |  | 471 |         $menu[] = array(get_string('suspendedusers') => $menususpendedusers);
 | 
        
           |  |  | 472 |     }
 | 
        
           |  |  | 473 |     $gpr = new grade_plugin_return(array('type' => 'report', 'course' => $course, 'groupid' => $groupid));
 | 
        
           |  |  | 474 |     $select = new single_select(
 | 
        
           |  |  | 475 |         new moodle_url('/grade/report/'.$report.'/index.php', $gpr->get_options()),
 | 
        
           |  |  | 476 |         'userid', $menu, $userid
 | 
        
           |  |  | 477 |     );
 | 
        
           |  |  | 478 |     $select->label = $label;
 | 
        
           |  |  | 479 |     $select->formid = 'choosegradeuser';
 | 
        
           |  |  | 480 |     return $select;
 | 
        
           |  |  | 481 | }
 | 
        
           |  |  | 482 |   | 
        
           |  |  | 483 | /**
 | 
        
           |  |  | 484 |  * Hide warning about changed grades during upgrade to 2.8.
 | 
        
           |  |  | 485 |  *
 | 
        
           |  |  | 486 |  * @param int $courseid The current course id.
 | 
        
           |  |  | 487 |  */
 | 
        
           |  |  | 488 | function hide_natural_aggregation_upgrade_notice($courseid) {
 | 
        
           |  |  | 489 |     unset_config('show_sumofgrades_upgrade_' . $courseid);
 | 
        
           |  |  | 490 | }
 | 
        
           |  |  | 491 |   | 
        
           |  |  | 492 | /**
 | 
        
           |  |  | 493 |  * Hide warning about changed grades during upgrade from 2.8.0-2.8.6 and 2.9.0.
 | 
        
           |  |  | 494 |  *
 | 
        
           |  |  | 495 |  * @param int $courseid The current course id.
 | 
        
           |  |  | 496 |  */
 | 
        
           |  |  | 497 | function grade_hide_min_max_grade_upgrade_notice($courseid) {
 | 
        
           |  |  | 498 |     unset_config('show_min_max_grades_changed_' . $courseid);
 | 
        
           |  |  | 499 | }
 | 
        
           |  |  | 500 |   | 
        
           |  |  | 501 | /**
 | 
        
           |  |  | 502 |  * Use the grade min and max from the grade_grade.
 | 
        
           |  |  | 503 |  *
 | 
        
           |  |  | 504 |  * This is reserved for core use after an upgrade.
 | 
        
           |  |  | 505 |  *
 | 
        
           |  |  | 506 |  * @param int $courseid The current course id.
 | 
        
           |  |  | 507 |  */
 | 
        
           |  |  | 508 | function grade_upgrade_use_min_max_from_grade_grade($courseid) {
 | 
        
           |  |  | 509 |     grade_set_setting($courseid, 'minmaxtouse', GRADE_MIN_MAX_FROM_GRADE_GRADE);
 | 
        
           |  |  | 510 |   | 
        
           |  |  | 511 |     grade_force_full_regrading($courseid);
 | 
        
           |  |  | 512 |     // Do this now, because it probably happened to late in the page load to be happen automatically.
 | 
        
           |  |  | 513 |     grade_regrade_final_grades($courseid);
 | 
        
           |  |  | 514 | }
 | 
        
           |  |  | 515 |   | 
        
           |  |  | 516 | /**
 | 
        
           |  |  | 517 |  * Use the grade min and max from the grade_item.
 | 
        
           |  |  | 518 |  *
 | 
        
           |  |  | 519 |  * This is reserved for core use after an upgrade.
 | 
        
           |  |  | 520 |  *
 | 
        
           |  |  | 521 |  * @param int $courseid The current course id.
 | 
        
           |  |  | 522 |  */
 | 
        
           |  |  | 523 | function grade_upgrade_use_min_max_from_grade_item($courseid) {
 | 
        
           |  |  | 524 |     grade_set_setting($courseid, 'minmaxtouse', GRADE_MIN_MAX_FROM_GRADE_ITEM);
 | 
        
           |  |  | 525 |   | 
        
           |  |  | 526 |     grade_force_full_regrading($courseid);
 | 
        
           |  |  | 527 |     // Do this now, because it probably happened to late in the page load to be happen automatically.
 | 
        
           |  |  | 528 |     grade_regrade_final_grades($courseid);
 | 
        
           |  |  | 529 | }
 | 
        
           |  |  | 530 |   | 
        
           |  |  | 531 | /**
 | 
        
           |  |  | 532 |  * Hide warning about changed grades during upgrade to 2.8.
 | 
        
           |  |  | 533 |  *
 | 
        
           |  |  | 534 |  * @param int $courseid The current course id.
 | 
        
           |  |  | 535 |  */
 | 
        
           |  |  | 536 | function hide_aggregatesubcats_upgrade_notice($courseid) {
 | 
        
           |  |  | 537 |     unset_config('show_aggregatesubcats_upgrade_' . $courseid);
 | 
        
           |  |  | 538 | }
 | 
        
           |  |  | 539 |   | 
        
           |  |  | 540 | /**
 | 
        
           |  |  | 541 |  * Hide warning about changed grades due to bug fixes
 | 
        
           |  |  | 542 |  *
 | 
        
           |  |  | 543 |  * @param int $courseid The current course id.
 | 
        
           |  |  | 544 |  */
 | 
        
           |  |  | 545 | function hide_gradebook_calculations_freeze_notice($courseid) {
 | 
        
           |  |  | 546 |     unset_config('gradebook_calculations_freeze_' . $courseid);
 | 
        
           |  |  | 547 | }
 | 
        
           |  |  | 548 |   | 
        
           |  |  | 549 | /**
 | 
        
           |  |  | 550 |  * Print warning about changed grades during upgrade to 2.8.
 | 
        
           |  |  | 551 |  *
 | 
        
           |  |  | 552 |  * @param int $courseid The current course id.
 | 
        
           |  |  | 553 |  * @param context $context The course context.
 | 
        
           |  |  | 554 |  * @param string $thispage The relative path for the current page. E.g. /grade/report/user/index.php
 | 
        
           |  |  | 555 |  * @param boolean $return return as string
 | 
        
           |  |  | 556 |  *
 | 
        
           |  |  | 557 |  * @return nothing or string if $return true
 | 
        
           |  |  | 558 |  */
 | 
        
           |  |  | 559 | function print_natural_aggregation_upgrade_notice($courseid, $context, $thispage, $return=false) {
 | 
        
           |  |  | 560 |     global $CFG, $OUTPUT;
 | 
        
           |  |  | 561 |     $html = '';
 | 
        
           |  |  | 562 |   | 
        
           |  |  | 563 |     // Do not do anything if they cannot manage the grades of this course.
 | 
        
           |  |  | 564 |     if (!has_capability('moodle/grade:manage', $context)) {
 | 
        
           |  |  | 565 |         return $html;
 | 
        
           |  |  | 566 |     }
 | 
        
           |  |  | 567 |   | 
        
           |  |  | 568 |     $hidesubcatswarning = optional_param('seenaggregatesubcatsupgradedgrades', false, PARAM_BOOL) && confirm_sesskey();
 | 
        
           |  |  | 569 |     $showsubcatswarning = get_config('core', 'show_aggregatesubcats_upgrade_' . $courseid);
 | 
        
           |  |  | 570 |     $hidenaturalwarning = optional_param('seensumofgradesupgradedgrades', false, PARAM_BOOL) && confirm_sesskey();
 | 
        
           |  |  | 571 |     $shownaturalwarning = get_config('core', 'show_sumofgrades_upgrade_' . $courseid);
 | 
        
           |  |  | 572 |   | 
        
           |  |  | 573 |     $hideminmaxwarning = optional_param('seenminmaxupgradedgrades', false, PARAM_BOOL) && confirm_sesskey();
 | 
        
           |  |  | 574 |     $showminmaxwarning = get_config('core', 'show_min_max_grades_changed_' . $courseid);
 | 
        
           |  |  | 575 |   | 
        
           |  |  | 576 |     $useminmaxfromgradeitem = optional_param('useminmaxfromgradeitem', false, PARAM_BOOL) && confirm_sesskey();
 | 
        
           |  |  | 577 |     $useminmaxfromgradegrade = optional_param('useminmaxfromgradegrade', false, PARAM_BOOL) && confirm_sesskey();
 | 
        
           |  |  | 578 |   | 
        
           |  |  | 579 |     $minmaxtouse = grade_get_setting($courseid, 'minmaxtouse', $CFG->grade_minmaxtouse);
 | 
        
           |  |  | 580 |   | 
        
           |  |  | 581 |     $gradebookcalculationsfreeze = get_config('core', 'gradebook_calculations_freeze_' . $courseid);
 | 
        
           |  |  | 582 |     $acceptgradebookchanges = optional_param('acceptgradebookchanges', false, PARAM_BOOL) && confirm_sesskey();
 | 
        
           |  |  | 583 |   | 
        
           |  |  | 584 |     // Hide the warning if the user told it to go away.
 | 
        
           |  |  | 585 |     if ($hidenaturalwarning) {
 | 
        
           |  |  | 586 |         hide_natural_aggregation_upgrade_notice($courseid);
 | 
        
           |  |  | 587 |     }
 | 
        
           |  |  | 588 |     // Hide the warning if the user told it to go away.
 | 
        
           |  |  | 589 |     if ($hidesubcatswarning) {
 | 
        
           |  |  | 590 |         hide_aggregatesubcats_upgrade_notice($courseid);
 | 
        
           |  |  | 591 |     }
 | 
        
           |  |  | 592 |   | 
        
           |  |  | 593 |     // Hide the min/max warning if the user told it to go away.
 | 
        
           |  |  | 594 |     if ($hideminmaxwarning) {
 | 
        
           |  |  | 595 |         grade_hide_min_max_grade_upgrade_notice($courseid);
 | 
        
           |  |  | 596 |         $showminmaxwarning = false;
 | 
        
           |  |  | 597 |     }
 | 
        
           |  |  | 598 |   | 
        
           |  |  | 599 |     if ($useminmaxfromgradegrade) {
 | 
        
           |  |  | 600 |         // Revert to the new behaviour, we now use the grade_grade for min/max.
 | 
        
           |  |  | 601 |         grade_upgrade_use_min_max_from_grade_grade($courseid);
 | 
        
           |  |  | 602 |         grade_hide_min_max_grade_upgrade_notice($courseid);
 | 
        
           |  |  | 603 |         $showminmaxwarning = false;
 | 
        
           |  |  | 604 |   | 
        
           |  |  | 605 |     } else if ($useminmaxfromgradeitem) {
 | 
        
           |  |  | 606 |         // Apply the new logic, we now use the grade_item for min/max.
 | 
        
           |  |  | 607 |         grade_upgrade_use_min_max_from_grade_item($courseid);
 | 
        
           |  |  | 608 |         grade_hide_min_max_grade_upgrade_notice($courseid);
 | 
        
           |  |  | 609 |         $showminmaxwarning = false;
 | 
        
           |  |  | 610 |     }
 | 
        
           |  |  | 611 |   | 
        
           |  |  | 612 |   | 
        
           |  |  | 613 |     if (!$hidenaturalwarning && $shownaturalwarning) {
 | 
        
           |  |  | 614 |         $message = get_string('sumofgradesupgradedgrades', 'grades');
 | 
        
           |  |  | 615 |         $hidemessage = get_string('upgradedgradeshidemessage', 'grades');
 | 
        
           |  |  | 616 |         $urlparams = array( 'id' => $courseid,
 | 
        
           |  |  | 617 |                             'seensumofgradesupgradedgrades' => true,
 | 
        
           |  |  | 618 |                             'sesskey' => sesskey());
 | 
        
           |  |  | 619 |         $goawayurl = new moodle_url($thispage, $urlparams);
 | 
        
           |  |  | 620 |         $goawaybutton = $OUTPUT->single_button($goawayurl, $hidemessage, 'get');
 | 
        
           |  |  | 621 |         $html .= $OUTPUT->notification($message, 'notifysuccess');
 | 
        
           |  |  | 622 |         $html .= $goawaybutton;
 | 
        
           |  |  | 623 |     }
 | 
        
           |  |  | 624 |   | 
        
           |  |  | 625 |     if (!$hidesubcatswarning && $showsubcatswarning) {
 | 
        
           |  |  | 626 |         $message = get_string('aggregatesubcatsupgradedgrades', 'grades');
 | 
        
           |  |  | 627 |         $hidemessage = get_string('upgradedgradeshidemessage', 'grades');
 | 
        
           |  |  | 628 |         $urlparams = array( 'id' => $courseid,
 | 
        
           |  |  | 629 |                             'seenaggregatesubcatsupgradedgrades' => true,
 | 
        
           |  |  | 630 |                             'sesskey' => sesskey());
 | 
        
           |  |  | 631 |         $goawayurl = new moodle_url($thispage, $urlparams);
 | 
        
           |  |  | 632 |         $goawaybutton = $OUTPUT->single_button($goawayurl, $hidemessage, 'get');
 | 
        
           |  |  | 633 |         $html .= $OUTPUT->notification($message, 'notifysuccess');
 | 
        
           |  |  | 634 |         $html .= $goawaybutton;
 | 
        
           |  |  | 635 |     }
 | 
        
           |  |  | 636 |   | 
        
           |  |  | 637 |     if ($showminmaxwarning) {
 | 
        
           |  |  | 638 |         $hidemessage = get_string('upgradedgradeshidemessage', 'grades');
 | 
        
           |  |  | 639 |         $urlparams = array( 'id' => $courseid,
 | 
        
           |  |  | 640 |                             'seenminmaxupgradedgrades' => true,
 | 
        
           |  |  | 641 |                             'sesskey' => sesskey());
 | 
        
           |  |  | 642 |   | 
        
           |  |  | 643 |         $goawayurl = new moodle_url($thispage, $urlparams);
 | 
        
           |  |  | 644 |         $hideminmaxbutton = $OUTPUT->single_button($goawayurl, $hidemessage, 'get');
 | 
        
           |  |  | 645 |         $moreinfo = html_writer::link(get_docs_url(get_string('minmaxtouse_link', 'grades')), get_string('moreinfo'),
 | 
        
           |  |  | 646 |             array('target' => '_blank'));
 | 
        
           |  |  | 647 |   | 
        
           |  |  | 648 |         if ($minmaxtouse == GRADE_MIN_MAX_FROM_GRADE_ITEM) {
 | 
        
           |  |  | 649 |             // Show the message that there were min/max issues that have been resolved.
 | 
        
           |  |  | 650 |             $message = get_string('minmaxupgradedgrades', 'grades') . ' ' . $moreinfo;
 | 
        
           |  |  | 651 |   | 
        
           |  |  | 652 |             $revertmessage = get_string('upgradedminmaxrevertmessage', 'grades');
 | 
        
           |  |  | 653 |             $urlparams = array('id' => $courseid,
 | 
        
           |  |  | 654 |                                'useminmaxfromgradegrade' => true,
 | 
        
           |  |  | 655 |                                'sesskey' => sesskey());
 | 
        
           |  |  | 656 |             $reverturl = new moodle_url($thispage, $urlparams);
 | 
        
           |  |  | 657 |             $revertbutton = $OUTPUT->single_button($reverturl, $revertmessage, 'get');
 | 
        
           |  |  | 658 |   | 
        
           |  |  | 659 |             $html .= $OUTPUT->notification($message);
 | 
        
           |  |  | 660 |             $html .= $revertbutton . $hideminmaxbutton;
 | 
        
           |  |  | 661 |   | 
        
           |  |  | 662 |         } else if ($minmaxtouse == GRADE_MIN_MAX_FROM_GRADE_GRADE) {
 | 
        
           |  |  | 663 |             // Show the warning that there are min/max issues that have not be resolved.
 | 
        
           |  |  | 664 |             $message = get_string('minmaxupgradewarning', 'grades') . ' ' . $moreinfo;
 | 
        
           |  |  | 665 |   | 
        
           |  |  | 666 |             $fixmessage = get_string('minmaxupgradefixbutton', 'grades');
 | 
        
           |  |  | 667 |             $urlparams = array('id' => $courseid,
 | 
        
           |  |  | 668 |                                'useminmaxfromgradeitem' => true,
 | 
        
           |  |  | 669 |                                'sesskey' => sesskey());
 | 
        
           |  |  | 670 |             $fixurl = new moodle_url($thispage, $urlparams);
 | 
        
           |  |  | 671 |             $fixbutton = $OUTPUT->single_button($fixurl, $fixmessage, 'get');
 | 
        
           |  |  | 672 |   | 
        
           |  |  | 673 |             $html .= $OUTPUT->notification($message);
 | 
        
           |  |  | 674 |             $html .= $fixbutton . $hideminmaxbutton;
 | 
        
           |  |  | 675 |         }
 | 
        
           |  |  | 676 |     }
 | 
        
           |  |  | 677 |   | 
        
           |  |  | 678 |     if ($gradebookcalculationsfreeze) {
 | 
        
           |  |  | 679 |         if ($acceptgradebookchanges) {
 | 
        
           |  |  | 680 |             // Accept potential changes in grades caused by extra credit bug MDL-49257.
 | 
        
           |  |  | 681 |             hide_gradebook_calculations_freeze_notice($courseid);
 | 
        
           |  |  | 682 |             $courseitem = grade_item::fetch_course_item($courseid);
 | 
        
           |  |  | 683 |             $courseitem->force_regrading();
 | 
        
           |  |  | 684 |             grade_regrade_final_grades($courseid);
 | 
        
           |  |  | 685 |   | 
        
           |  |  | 686 |             $html .= $OUTPUT->notification(get_string('gradebookcalculationsuptodate', 'grades'), 'notifysuccess');
 | 
        
           |  |  | 687 |         } else {
 | 
        
           |  |  | 688 |             // Show the warning that there may be extra credit weights problems.
 | 
        
           |  |  | 689 |             $a = new stdClass();
 | 
        
           |  |  | 690 |             $a->gradebookversion = $gradebookcalculationsfreeze;
 | 
        
           |  |  | 691 |             if (preg_match('/(\d{8,})/', $CFG->release, $matches)) {
 | 
        
           |  |  | 692 |                 $a->currentversion = $matches[1];
 | 
        
           |  |  | 693 |             } else {
 | 
        
           |  |  | 694 |                 $a->currentversion = $CFG->release;
 | 
        
           |  |  | 695 |             }
 | 
        
           |  |  | 696 |             $a->url = get_docs_url('Gradebook_calculation_changes');
 | 
        
           |  |  | 697 |             $message = get_string('gradebookcalculationswarning', 'grades', $a);
 | 
        
           |  |  | 698 |   | 
        
           |  |  | 699 |             $fixmessage = get_string('gradebookcalculationsfixbutton', 'grades');
 | 
        
           |  |  | 700 |             $urlparams = array('id' => $courseid,
 | 
        
           |  |  | 701 |                 'acceptgradebookchanges' => true,
 | 
        
           |  |  | 702 |                 'sesskey' => sesskey());
 | 
        
           |  |  | 703 |             $fixurl = new moodle_url($thispage, $urlparams);
 | 
        
           |  |  | 704 |             $fixbutton = $OUTPUT->single_button($fixurl, $fixmessage, 'get');
 | 
        
           |  |  | 705 |   | 
        
           |  |  | 706 |             $html .= $OUTPUT->notification($message);
 | 
        
           |  |  | 707 |             $html .= $fixbutton;
 | 
        
           |  |  | 708 |         }
 | 
        
           |  |  | 709 |     }
 | 
        
           |  |  | 710 |   | 
        
           |  |  | 711 |     if (!empty($html)) {
 | 
        
           |  |  | 712 |         $html = html_writer::tag('div', $html, array('class' => 'core_grades_notices'));
 | 
        
           |  |  | 713 |     }
 | 
        
           |  |  | 714 |   | 
        
           |  |  | 715 |     if ($return) {
 | 
        
           |  |  | 716 |         return $html;
 | 
        
           |  |  | 717 |     } else {
 | 
        
           |  |  | 718 |         echo $html;
 | 
        
           |  |  | 719 |     }
 | 
        
           |  |  | 720 | }
 | 
        
           |  |  | 721 |   | 
        
           |  |  | 722 | /**
 | 
        
           |  |  | 723 |  * grade_get_plugin_info
 | 
        
           |  |  | 724 |  *
 | 
        
           |  |  | 725 |  * @param int    $courseid The course id
 | 
        
           |  |  | 726 |  * @param string $active_type type of plugin on current page - import, export, report or edit
 | 
        
           |  |  | 727 |  * @param string $active_plugin active plugin type - grader, user, cvs, ...
 | 
        
           |  |  | 728 |  *
 | 
        
           |  |  | 729 |  * @return array
 | 
        
           |  |  | 730 |  */
 | 
        
           |  |  | 731 | function grade_get_plugin_info($courseid, $active_type, $active_plugin) {
 | 
        
           |  |  | 732 |     global $CFG, $SITE;
 | 
        
           |  |  | 733 |   | 
        
           |  |  | 734 |     $context = context_course::instance($courseid);
 | 
        
           |  |  | 735 |   | 
        
           |  |  | 736 |     $plugin_info = array();
 | 
        
           |  |  | 737 |     $count = 0;
 | 
        
           |  |  | 738 |     $active = '';
 | 
        
           |  |  | 739 |     $url_prefix = $CFG->wwwroot . '/grade/';
 | 
        
           |  |  | 740 |   | 
        
           |  |  | 741 |     // Language strings
 | 
        
           |  |  | 742 |     $plugin_info['strings'] = grade_helper::get_plugin_strings();
 | 
        
           |  |  | 743 |   | 
        
           |  |  | 744 |     if ($reports = grade_helper::get_plugins_reports($courseid)) {
 | 
        
           |  |  | 745 |         $plugin_info['report'] = $reports;
 | 
        
           |  |  | 746 |     }
 | 
        
           |  |  | 747 |   | 
        
           |  |  | 748 |     if ($settings = grade_helper::get_info_manage_settings($courseid)) {
 | 
        
           |  |  | 749 |         $plugin_info['settings'] = $settings;
 | 
        
           |  |  | 750 |     }
 | 
        
           |  |  | 751 |   | 
        
           |  |  | 752 |     if ($scale = grade_helper::get_info_scales($courseid)) {
 | 
        
           |  |  | 753 |         $plugin_info['scale'] = array('view'=>$scale);
 | 
        
           |  |  | 754 |     }
 | 
        
           |  |  | 755 |   | 
        
           |  |  | 756 |     if ($outcomes = grade_helper::get_info_outcomes($courseid)) {
 | 
        
           |  |  | 757 |         $plugin_info['outcome'] = $outcomes;
 | 
        
           |  |  | 758 |     }
 | 
        
           |  |  | 759 |   | 
        
           |  |  | 760 |     if ($letters = grade_helper::get_info_letters($courseid)) {
 | 
        
           |  |  | 761 |         $plugin_info['letter'] = $letters;
 | 
        
           |  |  | 762 |     }
 | 
        
           |  |  | 763 |   | 
        
           |  |  | 764 |     if ($imports = grade_helper::get_plugins_import($courseid)) {
 | 
        
           |  |  | 765 |         $plugin_info['import'] = $imports;
 | 
        
           |  |  | 766 |     }
 | 
        
           |  |  | 767 |   | 
        
           |  |  | 768 |     if ($exports = grade_helper::get_plugins_export($courseid)) {
 | 
        
           |  |  | 769 |         $plugin_info['export'] = $exports;
 | 
        
           |  |  | 770 |     }
 | 
        
           |  |  | 771 |   | 
        
           |  |  | 772 |     // Let other plugins add plugins here so that we get extra tabs
 | 
        
           |  |  | 773 |     // in the gradebook.
 | 
        
           |  |  | 774 |     $callbacks = get_plugins_with_function('extend_gradebook_plugininfo', 'lib.php');
 | 
        
           |  |  | 775 |     foreach ($callbacks as $plugins) {
 | 
        
           |  |  | 776 |         foreach ($plugins as $pluginfunction) {
 | 
        
           |  |  | 777 |             $plugin_info = $pluginfunction($plugin_info, $courseid);
 | 
        
           |  |  | 778 |         }
 | 
        
           |  |  | 779 |     }
 | 
        
           |  |  | 780 |   | 
        
           |  |  | 781 |     foreach ($plugin_info as $plugin_type => $plugins) {
 | 
        
           |  |  | 782 |         if (!empty($plugins->id) && $active_plugin == $plugins->id) {
 | 
        
           |  |  | 783 |             $plugin_info['strings']['active_plugin_str'] = $plugins->string;
 | 
        
           |  |  | 784 |             break;
 | 
        
           |  |  | 785 |         }
 | 
        
           |  |  | 786 |         foreach ($plugins as $plugin) {
 | 
        
           |  |  | 787 |             if (is_a($plugin, grade_plugin_info::class)) {
 | 
        
           |  |  | 788 |                 if ($plugin_type === $active_type && $active_plugin == $plugin->id) {
 | 
        
           |  |  | 789 |                     $plugin_info['strings']['active_plugin_str'] = $plugin->string;
 | 
        
           |  |  | 790 |                 }
 | 
        
           |  |  | 791 |             }
 | 
        
           |  |  | 792 |         }
 | 
        
           |  |  | 793 |     }
 | 
        
           |  |  | 794 |   | 
        
           |  |  | 795 |     return $plugin_info;
 | 
        
           |  |  | 796 | }
 | 
        
           |  |  | 797 |   | 
        
           |  |  | 798 | /**
 | 
        
           |  |  | 799 |  * Load a valid list of gradable users in a course.
 | 
        
           |  |  | 800 |  *
 | 
        
           |  |  | 801 |  * @param int $courseid The course ID.
 | 
        
           |  |  | 802 |  * @param int|null $groupid The group ID (optional).
 | 
        
           |  |  | 803 |  * @param bool $onlyactiveenrol Include only active enrolments.
 | 
        
           |  |  | 804 |  * @return array $users A list of enrolled gradable users.
 | 
        
           |  |  | 805 |  */
 | 
        
           |  |  | 806 | function get_gradable_users(int $courseid, ?int $groupid = null, bool $onlyactiveenrol = false): array {
 | 
        
           |  |  | 807 |     $course = get_course($courseid);
 | 
        
           |  |  | 808 |     // Create a graded_users_iterator because it will properly check the groups etc.
 | 
        
           |  |  | 809 |     $gui = new graded_users_iterator($course, null, $groupid);
 | 
        
           |  |  | 810 |     $gui->require_active_enrolment($onlyactiveenrol);
 | 
        
           |  |  | 811 |     $gui->init();
 | 
        
           |  |  | 812 |   | 
        
           |  |  | 813 |     // Flatten the users.
 | 
        
           |  |  | 814 |     $users = [];
 | 
        
           |  |  | 815 |     while ($user = $gui->next_user()) {
 | 
        
           |  |  | 816 |         $users[$user->user->id] = $user->user;
 | 
        
           |  |  | 817 |     }
 | 
        
           |  |  | 818 |     $gui->close();
 | 
        
           |  |  | 819 |   | 
        
           |  |  | 820 |     return $users;
 | 
        
           |  |  | 821 | }
 | 
        
           |  |  | 822 |   | 
        
           |  |  | 823 | /**
 | 
        
           |  |  | 824 |  * A simple class containing info about grade plugins.
 | 
        
           |  |  | 825 |  * Can be subclassed for special rules
 | 
        
           |  |  | 826 |  *
 | 
        
           |  |  | 827 |  * @package core_grades
 | 
        
           |  |  | 828 |  * @copyright 2009 Nicolas Connault
 | 
        
           |  |  | 829 |  * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
 | 
        
           |  |  | 830 |  */
 | 
        
           |  |  | 831 | class grade_plugin_info {
 | 
        
           |  |  | 832 |     /**
 | 
        
           |  |  | 833 |      * A unique id for this plugin
 | 
        
           |  |  | 834 |      *
 | 
        
           |  |  | 835 |      * @var mixed
 | 
        
           |  |  | 836 |      */
 | 
        
           |  |  | 837 |     public $id;
 | 
        
           |  |  | 838 |     /**
 | 
        
           |  |  | 839 |      * A URL to access this plugin
 | 
        
           |  |  | 840 |      *
 | 
        
           |  |  | 841 |      * @var mixed
 | 
        
           |  |  | 842 |      */
 | 
        
           |  |  | 843 |     public $link;
 | 
        
           |  |  | 844 |     /**
 | 
        
           |  |  | 845 |      * The name of this plugin
 | 
        
           |  |  | 846 |      *
 | 
        
           |  |  | 847 |      * @var mixed
 | 
        
           |  |  | 848 |      */
 | 
        
           |  |  | 849 |     public $string;
 | 
        
           |  |  | 850 |     /**
 | 
        
           |  |  | 851 |      * Another grade_plugin_info object, parent of the current one
 | 
        
           |  |  | 852 |      *
 | 
        
           |  |  | 853 |      * @var mixed
 | 
        
           |  |  | 854 |      */
 | 
        
           |  |  | 855 |     public $parent;
 | 
        
           |  |  | 856 |   | 
        
           |  |  | 857 |     /**
 | 
        
           |  |  | 858 |      * Constructor
 | 
        
           |  |  | 859 |      *
 | 
        
           |  |  | 860 |      * @param int $id A unique id for this plugin
 | 
        
           |  |  | 861 |      * @param string $link A URL to access this plugin
 | 
        
           |  |  | 862 |      * @param string $string The name of this plugin
 | 
        
           |  |  | 863 |      * @param object $parent Another grade_plugin_info object, parent of the current one
 | 
        
           |  |  | 864 |      *
 | 
        
           |  |  | 865 |      * @return void
 | 
        
           |  |  | 866 |      */
 | 
        
           |  |  | 867 |     public function __construct($id, $link, $string, $parent=null) {
 | 
        
           |  |  | 868 |         $this->id = $id;
 | 
        
           |  |  | 869 |         $this->link = $link;
 | 
        
           |  |  | 870 |         $this->string = $string;
 | 
        
           |  |  | 871 |         $this->parent = $parent;
 | 
        
           |  |  | 872 |     }
 | 
        
           |  |  | 873 | }
 | 
        
           |  |  | 874 |   | 
        
           |  |  | 875 | /**
 | 
        
           |  |  | 876 |  * Prints the page headers, breadcrumb trail, page heading, (optional) navigation and for any gradebook page.
 | 
        
           |  |  | 877 |  * All gradebook pages MUST use these functions in favour of the usual print_header(), print_header_simple(),
 | 
        
           |  |  | 878 |  * print_heading() etc.
 | 
        
           |  |  | 879 |  *
 | 
        
           |  |  | 880 |  * @param int $courseid Course id
 | 
        
           |  |  | 881 |  * @param string $active_type The type of the current page (report, settings,
 | 
        
           |  |  | 882 |  *                            import, export, scales, outcomes, letters)
 | 
        
           |  |  | 883 |  * @param string|null $active_plugin The plugin of the current page (grader, fullview etc...)
 | 
        
           |  |  | 884 |  * @param string|bool $heading The heading of the page.
 | 
        
           |  |  | 885 |  * @param boolean $return Whether to return (true) or echo (false) the HTML generated by this function
 | 
        
           |  |  | 886 |  * @param string|bool $buttons Additional buttons to display on the page
 | 
        
           |  |  | 887 |  * @param boolean $shownavigation should the gradebook navigation be shown?
 | 
        
           |  |  | 888 |  * @param string|null $headerhelpidentifier The help string identifier if required.
 | 
        
           |  |  | 889 |  * @param string|null $headerhelpcomponent The component for the help string.
 | 
        
           |  |  | 890 |  * @param stdClass|null $user The user object for use with the user context header.
 | 
        
           |  |  | 891 |  * @param action_bar|null $actionbar The actions bar which will be displayed on the page if $shownavigation is set
 | 
        
           |  |  | 892 |  *                                  to true. If $actionbar is not explicitly defined, the general action bar
 | 
        
           |  |  | 893 |  *                                  (\core_grades\output\general_action_bar) will be used by default.
 | 
        
           |  |  | 894 |  * @param null $unused This parameter has been deprecated since 4.3 and should not be used anymore.
 | 
        
           |  |  | 895 |  * @return string HTML code or nothing if $return == false
 | 
        
           |  |  | 896 |  */
 | 
        
           |  |  | 897 | function print_grade_page_head(int $courseid, string $active_type, ?string $active_plugin = null, string|bool $heading = false,
 | 
        
           |  |  | 898 |        bool $return = false, $buttons = false, bool $shownavigation = true, ?string $headerhelpidentifier = null,
 | 
        
           |  |  | 899 |        ?string $headerhelpcomponent = null, ?stdClass $user = null, ?action_bar $actionbar = null, $unused = null) {
 | 
        
           |  |  | 900 |     global $CFG, $OUTPUT, $PAGE, $USER;
 | 
        
           |  |  | 901 |   | 
        
           |  |  | 902 |     if ($heading !== false) {
 | 
        
           |  |  | 903 |         // Make sure to trim heading, including the non-breaking space character.
 | 
        
           |  |  | 904 |         $heading = str_replace(" ", " ", $heading);
 | 
        
           |  |  | 905 |         $heading = trim($heading);
 | 
        
           |  |  | 906 |     }
 | 
        
           |  |  | 907 |   | 
        
           |  |  | 908 |     if ($unused !== null) {
 | 
        
           |  |  | 909 |         debugging('Deprecated argument passed to ' . __FUNCTION__, DEBUG_DEVELOPER);
 | 
        
           |  |  | 910 |     }
 | 
        
           |  |  | 911 |   | 
        
           |  |  | 912 |     // Put a warning on all gradebook pages if the course has modules currently scheduled for background deletion.
 | 
        
           |  |  | 913 |     require_once($CFG->dirroot . '/course/lib.php');
 | 
        
           |  |  | 914 |     if (course_modules_pending_deletion($courseid, true)) {
 | 
        
           |  |  | 915 |         \core\notification::add(get_string('gradesmoduledeletionpendingwarning', 'grades'),
 | 
        
           |  |  | 916 |             \core\output\notification::NOTIFY_WARNING);
 | 
        
           |  |  | 917 |     }
 | 
        
           |  |  | 918 |   | 
        
           |  |  | 919 |     if ($active_type === 'preferences') {
 | 
        
           |  |  | 920 |         // In Moodle 2.8 report preferences were moved under 'settings'. Allow backward compatibility for 3rd party grade reports.
 | 
        
           |  |  | 921 |         $active_type = 'settings';
 | 
        
           |  |  | 922 |     }
 | 
        
           |  |  | 923 |   | 
        
           |  |  | 924 |     $plugin_info = grade_get_plugin_info($courseid, $active_type, $active_plugin);
 | 
        
           |  |  | 925 |   | 
        
           |  |  | 926 |     // Determine the string of the active plugin.
 | 
        
           |  |  | 927 |     $stractive_type = $plugin_info['strings'][$active_type];
 | 
        
           |  |  | 928 |     $stractiveplugin = ($active_plugin) ? $plugin_info['strings']['active_plugin_str'] : $heading;
 | 
        
           |  |  | 929 |   | 
        
           |  |  | 930 |     if ($active_type == 'report') {
 | 
        
           |  |  | 931 |         $PAGE->set_pagelayout('report');
 | 
        
           |  |  | 932 |     } else {
 | 
        
           |  |  | 933 |         $PAGE->set_pagelayout('admin');
 | 
        
           |  |  | 934 |     }
 | 
        
           |  |  | 935 |     $coursecontext = context_course::instance($courseid);
 | 
        
           |  |  | 936 |     // Title will be constituted by information starting from the unique identifying information for the page.
 | 
        
           |  |  | 937 |     if ($heading) {
 | 
        
           |  |  | 938 |         // If heading is supplied, use this for the page title.
 | 
        
           |  |  | 939 |         $uniquetitle = $heading;
 | 
        
           |  |  | 940 |     } else if (in_array($active_type, ['report', 'settings'])) {
 | 
        
           |  |  | 941 |         // For grade reports or settings pages of grade plugins, use the plugin name for the unique title.
 | 
        
           |  |  | 942 |         $uniquetitle = $stractiveplugin;
 | 
        
           |  |  | 943 |         // But if editing mode is turned on, check if the report plugin has an editing mode title string and use it if present.
 | 
        
           |  |  | 944 |         if ($PAGE->user_is_editing() && $active_type === 'report') {
 | 
        
           |  |  | 945 |             $strcomponent = "gradereport_{$active_plugin}";
 | 
        
           |  |  | 946 |             if (get_string_manager()->string_exists('editingmode_title', $strcomponent)) {
 | 
        
           |  |  | 947 |                 $uniquetitle = get_string('editingmode_title', $strcomponent);
 | 
        
           |  |  | 948 |             }
 | 
        
           |  |  | 949 |         }
 | 
        
           |  |  | 950 |     } else {
 | 
        
           |  |  | 951 |         $uniquetitle = $stractive_type . ': ' . $stractiveplugin;
 | 
        
           |  |  | 952 |     }
 | 
        
           |  |  | 953 |     $titlecomponents = [
 | 
        
           |  |  | 954 |         $uniquetitle,
 | 
        
           |  |  | 955 |         $coursecontext->get_context_name(false),
 | 
        
           |  |  | 956 |     ];
 | 
        
           |  |  | 957 |     $PAGE->set_title(implode(moodle_page::TITLE_SEPARATOR, $titlecomponents));
 | 
        
           |  |  | 958 |     $PAGE->set_heading($PAGE->course->fullname);
 | 
        
           |  |  | 959 |     $PAGE->set_secondary_active_tab('grades');
 | 
        
           |  |  | 960 |   | 
        
           |  |  | 961 |     if ($buttons instanceof single_button) {
 | 
        
           |  |  | 962 |         $buttons = $OUTPUT->render($buttons);
 | 
        
           |  |  | 963 |     }
 | 
        
           |  |  | 964 |     $PAGE->set_button($buttons);
 | 
        
           |  |  | 965 |     if ($courseid != SITEID) {
 | 
        
           |  |  | 966 |         grade_extend_settings($plugin_info, $courseid);
 | 
        
           |  |  | 967 |     }
 | 
        
           |  |  | 968 |   | 
        
           |  |  | 969 |     // Set the current report as active in the breadcrumbs.
 | 
        
           |  |  | 970 |     if ($active_plugin !== null && $reportnav = $PAGE->settingsnav->find($active_plugin, navigation_node::TYPE_SETTING)) {
 | 
        
           |  |  | 971 |         $reportnav->make_active();
 | 
        
           |  |  | 972 |     }
 | 
        
           |  |  | 973 |   | 
        
           |  |  | 974 |     $returnval = $OUTPUT->header();
 | 
        
           |  |  | 975 |   | 
        
           |  |  | 976 |     if (!$return) {
 | 
        
           |  |  | 977 |         echo $returnval;
 | 
        
           |  |  | 978 |     }
 | 
        
           |  |  | 979 |   | 
        
           |  |  | 980 |     if ($shownavigation) {
 | 
        
           |  |  | 981 |         $renderer = $PAGE->get_renderer('core_grades');
 | 
        
           |  |  | 982 |         // If the navigation action bar is not explicitly defined, use the general (default) action bar.
 | 
        
           |  |  | 983 |         if (!$actionbar) {
 | 
        
           |  |  | 984 |             $actionbar = new general_action_bar($PAGE->context, $PAGE->url, $active_type, $active_plugin);
 | 
        
           |  |  | 985 |         }
 | 
        
           |  |  | 986 |   | 
        
           |  |  | 987 |         if ($return) {
 | 
        
           |  |  | 988 |             $returnval .= $renderer->render_action_bar($actionbar);
 | 
        
           |  |  | 989 |         } else {
 | 
        
           |  |  | 990 |             echo $renderer->render_action_bar($actionbar);
 | 
        
           |  |  | 991 |         }
 | 
        
           |  |  | 992 |     }
 | 
        
           |  |  | 993 |   | 
        
           |  |  | 994 |     $output = '';
 | 
        
           |  |  | 995 |     // Add a help dialogue box if provided.
 | 
        
           |  |  | 996 |     if (isset($headerhelpidentifier) && !empty($heading)) {
 | 
        
           |  |  | 997 |         $output = $OUTPUT->heading_with_help($heading, $headerhelpidentifier, $headerhelpcomponent);
 | 
        
           |  |  | 998 |     } else if (isset($user)) {
 | 
        
           |  |  | 999 |         $renderer = $PAGE->get_renderer('core_grades');
 | 
        
           |  |  | 1000 |         // If the user is viewing their own grade report, no need to show the "Message"
 | 
        
           |  |  | 1001 |         // and "Add to contact" buttons in the user heading.
 | 
        
           |  |  | 1002 |         $showuserbuttons = $user->id != $USER->id && !empty($CFG->messaging) &&
 | 
        
           |  |  | 1003 |             has_capability('moodle/site:sendmessage', $PAGE->context);
 | 
        
           |  |  | 1004 |         $output = $renderer->user_heading($user, $courseid, $showuserbuttons);
 | 
        
           |  |  | 1005 |     } else if (!empty($heading)) {
 | 
        
           |  |  | 1006 |         $output = $OUTPUT->heading($heading);
 | 
        
           |  |  | 1007 |     }
 | 
        
           |  |  | 1008 |   | 
        
           | 1441 | ariadna | 1009 |     // If any grade penalty plugins are enabled, notify the user that grade penalties will not be applied to imported grades.
 | 
        
           |  |  | 1010 |     if ($active_type === 'import') {
 | 
        
           |  |  | 1011 |         foreach (core_plugin_manager::instance()->get_plugins_of_type('gradepenalty') as $plugin) {
 | 
        
           |  |  | 1012 |             if ($plugin->is_enabled()) {
 | 
        
           |  |  | 1013 |                 $output .= $OUTPUT->notification(
 | 
        
           |  |  | 1014 |                     get_string('gradepenalties', 'gradeimport_csv'),
 | 
        
           |  |  | 1015 |                     \core\output\notification::NOTIFY_INFO,
 | 
        
           |  |  | 1016 |                     false,
 | 
        
           |  |  | 1017 |                 );
 | 
        
           |  |  | 1018 |                 break;
 | 
        
           |  |  | 1019 |             }
 | 
        
           |  |  | 1020 |         }
 | 
        
           |  |  | 1021 |     }
 | 
        
           |  |  | 1022 |   | 
        
           | 1 | efrain | 1023 |     if ($return) {
 | 
        
           |  |  | 1024 |         $returnval .= $output;
 | 
        
           |  |  | 1025 |     } else {
 | 
        
           |  |  | 1026 |         echo $output;
 | 
        
           |  |  | 1027 |     }
 | 
        
           |  |  | 1028 |   | 
        
           |  |  | 1029 |     $returnval .= print_natural_aggregation_upgrade_notice($courseid, $coursecontext, $PAGE->url, $return);
 | 
        
           |  |  | 1030 |   | 
        
           |  |  | 1031 |     if ($return) {
 | 
        
           |  |  | 1032 |         return $returnval;
 | 
        
           |  |  | 1033 |     }
 | 
        
           |  |  | 1034 | }
 | 
        
           |  |  | 1035 |   | 
        
           |  |  | 1036 | /**
 | 
        
           |  |  | 1037 |  * Utility class used for return tracking when using edit and other forms in grade plugins
 | 
        
           |  |  | 1038 |  *
 | 
        
           |  |  | 1039 |  * @package core_grades
 | 
        
           |  |  | 1040 |  * @copyright 2009 Nicolas Connault
 | 
        
           |  |  | 1041 |  * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
 | 
        
           |  |  | 1042 |  */
 | 
        
           |  |  | 1043 | class grade_plugin_return {
 | 
        
           |  |  | 1044 |     /**
 | 
        
           |  |  | 1045 |      * Type of grade plugin (e.g. 'edit', 'report')
 | 
        
           |  |  | 1046 |      *
 | 
        
           |  |  | 1047 |      * @var string
 | 
        
           |  |  | 1048 |      */
 | 
        
           |  |  | 1049 |     public $type;
 | 
        
           |  |  | 1050 |     /**
 | 
        
           |  |  | 1051 |      * Name of grade plugin (e.g. 'grader', 'overview')
 | 
        
           |  |  | 1052 |      *
 | 
        
           |  |  | 1053 |      * @var string
 | 
        
           |  |  | 1054 |      */
 | 
        
           |  |  | 1055 |     public $plugin;
 | 
        
           |  |  | 1056 |     /**
 | 
        
           |  |  | 1057 |      * Course id being viewed
 | 
        
           |  |  | 1058 |      *
 | 
        
           |  |  | 1059 |      * @var int
 | 
        
           |  |  | 1060 |      */
 | 
        
           |  |  | 1061 |     public $courseid;
 | 
        
           |  |  | 1062 |     /**
 | 
        
           |  |  | 1063 |      * Id of user whose information is being viewed/edited
 | 
        
           |  |  | 1064 |      *
 | 
        
           |  |  | 1065 |      * @var int
 | 
        
           |  |  | 1066 |      */
 | 
        
           |  |  | 1067 |     public $userid;
 | 
        
           |  |  | 1068 |     /**
 | 
        
           |  |  | 1069 |      * Id of group for which information is being viewed/edited
 | 
        
           |  |  | 1070 |      *
 | 
        
           |  |  | 1071 |      * @var int
 | 
        
           |  |  | 1072 |      */
 | 
        
           |  |  | 1073 |     public $groupid;
 | 
        
           |  |  | 1074 |     /**
 | 
        
           |  |  | 1075 |      * Current page # within output
 | 
        
           |  |  | 1076 |      *
 | 
        
           |  |  | 1077 |      * @var int
 | 
        
           |  |  | 1078 |      */
 | 
        
           |  |  | 1079 |     public $page;
 | 
        
           |  |  | 1080 |     /**
 | 
        
           |  |  | 1081 |      * Search string
 | 
        
           |  |  | 1082 |      *
 | 
        
           |  |  | 1083 |      * @var string
 | 
        
           |  |  | 1084 |      */
 | 
        
           |  |  | 1085 |     public $search;
 | 
        
           |  |  | 1086 |   | 
        
           |  |  | 1087 |     /**
 | 
        
           |  |  | 1088 |      * Constructor
 | 
        
           |  |  | 1089 |      *
 | 
        
           |  |  | 1090 |      * @param array $params - associative array with return parameters, if not supplied parameter are taken from _GET or _POST
 | 
        
           |  |  | 1091 |      */
 | 
        
           |  |  | 1092 |     public function __construct($params = []) {
 | 
        
           |  |  | 1093 |         $this->type     = optional_param('gpr_type', null, PARAM_SAFEDIR);
 | 
        
           |  |  | 1094 |         $this->plugin   = optional_param('gpr_plugin', null, PARAM_PLUGIN);
 | 
        
           |  |  | 1095 |         $this->courseid = optional_param('gpr_courseid', null, PARAM_INT);
 | 
        
           |  |  | 1096 |         $this->userid   = optional_param('gpr_userid', null, PARAM_INT);
 | 
        
           |  |  | 1097 |         $this->groupid  = optional_param('gpr_groupid', null, PARAM_INT);
 | 
        
           |  |  | 1098 |         $this->page     = optional_param('gpr_page', null, PARAM_INT);
 | 
        
           |  |  | 1099 |         $this->search   = optional_param('gpr_search', '', PARAM_NOTAGS);
 | 
        
           |  |  | 1100 |   | 
        
           |  |  | 1101 |         foreach ($params as $key => $value) {
 | 
        
           |  |  | 1102 |             if (property_exists($this, $key)) {
 | 
        
           |  |  | 1103 |                 $this->$key = $value;
 | 
        
           |  |  | 1104 |             }
 | 
        
           |  |  | 1105 |         }
 | 
        
           |  |  | 1106 |         // Allow course object rather than id to be used to specify course
 | 
        
           |  |  | 1107 |         // - avoid unnecessary use of get_course.
 | 
        
           |  |  | 1108 |         if (array_key_exists('course', $params)) {
 | 
        
           |  |  | 1109 |             $course = $params['course'];
 | 
        
           |  |  | 1110 |             $this->courseid = $course->id;
 | 
        
           |  |  | 1111 |         } else {
 | 
        
           |  |  | 1112 |             $course = null;
 | 
        
           |  |  | 1113 |         }
 | 
        
           |  |  | 1114 |         // If group has been explicitly set in constructor parameters,
 | 
        
           |  |  | 1115 |         // we should respect that.
 | 
        
           |  |  | 1116 |         if (!array_key_exists('groupid', $params)) {
 | 
        
           |  |  | 1117 |             // Otherwise, 'group' in request parameters is a request for a change.
 | 
        
           |  |  | 1118 |             // In that case, or if we have no group at all, we should get groupid from
 | 
        
           |  |  | 1119 |             // groups_get_course_group, which will do some housekeeping as well as
 | 
        
           |  |  | 1120 |             // give us the correct value.
 | 
        
           |  |  | 1121 |             $changegroup = optional_param('group', -1, PARAM_INT);
 | 
        
           |  |  | 1122 |             if ($changegroup !== -1 or (empty($this->groupid) and !empty($this->courseid))) {
 | 
        
           |  |  | 1123 |                 if ($course === null) {
 | 
        
           |  |  | 1124 |                     $course = get_course($this->courseid);
 | 
        
           |  |  | 1125 |                 }
 | 
        
           |  |  | 1126 |                 $this->groupid = groups_get_course_group($course, true);
 | 
        
           |  |  | 1127 |             }
 | 
        
           |  |  | 1128 |         }
 | 
        
           |  |  | 1129 |     }
 | 
        
           |  |  | 1130 |   | 
        
           |  |  | 1131 |     /**
 | 
        
           |  |  | 1132 |      * Old syntax of class constructor. Deprecated in PHP7.
 | 
        
           |  |  | 1133 |      *
 | 
        
           |  |  | 1134 |      * @deprecated since Moodle 3.1
 | 
        
           |  |  | 1135 |      */
 | 
        
           |  |  | 1136 |     public function grade_plugin_return($params = null) {
 | 
        
           |  |  | 1137 |         debugging('Use of class name as constructor is deprecated', DEBUG_DEVELOPER);
 | 
        
           |  |  | 1138 |         self::__construct($params);
 | 
        
           |  |  | 1139 |     }
 | 
        
           |  |  | 1140 |   | 
        
           |  |  | 1141 |     /**
 | 
        
           |  |  | 1142 |      * Returns return parameters as options array suitable for buttons.
 | 
        
           |  |  | 1143 |      * @return array options
 | 
        
           |  |  | 1144 |      */
 | 
        
           |  |  | 1145 |     public function get_options() {
 | 
        
           |  |  | 1146 |         if (empty($this->type)) {
 | 
        
           |  |  | 1147 |             return array();
 | 
        
           |  |  | 1148 |         }
 | 
        
           |  |  | 1149 |   | 
        
           |  |  | 1150 |         $params = array();
 | 
        
           |  |  | 1151 |   | 
        
           |  |  | 1152 |         if (!empty($this->plugin)) {
 | 
        
           |  |  | 1153 |             $params['plugin'] = $this->plugin;
 | 
        
           |  |  | 1154 |         }
 | 
        
           |  |  | 1155 |   | 
        
           |  |  | 1156 |         if (!empty($this->courseid)) {
 | 
        
           |  |  | 1157 |             $params['id'] = $this->courseid;
 | 
        
           |  |  | 1158 |         }
 | 
        
           |  |  | 1159 |   | 
        
           |  |  | 1160 |         if (!empty($this->userid)) {
 | 
        
           |  |  | 1161 |             $params['userid'] = $this->userid;
 | 
        
           |  |  | 1162 |         }
 | 
        
           |  |  | 1163 |   | 
        
           |  |  | 1164 |         if (!empty($this->groupid)) {
 | 
        
           |  |  | 1165 |             $params['group'] = $this->groupid;
 | 
        
           |  |  | 1166 |         }
 | 
        
           |  |  | 1167 |   | 
        
           |  |  | 1168 |         if (!empty($this->page)) {
 | 
        
           |  |  | 1169 |             $params['page'] = $this->page;
 | 
        
           |  |  | 1170 |         }
 | 
        
           |  |  | 1171 |   | 
        
           |  |  | 1172 |         return $params;
 | 
        
           |  |  | 1173 |     }
 | 
        
           |  |  | 1174 |   | 
        
           |  |  | 1175 |     /**
 | 
        
           |  |  | 1176 |      * Returns return url
 | 
        
           |  |  | 1177 |      *
 | 
        
           |  |  | 1178 |      * @param string $default default url when params not set
 | 
        
           |  |  | 1179 |      * @param array  $extras Extra URL parameters
 | 
        
           |  |  | 1180 |      *
 | 
        
           |  |  | 1181 |      * @return string url
 | 
        
           |  |  | 1182 |      */
 | 
        
           |  |  | 1183 |     public function get_return_url($default, $extras=null) {
 | 
        
           |  |  | 1184 |         global $CFG;
 | 
        
           |  |  | 1185 |   | 
        
           |  |  | 1186 |         if (empty($this->type) or empty($this->plugin)) {
 | 
        
           |  |  | 1187 |             return $default;
 | 
        
           |  |  | 1188 |         }
 | 
        
           |  |  | 1189 |   | 
        
           |  |  | 1190 |         $url = $CFG->wwwroot.'/grade/'.$this->type.'/'.$this->plugin.'/index.php';
 | 
        
           |  |  | 1191 |         $glue = '?';
 | 
        
           |  |  | 1192 |   | 
        
           |  |  | 1193 |         if (!empty($this->courseid)) {
 | 
        
           |  |  | 1194 |             $url .= $glue.'id='.$this->courseid;
 | 
        
           |  |  | 1195 |             $glue = '&';
 | 
        
           |  |  | 1196 |         }
 | 
        
           |  |  | 1197 |   | 
        
           |  |  | 1198 |         if (!empty($this->userid)) {
 | 
        
           |  |  | 1199 |             $url .= $glue.'userid='.$this->userid;
 | 
        
           |  |  | 1200 |             $glue = '&';
 | 
        
           |  |  | 1201 |         }
 | 
        
           |  |  | 1202 |   | 
        
           |  |  | 1203 |         if (!empty($this->groupid)) {
 | 
        
           |  |  | 1204 |             $url .= $glue.'group='.$this->groupid;
 | 
        
           |  |  | 1205 |             $glue = '&';
 | 
        
           |  |  | 1206 |         }
 | 
        
           |  |  | 1207 |   | 
        
           |  |  | 1208 |         if (!empty($this->page)) {
 | 
        
           |  |  | 1209 |             $url .= $glue.'page='.$this->page;
 | 
        
           |  |  | 1210 |             $glue = '&';
 | 
        
           |  |  | 1211 |         }
 | 
        
           |  |  | 1212 |   | 
        
           |  |  | 1213 |         if (!empty($extras)) {
 | 
        
           |  |  | 1214 |             foreach ($extras as $key=>$value) {
 | 
        
           |  |  | 1215 |                 $url .= $glue.$key.'='.$value;
 | 
        
           |  |  | 1216 |                 $glue = '&';
 | 
        
           |  |  | 1217 |             }
 | 
        
           |  |  | 1218 |         }
 | 
        
           |  |  | 1219 |   | 
        
           |  |  | 1220 |         return $url;
 | 
        
           |  |  | 1221 |     }
 | 
        
           |  |  | 1222 |   | 
        
           |  |  | 1223 |     /**
 | 
        
           |  |  | 1224 |      * Returns string with hidden return tracking form elements.
 | 
        
           |  |  | 1225 |      * @return string
 | 
        
           |  |  | 1226 |      */
 | 
        
           |  |  | 1227 |     public function get_form_fields() {
 | 
        
           |  |  | 1228 |         if (empty($this->type)) {
 | 
        
           |  |  | 1229 |             return '';
 | 
        
           |  |  | 1230 |         }
 | 
        
           |  |  | 1231 |   | 
        
           |  |  | 1232 |         $result  = '<input type="hidden" name="gpr_type" value="'.$this->type.'" />';
 | 
        
           |  |  | 1233 |   | 
        
           |  |  | 1234 |         if (!empty($this->plugin)) {
 | 
        
           |  |  | 1235 |             $result .= '<input type="hidden" name="gpr_plugin" value="'.$this->plugin.'" />';
 | 
        
           |  |  | 1236 |         }
 | 
        
           |  |  | 1237 |   | 
        
           |  |  | 1238 |         if (!empty($this->courseid)) {
 | 
        
           |  |  | 1239 |             $result .= '<input type="hidden" name="gpr_courseid" value="'.$this->courseid.'" />';
 | 
        
           |  |  | 1240 |         }
 | 
        
           |  |  | 1241 |   | 
        
           |  |  | 1242 |         if (!empty($this->userid)) {
 | 
        
           |  |  | 1243 |             $result .= '<input type="hidden" name="gpr_userid" value="'.$this->userid.'" />';
 | 
        
           |  |  | 1244 |         }
 | 
        
           |  |  | 1245 |   | 
        
           |  |  | 1246 |         if (!empty($this->groupid)) {
 | 
        
           |  |  | 1247 |             $result .= '<input type="hidden" name="gpr_groupid" value="'.$this->groupid.'" />';
 | 
        
           |  |  | 1248 |         }
 | 
        
           |  |  | 1249 |   | 
        
           |  |  | 1250 |         if (!empty($this->page)) {
 | 
        
           |  |  | 1251 |             $result .= '<input type="hidden" name="gpr_page" value="'.$this->page.'" />';
 | 
        
           |  |  | 1252 |         }
 | 
        
           |  |  | 1253 |   | 
        
           |  |  | 1254 |         if (!empty($this->search)) {
 | 
        
           |  |  | 1255 |             $result .= html_writer::empty_tag('input',
 | 
        
           |  |  | 1256 |                 ['type' => 'hidden', 'name' => 'gpr_search', 'value' => $this->search]);
 | 
        
           |  |  | 1257 |         }
 | 
        
           |  |  | 1258 |   | 
        
           |  |  | 1259 |         return $result;
 | 
        
           |  |  | 1260 |     }
 | 
        
           |  |  | 1261 |   | 
        
           |  |  | 1262 |     /**
 | 
        
           |  |  | 1263 |      * Add hidden elements into mform
 | 
        
           |  |  | 1264 |      *
 | 
        
           |  |  | 1265 |      * @param object &$mform moodle form object
 | 
        
           |  |  | 1266 |      *
 | 
        
           |  |  | 1267 |      * @return void
 | 
        
           |  |  | 1268 |      */
 | 
        
           |  |  | 1269 |     public function add_mform_elements(&$mform) {
 | 
        
           |  |  | 1270 |         if (empty($this->type)) {
 | 
        
           |  |  | 1271 |             return;
 | 
        
           |  |  | 1272 |         }
 | 
        
           |  |  | 1273 |   | 
        
           |  |  | 1274 |         $mform->addElement('hidden', 'gpr_type', $this->type);
 | 
        
           |  |  | 1275 |         $mform->setType('gpr_type', PARAM_SAFEDIR);
 | 
        
           |  |  | 1276 |   | 
        
           |  |  | 1277 |         if (!empty($this->plugin)) {
 | 
        
           |  |  | 1278 |             $mform->addElement('hidden', 'gpr_plugin', $this->plugin);
 | 
        
           |  |  | 1279 |             $mform->setType('gpr_plugin', PARAM_PLUGIN);
 | 
        
           |  |  | 1280 |         }
 | 
        
           |  |  | 1281 |   | 
        
           |  |  | 1282 |         if (!empty($this->courseid)) {
 | 
        
           |  |  | 1283 |             $mform->addElement('hidden', 'gpr_courseid', $this->courseid);
 | 
        
           |  |  | 1284 |             $mform->setType('gpr_courseid', PARAM_INT);
 | 
        
           |  |  | 1285 |         }
 | 
        
           |  |  | 1286 |   | 
        
           |  |  | 1287 |         if (!empty($this->userid)) {
 | 
        
           |  |  | 1288 |             $mform->addElement('hidden', 'gpr_userid', $this->userid);
 | 
        
           |  |  | 1289 |             $mform->setType('gpr_userid', PARAM_INT);
 | 
        
           |  |  | 1290 |         }
 | 
        
           |  |  | 1291 |   | 
        
           |  |  | 1292 |         if (!empty($this->groupid)) {
 | 
        
           |  |  | 1293 |             $mform->addElement('hidden', 'gpr_groupid', $this->groupid);
 | 
        
           |  |  | 1294 |             $mform->setType('gpr_groupid', PARAM_INT);
 | 
        
           |  |  | 1295 |         }
 | 
        
           |  |  | 1296 |   | 
        
           |  |  | 1297 |         if (!empty($this->page)) {
 | 
        
           |  |  | 1298 |             $mform->addElement('hidden', 'gpr_page', $this->page);
 | 
        
           |  |  | 1299 |             $mform->setType('gpr_page', PARAM_INT);
 | 
        
           |  |  | 1300 |         }
 | 
        
           |  |  | 1301 |     }
 | 
        
           |  |  | 1302 |   | 
        
           |  |  | 1303 |     /**
 | 
        
           |  |  | 1304 |      * Add return tracking params into url
 | 
        
           |  |  | 1305 |      *
 | 
        
           |  |  | 1306 |      * @param moodle_url $url A URL
 | 
        
           |  |  | 1307 |      * @return moodle_url with return tracking params
 | 
        
           |  |  | 1308 |      */
 | 
        
           |  |  | 1309 |     public function add_url_params(moodle_url $url): moodle_url {
 | 
        
           |  |  | 1310 |         if (empty($this->type)) {
 | 
        
           |  |  | 1311 |             return $url;
 | 
        
           |  |  | 1312 |         }
 | 
        
           |  |  | 1313 |   | 
        
           |  |  | 1314 |         $url->param('gpr_type', $this->type);
 | 
        
           |  |  | 1315 |   | 
        
           |  |  | 1316 |         if (!empty($this->plugin)) {
 | 
        
           |  |  | 1317 |             $url->param('gpr_plugin', $this->plugin);
 | 
        
           |  |  | 1318 |         }
 | 
        
           |  |  | 1319 |   | 
        
           |  |  | 1320 |         if (!empty($this->courseid)) {
 | 
        
           |  |  | 1321 |             $url->param('gpr_courseid' ,$this->courseid);
 | 
        
           |  |  | 1322 |         }
 | 
        
           |  |  | 1323 |   | 
        
           |  |  | 1324 |         if (!empty($this->userid)) {
 | 
        
           |  |  | 1325 |             $url->param('gpr_userid', $this->userid);
 | 
        
           |  |  | 1326 |         }
 | 
        
           |  |  | 1327 |   | 
        
           |  |  | 1328 |         if (!empty($this->groupid)) {
 | 
        
           |  |  | 1329 |             $url->param('gpr_groupid', $this->groupid);
 | 
        
           |  |  | 1330 |         }
 | 
        
           |  |  | 1331 |   | 
        
           |  |  | 1332 |         if (!empty($this->page)) {
 | 
        
           |  |  | 1333 |             $url->param('gpr_page', $this->page);
 | 
        
           |  |  | 1334 |         }
 | 
        
           |  |  | 1335 |   | 
        
           |  |  | 1336 |         return $url;
 | 
        
           |  |  | 1337 |     }
 | 
        
           |  |  | 1338 | }
 | 
        
           |  |  | 1339 |   | 
        
           |  |  | 1340 | /**
 | 
        
           |  |  | 1341 |  * Function central to gradebook for building and printing the navigation (breadcrumb trail).
 | 
        
           |  |  | 1342 |  *
 | 
        
           |  |  | 1343 |  * @param string $path The path of the calling script (using __FILE__?)
 | 
        
           |  |  | 1344 |  * @param string $pagename The language string to use as the last part of the navigation (non-link)
 | 
        
           |  |  | 1345 |  * @param mixed  $id Either a plain integer (assuming the key is 'id') or
 | 
        
           |  |  | 1346 |  *                   an array of keys and values (e.g courseid => $courseid, itemid...)
 | 
        
           |  |  | 1347 |  *
 | 
        
           |  |  | 1348 |  * @return string
 | 
        
           |  |  | 1349 |  */
 | 
        
           |  |  | 1350 | function grade_build_nav($path, $pagename=null, $id=null) {
 | 
        
           |  |  | 1351 |     global $CFG, $COURSE, $PAGE;
 | 
        
           |  |  | 1352 |   | 
        
           |  |  | 1353 |     $strgrades = get_string('grades', 'grades');
 | 
        
           |  |  | 1354 |   | 
        
           |  |  | 1355 |     // Parse the path and build navlinks from its elements
 | 
        
           |  |  | 1356 |     $dirroot_length = strlen($CFG->dirroot) + 1; // Add 1 for the first slash
 | 
        
           |  |  | 1357 |     $path = substr($path, $dirroot_length);
 | 
        
           |  |  | 1358 |     $path = str_replace('\\', '/', $path);
 | 
        
           |  |  | 1359 |   | 
        
           |  |  | 1360 |     $path_elements = explode('/', $path);
 | 
        
           |  |  | 1361 |   | 
        
           |  |  | 1362 |     $path_elements_count = count($path_elements);
 | 
        
           |  |  | 1363 |   | 
        
           |  |  | 1364 |     // First link is always 'grade'
 | 
        
           |  |  | 1365 |     $PAGE->navbar->add($strgrades, new moodle_url('/grade/index.php', array('id'=>$COURSE->id)));
 | 
        
           |  |  | 1366 |   | 
        
           |  |  | 1367 |     $link = null;
 | 
        
           |  |  | 1368 |     $numberofelements = 3;
 | 
        
           |  |  | 1369 |   | 
        
           |  |  | 1370 |     // Prepare URL params string
 | 
        
           |  |  | 1371 |     $linkparams = array();
 | 
        
           |  |  | 1372 |     if (!is_null($id)) {
 | 
        
           |  |  | 1373 |         if (is_array($id)) {
 | 
        
           |  |  | 1374 |             foreach ($id as $idkey => $idvalue) {
 | 
        
           |  |  | 1375 |                 $linkparams[$idkey] = $idvalue;
 | 
        
           |  |  | 1376 |             }
 | 
        
           |  |  | 1377 |         } else {
 | 
        
           |  |  | 1378 |             $linkparams['id'] = $id;
 | 
        
           |  |  | 1379 |         }
 | 
        
           |  |  | 1380 |     }
 | 
        
           |  |  | 1381 |   | 
        
           |  |  | 1382 |     $navlink4 = null;
 | 
        
           |  |  | 1383 |   | 
        
           |  |  | 1384 |     // Remove file extensions from filenames
 | 
        
           |  |  | 1385 |     foreach ($path_elements as $key => $filename) {
 | 
        
           |  |  | 1386 |         $path_elements[$key] = str_replace('.php', '', $filename);
 | 
        
           |  |  | 1387 |     }
 | 
        
           |  |  | 1388 |   | 
        
           |  |  | 1389 |     // Second level links
 | 
        
           |  |  | 1390 |     switch ($path_elements[1]) {
 | 
        
           |  |  | 1391 |         case 'edit': // No link
 | 
        
           |  |  | 1392 |             if ($path_elements[3] != 'index.php') {
 | 
        
           |  |  | 1393 |                 $numberofelements = 4;
 | 
        
           |  |  | 1394 |             }
 | 
        
           |  |  | 1395 |             break;
 | 
        
           |  |  | 1396 |         case 'import': // No link
 | 
        
           |  |  | 1397 |             break;
 | 
        
           |  |  | 1398 |         case 'export': // No link
 | 
        
           |  |  | 1399 |             break;
 | 
        
           |  |  | 1400 |         case 'report':
 | 
        
           |  |  | 1401 |             // $id is required for this link. Do not print it if $id isn't given
 | 
        
           |  |  | 1402 |             if (!is_null($id)) {
 | 
        
           |  |  | 1403 |                 $link = new moodle_url('/grade/report/index.php', $linkparams);
 | 
        
           |  |  | 1404 |             }
 | 
        
           |  |  | 1405 |   | 
        
           |  |  | 1406 |             if ($path_elements[2] == 'grader') {
 | 
        
           |  |  | 1407 |                 $numberofelements = 4;
 | 
        
           |  |  | 1408 |             }
 | 
        
           |  |  | 1409 |             break;
 | 
        
           |  |  | 1410 |   | 
        
           |  |  | 1411 |         default:
 | 
        
           |  |  | 1412 |             // If this element isn't among the ones already listed above, it isn't supported, throw an error.
 | 
        
           |  |  | 1413 |             debugging("grade_build_nav() doesn't support ". $path_elements[1] .
 | 
        
           |  |  | 1414 |                     " as the second path element after 'grade'.");
 | 
        
           |  |  | 1415 |             return false;
 | 
        
           |  |  | 1416 |     }
 | 
        
           |  |  | 1417 |     $PAGE->navbar->add(get_string($path_elements[1], 'grades'), $link);
 | 
        
           |  |  | 1418 |   | 
        
           |  |  | 1419 |     // Third level links
 | 
        
           |  |  | 1420 |     if (empty($pagename)) {
 | 
        
           |  |  | 1421 |         $pagename = get_string($path_elements[2], 'grades');
 | 
        
           |  |  | 1422 |     }
 | 
        
           |  |  | 1423 |   | 
        
           |  |  | 1424 |     switch ($numberofelements) {
 | 
        
           |  |  | 1425 |         case 3:
 | 
        
           |  |  | 1426 |             $PAGE->navbar->add($pagename, $link);
 | 
        
           |  |  | 1427 |             break;
 | 
        
           |  |  | 1428 |         case 4:
 | 
        
           |  |  | 1429 |             if ($path_elements[2] == 'grader' AND $path_elements[3] != 'index.php') {
 | 
        
           |  |  | 1430 |                 $PAGE->navbar->add(get_string('pluginname', 'gradereport_grader'), new moodle_url('/grade/report/grader/index.php', $linkparams));
 | 
        
           |  |  | 1431 |             }
 | 
        
           |  |  | 1432 |             $PAGE->navbar->add($pagename);
 | 
        
           |  |  | 1433 |             break;
 | 
        
           |  |  | 1434 |     }
 | 
        
           |  |  | 1435 |   | 
        
           |  |  | 1436 |     return '';
 | 
        
           |  |  | 1437 | }
 | 
        
           |  |  | 1438 |   | 
        
           |  |  | 1439 | /**
 | 
        
           |  |  | 1440 |  * General structure representing grade items in course
 | 
        
           |  |  | 1441 |  *
 | 
        
           |  |  | 1442 |  * @package core_grades
 | 
        
           |  |  | 1443 |  * @copyright 2009 Nicolas Connault
 | 
        
           |  |  | 1444 |  * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
 | 
        
           |  |  | 1445 |  */
 | 
        
           |  |  | 1446 | class grade_structure {
 | 
        
           |  |  | 1447 |     public $context;
 | 
        
           |  |  | 1448 |   | 
        
           |  |  | 1449 |     public $courseid;
 | 
        
           |  |  | 1450 |   | 
        
           |  |  | 1451 |     /**
 | 
        
           |  |  | 1452 |     * Reference to modinfo for current course (for performance, to save
 | 
        
           |  |  | 1453 |     * retrieving it from courseid every time). Not actually set except for
 | 
        
           |  |  | 1454 |     * the grade_tree type.
 | 
        
           |  |  | 1455 |     * @var course_modinfo
 | 
        
           |  |  | 1456 |     */
 | 
        
           |  |  | 1457 |     public $modinfo;
 | 
        
           |  |  | 1458 |   | 
        
           |  |  | 1459 |     /**
 | 
        
           |  |  | 1460 |      * 1D array of grade items only
 | 
        
           |  |  | 1461 |      */
 | 
        
           |  |  | 1462 |     public $items;
 | 
        
           |  |  | 1463 |   | 
        
           |  |  | 1464 |     /**
 | 
        
           |  |  | 1465 |      * @deprecated since Moodle 4.4 - please use {@see grade_helper::get_element_icon()}
 | 
        
           |  |  | 1466 |      */
 | 
        
           | 1441 | ariadna | 1467 |     #[\core\attribute\deprecated('grade_helper::get_element_icon', since: '4.4', mdl: 'MDL-77326', final: true)]
 | 
        
           |  |  | 1468 |     public function get_element_icon(): void {
 | 
        
           |  |  | 1469 |         \core\deprecation::emit_deprecation([self::class, __FUNCTION__]);
 | 
        
           | 1 | efrain | 1470 |     }
 | 
        
           |  |  | 1471 |   | 
        
           |  |  | 1472 |     /**
 | 
        
           |  |  | 1473 |      * @deprecated since Moodle 4.4 - please use {@see grade_helper::get_element_type_string()}
 | 
        
           |  |  | 1474 |      */
 | 
        
           | 1441 | ariadna | 1475 |     #[\core\attribute\deprecated('grade_helper::get_element_type_string', since: '4.4', mdl: 'MDL-77326', final: true)]
 | 
        
           |  |  | 1476 |     public function get_element_type_string(): void {
 | 
        
           |  |  | 1477 |         \core\deprecation::emit_deprecation([self::class, __FUNCTION__]);
 | 
        
           | 1 | efrain | 1478 |     }
 | 
        
           |  |  | 1479 |   | 
        
           |  |  | 1480 |     /**
 | 
        
           |  |  | 1481 |      * @deprecated since Moodle 4.4 - please use {@see grade_helper::get_element_header()}
 | 
        
           |  |  | 1482 |      */
 | 
        
           | 1441 | ariadna | 1483 |     #[\core\attribute\deprecated('grade_helper::get_element_header', since: '4.4', mdl: 'MDL-77326', final: true)]
 | 
        
           |  |  | 1484 |     public function get_element_header(): void {
 | 
        
           |  |  | 1485 |         \core\deprecation::emit_deprecation([self::class, __FUNCTION__]);
 | 
        
           | 1 | efrain | 1486 |     }
 | 
        
           |  |  | 1487 |   | 
        
           |  |  | 1488 |     /**
 | 
        
           |  |  | 1489 |      * @deprecated since Moodle 4.4 - please use {@see grade_helper::get_activity_link()}
 | 
        
           |  |  | 1490 |      */
 | 
        
           | 1441 | ariadna | 1491 |     #[\core\attribute\deprecated('grade_helper::get_activity_link', since: '4.4', mdl: 'MDL-77326', final: true)]
 | 
        
           |  |  | 1492 |     private function get_activity_link(): void {
 | 
        
           |  |  | 1493 |         \core\deprecation::emit_deprecation([self::class, __FUNCTION__]);
 | 
        
           | 1 | efrain | 1494 |     }
 | 
        
           |  |  | 1495 |   | 
        
           |  |  | 1496 |     /**
 | 
        
           |  |  | 1497 |      * Returns URL of a page that is supposed to contain detailed grade analysis
 | 
        
           |  |  | 1498 |      *
 | 
        
           |  |  | 1499 |      * At the moment, only activity modules are supported. The method generates link
 | 
        
           |  |  | 1500 |      * to the module's file grade.php with the parameters id (cmid), itemid, itemnumber,
 | 
        
           |  |  | 1501 |      * gradeid and userid. If the grade.php does not exist, null is returned.
 | 
        
           |  |  | 1502 |      *
 | 
        
           |  |  | 1503 |      * @return moodle_url|null URL or null if unable to construct it
 | 
        
           |  |  | 1504 |      */
 | 
        
           |  |  | 1505 |     public function get_grade_analysis_url(grade_grade $grade) {
 | 
        
           |  |  | 1506 |         global $CFG;
 | 
        
           |  |  | 1507 |         /** @var array static cache of the grade.php file existence flags */
 | 
        
           |  |  | 1508 |         static $hasgradephp = array();
 | 
        
           |  |  | 1509 |   | 
        
           |  |  | 1510 |         if (empty($grade->grade_item) or !($grade->grade_item instanceof grade_item)) {
 | 
        
           |  |  | 1511 |             throw new coding_exception('Passed grade without the associated grade item');
 | 
        
           |  |  | 1512 |         }
 | 
        
           |  |  | 1513 |         $item = $grade->grade_item;
 | 
        
           |  |  | 1514 |   | 
        
           |  |  | 1515 |         if (!$item->is_external_item()) {
 | 
        
           |  |  | 1516 |             // at the moment, only activity modules are supported
 | 
        
           |  |  | 1517 |             return null;
 | 
        
           |  |  | 1518 |         }
 | 
        
           |  |  | 1519 |         if ($item->itemtype !== 'mod') {
 | 
        
           |  |  | 1520 |             throw new coding_exception('Unknown external itemtype: '.$item->itemtype);
 | 
        
           |  |  | 1521 |         }
 | 
        
           |  |  | 1522 |         if (empty($item->iteminstance) or empty($item->itemmodule) or empty($this->modinfo)) {
 | 
        
           |  |  | 1523 |             return null;
 | 
        
           |  |  | 1524 |         }
 | 
        
           |  |  | 1525 |   | 
        
           |  |  | 1526 |         if (!array_key_exists($item->itemmodule, $hasgradephp)) {
 | 
        
           |  |  | 1527 |             if (file_exists($CFG->dirroot . '/mod/' . $item->itemmodule . '/grade.php')) {
 | 
        
           |  |  | 1528 |                 $hasgradephp[$item->itemmodule] = true;
 | 
        
           |  |  | 1529 |             } else {
 | 
        
           |  |  | 1530 |                 $hasgradephp[$item->itemmodule] = false;
 | 
        
           |  |  | 1531 |             }
 | 
        
           |  |  | 1532 |         }
 | 
        
           |  |  | 1533 |   | 
        
           |  |  | 1534 |         if (!$hasgradephp[$item->itemmodule]) {
 | 
        
           |  |  | 1535 |             return null;
 | 
        
           |  |  | 1536 |         }
 | 
        
           |  |  | 1537 |   | 
        
           |  |  | 1538 |         $instances = $this->modinfo->get_instances();
 | 
        
           |  |  | 1539 |         if (empty($instances[$item->itemmodule][$item->iteminstance])) {
 | 
        
           |  |  | 1540 |             return null;
 | 
        
           |  |  | 1541 |         }
 | 
        
           |  |  | 1542 |         $cm = $instances[$item->itemmodule][$item->iteminstance];
 | 
        
           |  |  | 1543 |         if (!$cm->uservisible) {
 | 
        
           |  |  | 1544 |             return null;
 | 
        
           |  |  | 1545 |         }
 | 
        
           |  |  | 1546 |   | 
        
           |  |  | 1547 |         $url = new moodle_url('/mod/'.$item->itemmodule.'/grade.php', array(
 | 
        
           |  |  | 1548 |             'id'         => $cm->id,
 | 
        
           |  |  | 1549 |             'itemid'     => $item->id,
 | 
        
           |  |  | 1550 |             'itemnumber' => $item->itemnumber,
 | 
        
           |  |  | 1551 |             'gradeid'    => $grade->id,
 | 
        
           |  |  | 1552 |             'userid'     => $grade->userid,
 | 
        
           |  |  | 1553 |         ));
 | 
        
           |  |  | 1554 |   | 
        
           |  |  | 1555 |         return $url;
 | 
        
           |  |  | 1556 |     }
 | 
        
           |  |  | 1557 |   | 
        
           |  |  | 1558 |     /**
 | 
        
           |  |  | 1559 |      * Returns an action icon leading to the grade analysis page
 | 
        
           |  |  | 1560 |      *
 | 
        
           |  |  | 1561 |      * @param grade_grade $grade
 | 
        
           |  |  | 1562 |      * @return string
 | 
        
           |  |  | 1563 |      * @deprecated since Moodle 4.2 - The row is not shown anymore - we have actions menu.
 | 
        
           |  |  | 1564 |      * @todo MDL-77307 This will be deleted in Moodle 4.6.
 | 
        
           |  |  | 1565 |      */
 | 
        
           |  |  | 1566 |     public function get_grade_analysis_icon(grade_grade $grade) {
 | 
        
           |  |  | 1567 |         global $OUTPUT;
 | 
        
           |  |  | 1568 |         debugging('The function get_grade_analysis_icon() is deprecated, please do not use it anymore.',
 | 
        
           |  |  | 1569 |             DEBUG_DEVELOPER);
 | 
        
           |  |  | 1570 |   | 
        
           |  |  | 1571 |         $url = $this->get_grade_analysis_url($grade);
 | 
        
           |  |  | 1572 |         if (is_null($url)) {
 | 
        
           |  |  | 1573 |             return '';
 | 
        
           |  |  | 1574 |         }
 | 
        
           |  |  | 1575 |   | 
        
           |  |  | 1576 |         $title = get_string('gradeanalysis', 'core_grades');
 | 
        
           |  |  | 1577 |         return $OUTPUT->action_icon($url, new pix_icon('t/preview', ''), null,
 | 
        
           |  |  | 1578 |                 ['title' => $title, 'aria-label' => $title]);
 | 
        
           |  |  | 1579 |     }
 | 
        
           |  |  | 1580 |   | 
        
           |  |  | 1581 |     /**
 | 
        
           |  |  | 1582 |      * Returns a link leading to the grade analysis page
 | 
        
           |  |  | 1583 |      *
 | 
        
           |  |  | 1584 |      * @param grade_grade $grade
 | 
        
           |  |  | 1585 |      * @return string|null
 | 
        
           |  |  | 1586 |      */
 | 
        
           |  |  | 1587 |     public function get_grade_analysis_link(grade_grade $grade): ?string {
 | 
        
           |  |  | 1588 |         $url = $this->get_grade_analysis_url($grade);
 | 
        
           |  |  | 1589 |         if (is_null($url)) {
 | 
        
           |  |  | 1590 |             return null;
 | 
        
           |  |  | 1591 |         }
 | 
        
           |  |  | 1592 |   | 
        
           |  |  | 1593 |         $gradeanalysisstring = get_string('gradeanalysis', 'grades');
 | 
        
           |  |  | 1594 |         return html_writer::link($url, $gradeanalysisstring,
 | 
        
           |  |  | 1595 |             ['class' => 'dropdown-item', 'aria-label' => $gradeanalysisstring, 'role' => 'menuitem']);
 | 
        
           |  |  | 1596 |     }
 | 
        
           |  |  | 1597 |   | 
        
           |  |  | 1598 |     /**
 | 
        
           |  |  | 1599 |      * Returns an action menu for the grade.
 | 
        
           |  |  | 1600 |      *
 | 
        
           |  |  | 1601 |      * @param grade_grade $grade A grade_grade object
 | 
        
           |  |  | 1602 |      * @return string
 | 
        
           |  |  | 1603 |      */
 | 
        
           |  |  | 1604 |     public function get_grade_action_menu(grade_grade $grade): string {
 | 
        
           |  |  | 1605 |         global $OUTPUT;
 | 
        
           |  |  | 1606 |   | 
        
           |  |  | 1607 |         $menuitems = [];
 | 
        
           |  |  | 1608 |   | 
        
           |  |  | 1609 |         $url = $this->get_grade_analysis_url($grade);
 | 
        
           |  |  | 1610 |         if ($url) {
 | 
        
           |  |  | 1611 |             $title = get_string('gradeanalysis', 'core_grades');
 | 
        
           |  |  | 1612 |             $menuitems[] = new action_menu_link_secondary($url, null, $title);
 | 
        
           |  |  | 1613 |         }
 | 
        
           |  |  | 1614 |   | 
        
           |  |  | 1615 |         if ($menuitems) {
 | 
        
           |  |  | 1616 |             $menu = new action_menu($menuitems);
 | 
        
           |  |  | 1617 |             $icon = $OUTPUT->pix_icon('i/moremenu', get_string('actions'));
 | 
        
           | 1441 | ariadna | 1618 |             $extraclasses = 'btn btn-link btn-icon d-flex no-caret';
 | 
        
           | 1 | efrain | 1619 |             $menu->set_menu_trigger($icon, $extraclasses);
 | 
        
           |  |  | 1620 |             $menu->set_menu_left();
 | 
        
           |  |  | 1621 |   | 
        
           |  |  | 1622 |             return $OUTPUT->render($menu);
 | 
        
           |  |  | 1623 |         } else {
 | 
        
           |  |  | 1624 |             return '';
 | 
        
           |  |  | 1625 |         }
 | 
        
           |  |  | 1626 |     }
 | 
        
           |  |  | 1627 |   | 
        
           |  |  | 1628 |     /**
 | 
        
           |  |  | 1629 |      * Returns the grade eid - the grade may not exist yet.
 | 
        
           |  |  | 1630 |      *
 | 
        
           |  |  | 1631 |      * @param grade_grade $grade_grade A grade_grade object
 | 
        
           |  |  | 1632 |      *
 | 
        
           |  |  | 1633 |      * @return string eid
 | 
        
           |  |  | 1634 |      */
 | 
        
           |  |  | 1635 |     public function get_grade_eid($grade_grade) {
 | 
        
           |  |  | 1636 |         if (empty($grade_grade->id)) {
 | 
        
           |  |  | 1637 |             return 'n'.$grade_grade->itemid.'u'.$grade_grade->userid;
 | 
        
           |  |  | 1638 |         } else {
 | 
        
           |  |  | 1639 |             return 'g'.$grade_grade->id;
 | 
        
           |  |  | 1640 |         }
 | 
        
           |  |  | 1641 |     }
 | 
        
           |  |  | 1642 |   | 
        
           |  |  | 1643 |     /**
 | 
        
           |  |  | 1644 |      * Returns the grade_item eid
 | 
        
           |  |  | 1645 |      * @param grade_item $grade_item A grade_item object
 | 
        
           |  |  | 1646 |      * @return string eid
 | 
        
           |  |  | 1647 |      */
 | 
        
           |  |  | 1648 |     public function get_item_eid($grade_item) {
 | 
        
           |  |  | 1649 |         return 'ig'.$grade_item->id;
 | 
        
           |  |  | 1650 |     }
 | 
        
           |  |  | 1651 |   | 
        
           |  |  | 1652 |     /**
 | 
        
           |  |  | 1653 |      * Given a grade_tree element, returns an array of parameters
 | 
        
           |  |  | 1654 |      * used to build an icon for that element.
 | 
        
           |  |  | 1655 |      *
 | 
        
           |  |  | 1656 |      * @param array $element An array representing an element in the grade_tree
 | 
        
           |  |  | 1657 |      *
 | 
        
           |  |  | 1658 |      * @return array
 | 
        
           |  |  | 1659 |      */
 | 
        
           |  |  | 1660 |     public function get_params_for_iconstr($element) {
 | 
        
           |  |  | 1661 |         $strparams = new stdClass();
 | 
        
           |  |  | 1662 |         $strparams->category = '';
 | 
        
           |  |  | 1663 |         $strparams->itemname = '';
 | 
        
           |  |  | 1664 |         $strparams->itemmodule = '';
 | 
        
           |  |  | 1665 |   | 
        
           |  |  | 1666 |         if (!method_exists($element['object'], 'get_name')) {
 | 
        
           |  |  | 1667 |             return $strparams;
 | 
        
           |  |  | 1668 |         }
 | 
        
           |  |  | 1669 |   | 
        
           |  |  | 1670 |         $strparams->itemname = html_to_text($element['object']->get_name());
 | 
        
           |  |  | 1671 |   | 
        
           |  |  | 1672 |         // If element name is categorytotal, get the name of the parent category
 | 
        
           |  |  | 1673 |         if ($strparams->itemname == get_string('categorytotal', 'grades')) {
 | 
        
           |  |  | 1674 |             $parent = $element['object']->get_parent_category();
 | 
        
           |  |  | 1675 |             $strparams->category = $parent->get_name() . ' ';
 | 
        
           |  |  | 1676 |         } else {
 | 
        
           |  |  | 1677 |             $strparams->category = '';
 | 
        
           |  |  | 1678 |         }
 | 
        
           |  |  | 1679 |   | 
        
           |  |  | 1680 |         $strparams->itemmodule = null;
 | 
        
           |  |  | 1681 |         if (isset($element['object']->itemmodule)) {
 | 
        
           |  |  | 1682 |             $strparams->itemmodule = $element['object']->itemmodule;
 | 
        
           |  |  | 1683 |         }
 | 
        
           |  |  | 1684 |         return $strparams;
 | 
        
           |  |  | 1685 |     }
 | 
        
           |  |  | 1686 |   | 
        
           |  |  | 1687 |     /**
 | 
        
           |  |  | 1688 |      * Return a reset icon for the given element.
 | 
        
           |  |  | 1689 |      *
 | 
        
           |  |  | 1690 |      * @param array  $element An array representing an element in the grade_tree
 | 
        
           |  |  | 1691 |      * @param object $gpr A grade_plugin_return object
 | 
        
           |  |  | 1692 |      * @param bool $returnactionmenulink return the instance of action_menu_link instead of string
 | 
        
           |  |  | 1693 |      * @return string|action_menu_link
 | 
        
           |  |  | 1694 |      * @deprecated since Moodle 4.2 - The row is not shown anymore - we have actions menu.
 | 
        
           |  |  | 1695 |      * @todo MDL-77307 This will be deleted in Moodle 4.6.
 | 
        
           |  |  | 1696 |      */
 | 
        
           |  |  | 1697 |     public function get_reset_icon($element, $gpr, $returnactionmenulink = false) {
 | 
        
           |  |  | 1698 |         global $CFG, $OUTPUT;
 | 
        
           |  |  | 1699 |         debugging('The function get_reset_icon() is deprecated, please do not use it anymore.',
 | 
        
           |  |  | 1700 |             DEBUG_DEVELOPER);
 | 
        
           |  |  | 1701 |   | 
        
           |  |  | 1702 |         // Limit to category items set to use the natural weights aggregation method, and users
 | 
        
           |  |  | 1703 |         // with the capability to manage grades.
 | 
        
           |  |  | 1704 |         if ($element['type'] != 'category' || $element['object']->aggregation != GRADE_AGGREGATE_SUM ||
 | 
        
           |  |  | 1705 |                 !has_capability('moodle/grade:manage', $this->context)) {
 | 
        
           |  |  | 1706 |             return $returnactionmenulink ? null : '';
 | 
        
           |  |  | 1707 |         }
 | 
        
           |  |  | 1708 |   | 
        
           |  |  | 1709 |         $str = get_string('resetweights', 'grades', $this->get_params_for_iconstr($element));
 | 
        
           |  |  | 1710 |         $url = new moodle_url('/grade/edit/tree/action.php', array(
 | 
        
           |  |  | 1711 |             'id' => $this->courseid,
 | 
        
           |  |  | 1712 |             'action' => 'resetweights',
 | 
        
           |  |  | 1713 |             'eid' => $element['eid'],
 | 
        
           |  |  | 1714 |             'sesskey' => sesskey(),
 | 
        
           |  |  | 1715 |         ));
 | 
        
           |  |  | 1716 |   | 
        
           |  |  | 1717 |         if ($returnactionmenulink) {
 | 
        
           |  |  | 1718 |             return new action_menu_link_secondary($gpr->add_url_params($url), new pix_icon('t/reset', $str),
 | 
        
           |  |  | 1719 |                 get_string('resetweightsshort', 'grades'));
 | 
        
           |  |  | 1720 |         } else {
 | 
        
           |  |  | 1721 |             return $OUTPUT->action_icon($gpr->add_url_params($url), new pix_icon('t/reset', $str));
 | 
        
           |  |  | 1722 |         }
 | 
        
           |  |  | 1723 |     }
 | 
        
           |  |  | 1724 |   | 
        
           |  |  | 1725 |     /**
 | 
        
           |  |  | 1726 |      * Returns a link to reset weights for the given element.
 | 
        
           |  |  | 1727 |      *
 | 
        
           |  |  | 1728 |      * @param array  $element An array representing an element in the grade_tree
 | 
        
           |  |  | 1729 |      * @param object $gpr A grade_plugin_return object
 | 
        
           |  |  | 1730 |      * @return string|null
 | 
        
           |  |  | 1731 |      */
 | 
        
           |  |  | 1732 |     public function get_reset_weights_link(array $element, object $gpr): ?string {
 | 
        
           |  |  | 1733 |   | 
        
           |  |  | 1734 |         // Limit to category items set to use the natural weights aggregation method, and users
 | 
        
           |  |  | 1735 |         // with the capability to manage grades.
 | 
        
           |  |  | 1736 |         if ($element['type'] != 'category' || $element['object']->aggregation != GRADE_AGGREGATE_SUM ||
 | 
        
           |  |  | 1737 |                 !has_capability('moodle/grade:manage', $this->context)) {
 | 
        
           |  |  | 1738 |             return null;
 | 
        
           |  |  | 1739 |         }
 | 
        
           |  |  | 1740 |   | 
        
           |  |  | 1741 |         $title = get_string('resetweightsshort', 'grades');
 | 
        
           |  |  | 1742 |         $str = get_string('resetweights', 'grades', $this->get_params_for_iconstr($element));
 | 
        
           |  |  | 1743 |         $url = new moodle_url('/grade/edit/tree/action.php', [
 | 
        
           |  |  | 1744 |             'id' => $this->courseid,
 | 
        
           |  |  | 1745 |             'action' => 'resetweights',
 | 
        
           |  |  | 1746 |             'eid' => $element['eid'],
 | 
        
           |  |  | 1747 |             'sesskey' => sesskey(),
 | 
        
           |  |  | 1748 |         ]);
 | 
        
           |  |  | 1749 |         $gpr->add_url_params($url);
 | 
        
           |  |  | 1750 |         return html_writer::link($url, $title,
 | 
        
           |  |  | 1751 |             ['class' => 'dropdown-item', 'aria-label' => $str, 'role' => 'menuitem']);
 | 
        
           |  |  | 1752 |     }
 | 
        
           |  |  | 1753 |   | 
        
           |  |  | 1754 |     /**
 | 
        
           |  |  | 1755 |      * Returns a link to delete a given element.
 | 
        
           |  |  | 1756 |      *
 | 
        
           |  |  | 1757 |      * @param array  $element An array representing an element in the grade_tree
 | 
        
           |  |  | 1758 |      * @param object $gpr A grade_plugin_return object
 | 
        
           |  |  | 1759 |      * @return string|null
 | 
        
           |  |  | 1760 |      */
 | 
        
           |  |  | 1761 |     public function get_delete_link(array $element, object $gpr): ?string {
 | 
        
           |  |  | 1762 |         if ($element['type'] == 'item' || ($element['type'] == 'category' && $element['depth'] > 1)) {
 | 
        
           |  |  | 1763 |             if (grade_edit_tree::element_deletable($element)) {
 | 
        
           |  |  | 1764 |                 $deleteconfirmationurl = new moodle_url('index.php', [
 | 
        
           |  |  | 1765 |                     'id' => $this->courseid,
 | 
        
           |  |  | 1766 |                     'action' => 'delete',
 | 
        
           |  |  | 1767 |                     'confirm' => 1,
 | 
        
           |  |  | 1768 |                     'eid' => $element['eid'],
 | 
        
           |  |  | 1769 |                     'sesskey' => sesskey(),
 | 
        
           |  |  | 1770 |                 ]);
 | 
        
           |  |  | 1771 |                 $gpr->add_url_params($deleteconfirmationurl);
 | 
        
           |  |  | 1772 |                 $title = get_string('delete');
 | 
        
           |  |  | 1773 |                 return html_writer::link(
 | 
        
           |  |  | 1774 |                     '',
 | 
        
           |  |  | 1775 |                     $title,
 | 
        
           |  |  | 1776 |                     [
 | 
        
           |  |  | 1777 |                         'class' => 'dropdown-item',
 | 
        
           |  |  | 1778 |                         'aria-label' => $title,
 | 
        
           |  |  | 1779 |                         'role' => 'menuitem',
 | 
        
           |  |  | 1780 |                         'data-modal' => 'confirmation',
 | 
        
           |  |  | 1781 |                         'data-modal-title-str' => json_encode(['confirm', 'core']),
 | 
        
           |  |  | 1782 |                         'data-modal-content-str' => json_encode([
 | 
        
           |  |  | 1783 |                             'deletecheck',
 | 
        
           |  |  | 1784 |                             '',
 | 
        
           |  |  | 1785 |                             $element['object']->get_name()
 | 
        
           |  |  | 1786 |                         ]),
 | 
        
           |  |  | 1787 |                         'data-modal-yes-button-str' => json_encode(['delete', 'core']),
 | 
        
           |  |  | 1788 |                         'data-modal-destination' => $deleteconfirmationurl->out(false),
 | 
        
           |  |  | 1789 |                     ]
 | 
        
           |  |  | 1790 |                 );
 | 
        
           |  |  | 1791 |             }
 | 
        
           |  |  | 1792 |         }
 | 
        
           |  |  | 1793 |         return null;
 | 
        
           |  |  | 1794 |     }
 | 
        
           |  |  | 1795 |   | 
        
           |  |  | 1796 |     /**
 | 
        
           |  |  | 1797 |      * Returns a link to duplicate a given element.
 | 
        
           |  |  | 1798 |      *
 | 
        
           |  |  | 1799 |      * @param array  $element An array representing an element in the grade_tree
 | 
        
           |  |  | 1800 |      * @param object $gpr A grade_plugin_return object
 | 
        
           |  |  | 1801 |      * @return string|null
 | 
        
           |  |  | 1802 |      */
 | 
        
           |  |  | 1803 |     public function get_duplicate_link(array $element, object $gpr): ?string {
 | 
        
           |  |  | 1804 |         if ($element['type'] == 'item' || ($element['type'] == 'category' && $element['depth'] > 1)) {
 | 
        
           |  |  | 1805 |             if (grade_edit_tree::element_duplicatable($element)) {
 | 
        
           |  |  | 1806 |                 $duplicateparams = [];
 | 
        
           |  |  | 1807 |                 $duplicateparams['id'] = $this->courseid;
 | 
        
           |  |  | 1808 |                 $duplicateparams['action'] = 'duplicate';
 | 
        
           |  |  | 1809 |                 $duplicateparams['eid'] = $element['eid'];
 | 
        
           |  |  | 1810 |                 $duplicateparams['sesskey'] = sesskey();
 | 
        
           |  |  | 1811 |                 $url = new moodle_url('index.php', $duplicateparams);
 | 
        
           |  |  | 1812 |                 $title = get_string('duplicate');
 | 
        
           |  |  | 1813 |                 $gpr->add_url_params($url);
 | 
        
           |  |  | 1814 |                 return html_writer::link($url, $title,
 | 
        
           |  |  | 1815 |                     ['class' => 'dropdown-item', 'aria-label' => $title, 'role' => 'menuitem']);
 | 
        
           |  |  | 1816 |             }
 | 
        
           |  |  | 1817 |         }
 | 
        
           |  |  | 1818 |         return null;
 | 
        
           |  |  | 1819 |     }
 | 
        
           |  |  | 1820 |   | 
        
           |  |  | 1821 |     /**
 | 
        
           |  |  | 1822 |      * Return edit icon for give element
 | 
        
           |  |  | 1823 |      *
 | 
        
           |  |  | 1824 |      * @param array  $element An array representing an element in the grade_tree
 | 
        
           |  |  | 1825 |      * @param object $gpr A grade_plugin_return object
 | 
        
           |  |  | 1826 |      * @param bool $returnactionmenulink return the instance of action_menu_link instead of string
 | 
        
           |  |  | 1827 |      * @return string|action_menu_link
 | 
        
           |  |  | 1828 |      * @deprecated since Moodle 4.2 - The row is not shown anymore - we have actions menu.
 | 
        
           |  |  | 1829 |      * @todo MDL-77307 This will be deleted in Moodle 4.6.
 | 
        
           |  |  | 1830 |      */
 | 
        
           |  |  | 1831 |     public function get_edit_icon($element, $gpr, $returnactionmenulink = false) {
 | 
        
           |  |  | 1832 |         global $CFG, $OUTPUT;
 | 
        
           |  |  | 1833 |   | 
        
           |  |  | 1834 |         debugging('The function get_edit_icon() is deprecated, please do not use it anymore.',
 | 
        
           |  |  | 1835 |             DEBUG_DEVELOPER);
 | 
        
           |  |  | 1836 |   | 
        
           |  |  | 1837 |         if (!has_capability('moodle/grade:manage', $this->context)) {
 | 
        
           |  |  | 1838 |             if ($element['type'] == 'grade' and has_capability('moodle/grade:edit', $this->context)) {
 | 
        
           |  |  | 1839 |                 // oki - let them override grade
 | 
        
           |  |  | 1840 |             } else {
 | 
        
           |  |  | 1841 |                 return $returnactionmenulink ? null : '';
 | 
        
           |  |  | 1842 |             }
 | 
        
           |  |  | 1843 |         }
 | 
        
           |  |  | 1844 |   | 
        
           |  |  | 1845 |         static $strfeedback   = null;
 | 
        
           |  |  | 1846 |         static $streditgrade = null;
 | 
        
           |  |  | 1847 |         if (is_null($streditgrade)) {
 | 
        
           |  |  | 1848 |             $streditgrade = get_string('editgrade', 'grades');
 | 
        
           |  |  | 1849 |             $strfeedback  = get_string('feedback');
 | 
        
           |  |  | 1850 |         }
 | 
        
           |  |  | 1851 |   | 
        
           |  |  | 1852 |         $strparams = $this->get_params_for_iconstr($element);
 | 
        
           |  |  | 1853 |   | 
        
           |  |  | 1854 |         $object = $element['object'];
 | 
        
           |  |  | 1855 |   | 
        
           |  |  | 1856 |         switch ($element['type']) {
 | 
        
           |  |  | 1857 |             case 'item':
 | 
        
           |  |  | 1858 |             case 'categoryitem':
 | 
        
           |  |  | 1859 |             case 'courseitem':
 | 
        
           |  |  | 1860 |                 $stredit = get_string('editverbose', 'grades', $strparams);
 | 
        
           |  |  | 1861 |                 if (empty($object->outcomeid) || empty($CFG->enableoutcomes)) {
 | 
        
           |  |  | 1862 |                     $url = new moodle_url('/grade/edit/tree/item.php',
 | 
        
           |  |  | 1863 |                             array('courseid' => $this->courseid, 'id' => $object->id));
 | 
        
           |  |  | 1864 |                 } else {
 | 
        
           |  |  | 1865 |                     $url = new moodle_url('/grade/edit/tree/outcomeitem.php',
 | 
        
           |  |  | 1866 |                             array('courseid' => $this->courseid, 'id' => $object->id));
 | 
        
           |  |  | 1867 |                 }
 | 
        
           |  |  | 1868 |                 break;
 | 
        
           |  |  | 1869 |   | 
        
           |  |  | 1870 |             case 'category':
 | 
        
           |  |  | 1871 |                 $stredit = get_string('editverbose', 'grades', $strparams);
 | 
        
           |  |  | 1872 |                 $url = new moodle_url('/grade/edit/tree/category.php',
 | 
        
           |  |  | 1873 |                         array('courseid' => $this->courseid, 'id' => $object->id));
 | 
        
           |  |  | 1874 |                 break;
 | 
        
           |  |  | 1875 |   | 
        
           |  |  | 1876 |             case 'grade':
 | 
        
           |  |  | 1877 |                 $stredit = $streditgrade;
 | 
        
           |  |  | 1878 |                 if (empty($object->id)) {
 | 
        
           |  |  | 1879 |                     $url = new moodle_url('/grade/edit/tree/grade.php',
 | 
        
           |  |  | 1880 |                             array('courseid' => $this->courseid, 'itemid' => $object->itemid, 'userid' => $object->userid));
 | 
        
           |  |  | 1881 |                 } else {
 | 
        
           |  |  | 1882 |                     $url = new moodle_url('/grade/edit/tree/grade.php',
 | 
        
           |  |  | 1883 |                             array('courseid' => $this->courseid, 'id' => $object->id));
 | 
        
           |  |  | 1884 |                 }
 | 
        
           |  |  | 1885 |                 if (!empty($object->feedback)) {
 | 
        
           |  |  | 1886 |                     $feedback = addslashes_js(trim(format_string($object->feedback, $object->feedbackformat)));
 | 
        
           |  |  | 1887 |                 }
 | 
        
           |  |  | 1888 |                 break;
 | 
        
           |  |  | 1889 |   | 
        
           |  |  | 1890 |             default:
 | 
        
           |  |  | 1891 |                 $url = null;
 | 
        
           |  |  | 1892 |         }
 | 
        
           |  |  | 1893 |   | 
        
           |  |  | 1894 |         if ($url) {
 | 
        
           |  |  | 1895 |             if ($returnactionmenulink) {
 | 
        
           |  |  | 1896 |                 return new action_menu_link_secondary($gpr->add_url_params($url),
 | 
        
           |  |  | 1897 |                     new pix_icon('t/edit', $stredit),
 | 
        
           |  |  | 1898 |                     get_string('editsettings'));
 | 
        
           |  |  | 1899 |             } else {
 | 
        
           |  |  | 1900 |                 return $OUTPUT->action_icon($gpr->add_url_params($url), new pix_icon('t/edit', $stredit));
 | 
        
           |  |  | 1901 |             }
 | 
        
           |  |  | 1902 |   | 
        
           |  |  | 1903 |         } else {
 | 
        
           |  |  | 1904 |             return $returnactionmenulink ? null : '';
 | 
        
           |  |  | 1905 |         }
 | 
        
           |  |  | 1906 |     }
 | 
        
           |  |  | 1907 |   | 
        
           |  |  | 1908 |     /**
 | 
        
           |  |  | 1909 |      * Returns a link leading to the edit grade/grade item/category page
 | 
        
           |  |  | 1910 |      *
 | 
        
           |  |  | 1911 |      * @param array  $element An array representing an element in the grade_tree
 | 
        
           |  |  | 1912 |      * @param object $gpr A grade_plugin_return object
 | 
        
           |  |  | 1913 |      * @return string|null
 | 
        
           |  |  | 1914 |      */
 | 
        
           |  |  | 1915 |     public function get_edit_link(array $element, object $gpr): ?string {
 | 
        
           |  |  | 1916 |         global $CFG;
 | 
        
           |  |  | 1917 |   | 
        
           |  |  | 1918 |         $url = null;
 | 
        
           |  |  | 1919 |         $title = '';
 | 
        
           |  |  | 1920 |         if ((!has_capability('moodle/grade:manage', $this->context) &&
 | 
        
           |  |  | 1921 |             (!($element['type'] == 'grade') || !has_capability('moodle/grade:edit', $this->context)))) {
 | 
        
           |  |  | 1922 |                 return null;
 | 
        
           |  |  | 1923 |         }
 | 
        
           |  |  | 1924 |   | 
        
           |  |  | 1925 |         $object = $element['object'];
 | 
        
           |  |  | 1926 |   | 
        
           |  |  | 1927 |         if ($element['type'] == 'grade') {
 | 
        
           |  |  | 1928 |             if (empty($object->id)) {
 | 
        
           |  |  | 1929 |                 $url = new moodle_url('/grade/edit/tree/grade.php',
 | 
        
           |  |  | 1930 |                     ['courseid' => $this->courseid, 'itemid' => $object->itemid, 'userid' => $object->userid]);
 | 
        
           |  |  | 1931 |             } else {
 | 
        
           |  |  | 1932 |                 $url = new moodle_url('/grade/edit/tree/grade.php',
 | 
        
           |  |  | 1933 |                     ['courseid' => $this->courseid, 'id' => $object->id]);
 | 
        
           |  |  | 1934 |             }
 | 
        
           |  |  | 1935 |             $url = $gpr->add_url_params($url);
 | 
        
           |  |  | 1936 |             $title = get_string('editgrade', 'grades');
 | 
        
           |  |  | 1937 |         } else if (($element['type'] == 'item') || ($element['type'] == 'categoryitem') ||
 | 
        
           |  |  | 1938 |             ($element['type'] == 'courseitem')) {
 | 
        
           |  |  | 1939 |             $url = new moodle_url('#');
 | 
        
           |  |  | 1940 |             if (empty($object->outcomeid) || empty($CFG->enableoutcomes)) {
 | 
        
           |  |  | 1941 |                 return html_writer::link($url, get_string('itemsedit', 'grades'), [
 | 
        
           |  |  | 1942 |                     'class' => 'dropdown-item',
 | 
        
           |  |  | 1943 |                     'aria-label' => get_string('itemsedit', 'grades'),
 | 
        
           |  |  | 1944 |                     'role' => 'menuitem',
 | 
        
           |  |  | 1945 |                     'data-gprplugin' => $gpr->plugin,
 | 
        
           |  |  | 1946 |                     'data-courseid' => $this->courseid,
 | 
        
           |  |  | 1947 |                     'data-itemid' => $object->id, 'data-trigger' => 'add-item-form'
 | 
        
           |  |  | 1948 |                 ]);
 | 
        
           |  |  | 1949 |             } else if (count(grade_outcome::fetch_all_available($this->courseid)) > 0) {
 | 
        
           |  |  | 1950 |                 return html_writer::link($url, get_string('itemsedit', 'grades'), [
 | 
        
           |  |  | 1951 |                     'class' => 'dropdown-item',
 | 
        
           |  |  | 1952 |                     get_string('itemsedit', 'grades'),
 | 
        
           |  |  | 1953 |                     'role' => 'menuitem',
 | 
        
           |  |  | 1954 |                     'data-gprplugin' => $gpr->plugin,
 | 
        
           |  |  | 1955 |                     'data-courseid' => $this->courseid,
 | 
        
           |  |  | 1956 |                     'data-itemid' => $object->id, 'data-trigger' => 'add-outcome-form'
 | 
        
           |  |  | 1957 |                 ]);
 | 
        
           |  |  | 1958 |             }
 | 
        
           |  |  | 1959 |         } else if ($element['type'] == 'category') {
 | 
        
           |  |  | 1960 |             $url = new moodle_url('#');
 | 
        
           |  |  | 1961 |             $title = get_string('categoryedit', 'grades');
 | 
        
           |  |  | 1962 |             return html_writer::link($url, $title, [
 | 
        
           |  |  | 1963 |                 'class' => 'dropdown-item',
 | 
        
           |  |  | 1964 |                 'aria-label' => $title,
 | 
        
           |  |  | 1965 |                 'role' => 'menuitem',
 | 
        
           |  |  | 1966 |                 'data-gprplugin' => $gpr->plugin,
 | 
        
           |  |  | 1967 |                 'data-courseid' => $this->courseid,
 | 
        
           |  |  | 1968 |                 'data-category' => $object->id,
 | 
        
           |  |  | 1969 |                 'data-trigger' => 'add-category-form'
 | 
        
           |  |  | 1970 |             ]);
 | 
        
           |  |  | 1971 |         }
 | 
        
           |  |  | 1972 |         return html_writer::link($url, $title,
 | 
        
           |  |  | 1973 |             ['class' => 'dropdown-item', 'aria-label' => $title, 'role' => 'menuitem']);
 | 
        
           |  |  | 1974 |     }
 | 
        
           |  |  | 1975 |   | 
        
           |  |  | 1976 |     /**
 | 
        
           |  |  | 1977 |      * Returns link to the advanced grading page
 | 
        
           |  |  | 1978 |      *
 | 
        
           |  |  | 1979 |      * @param array  $element An array representing an element in the grade_tree
 | 
        
           |  |  | 1980 |      * @param object $gpr A grade_plugin_return object
 | 
        
           |  |  | 1981 |      * @return string|null
 | 
        
           |  |  | 1982 |      */
 | 
        
           |  |  | 1983 |     public function get_advanced_grading_link(array $element, object $gpr): ?string {
 | 
        
           |  |  | 1984 |         global $CFG;
 | 
        
           |  |  | 1985 |   | 
        
           |  |  | 1986 |         /** @var array static cache of the grade.php file existence flags */
 | 
        
           |  |  | 1987 |         static $hasgradephp = [];
 | 
        
           |  |  | 1988 |   | 
        
           |  |  | 1989 |         $itemtype = $element['object']->itemtype;
 | 
        
           |  |  | 1990 |         $itemmodule = $element['object']->itemmodule;
 | 
        
           |  |  | 1991 |         $iteminstance = $element['object']->iteminstance;
 | 
        
           |  |  | 1992 |         $itemnumber = $element['object']->itemnumber;
 | 
        
           |  |  | 1993 |   | 
        
           |  |  | 1994 |         // Links only for module items that have valid instance, module and are
 | 
        
           |  |  | 1995 |         // called from grade_tree with valid modinfo.
 | 
        
           |  |  | 1996 |         if ($itemtype == 'mod' && $iteminstance && $itemmodule && $this->modinfo) {
 | 
        
           |  |  | 1997 |   | 
        
           |  |  | 1998 |             // Get $cm efficiently and with visibility information using modinfo.
 | 
        
           |  |  | 1999 |             $instances = $this->modinfo->get_instances();
 | 
        
           |  |  | 2000 |             if (!empty($instances[$itemmodule][$iteminstance])) {
 | 
        
           |  |  | 2001 |                 $cm = $instances[$itemmodule][$iteminstance];
 | 
        
           |  |  | 2002 |   | 
        
           |  |  | 2003 |                 // Do not add link if activity is not visible to the current user.
 | 
        
           |  |  | 2004 |                 if ($cm->uservisible) {
 | 
        
           |  |  | 2005 |                     if (!array_key_exists($itemmodule, $hasgradephp)) {
 | 
        
           |  |  | 2006 |                         if (file_exists($CFG->dirroot . '/mod/' . $itemmodule . '/grade.php')) {
 | 
        
           |  |  | 2007 |                             $hasgradephp[$itemmodule] = true;
 | 
        
           |  |  | 2008 |                         } else {
 | 
        
           |  |  | 2009 |                             $hasgradephp[$itemmodule] = false;
 | 
        
           |  |  | 2010 |                         }
 | 
        
           |  |  | 2011 |                     }
 | 
        
           |  |  | 2012 |   | 
        
           |  |  | 2013 |                     // If module has grade.php, add link to that.
 | 
        
           |  |  | 2014 |                     if ($hasgradephp[$itemmodule]) {
 | 
        
           |  |  | 2015 |                         $args = array('id' => $cm->id, 'itemnumber' => $itemnumber);
 | 
        
           |  |  | 2016 |                         if (isset($element['userid'])) {
 | 
        
           |  |  | 2017 |                             $args['userid'] = $element['userid'];
 | 
        
           |  |  | 2018 |                         }
 | 
        
           |  |  | 2019 |   | 
        
           |  |  | 2020 |                         $url = new moodle_url('/mod/' . $itemmodule . '/grade.php', $args);
 | 
        
           |  |  | 2021 |                         $title = get_string('advancedgrading', 'gradereport_grader',
 | 
        
           |  |  | 2022 |                             get_string('pluginname', "mod_{$itemmodule}"));
 | 
        
           |  |  | 2023 |                         $gpr->add_url_params($url);
 | 
        
           |  |  | 2024 |                         return html_writer::link($url, $title,
 | 
        
           |  |  | 2025 |                             ['class' => 'dropdown-item', 'aria-label' => $title, 'role' => 'menuitem']);
 | 
        
           |  |  | 2026 |                     }
 | 
        
           |  |  | 2027 |                 }
 | 
        
           |  |  | 2028 |             }
 | 
        
           |  |  | 2029 |         }
 | 
        
           |  |  | 2030 |   | 
        
           |  |  | 2031 |         return null;
 | 
        
           |  |  | 2032 |     }
 | 
        
           |  |  | 2033 |   | 
        
           |  |  | 2034 |     /**
 | 
        
           |  |  | 2035 |      * Return hiding icon for give element
 | 
        
           |  |  | 2036 |      *
 | 
        
           |  |  | 2037 |      * @param array  $element An array representing an element in the grade_tree
 | 
        
           |  |  | 2038 |      * @param object $gpr A grade_plugin_return object
 | 
        
           |  |  | 2039 |      * @param bool $returnactionmenulink return the instance of action_menu_link instead of string
 | 
        
           |  |  | 2040 |      * @return string|action_menu_link
 | 
        
           |  |  | 2041 |      * @deprecated since Moodle 4.2 - The row is not shown anymore - we have actions menu.
 | 
        
           |  |  | 2042 |      * @todo MDL-77307 This will be deleted in Moodle 4.6.
 | 
        
           |  |  | 2043 |      */
 | 
        
           |  |  | 2044 |     public function get_hiding_icon($element, $gpr, $returnactionmenulink = false) {
 | 
        
           |  |  | 2045 |         global $CFG, $OUTPUT;
 | 
        
           |  |  | 2046 |         debugging('The function get_hiding_icon() is deprecated, please do not use it anymore.',
 | 
        
           |  |  | 2047 |             DEBUG_DEVELOPER);
 | 
        
           |  |  | 2048 |   | 
        
           |  |  | 2049 |         if (!$element['object']->can_control_visibility()) {
 | 
        
           |  |  | 2050 |             return $returnactionmenulink ? null : '';
 | 
        
           |  |  | 2051 |         }
 | 
        
           |  |  | 2052 |   | 
        
           |  |  | 2053 |         if (!has_capability('moodle/grade:manage', $this->context) and
 | 
        
           |  |  | 2054 |             !has_capability('moodle/grade:hide', $this->context)) {
 | 
        
           |  |  | 2055 |             return $returnactionmenulink ? null : '';
 | 
        
           |  |  | 2056 |         }
 | 
        
           |  |  | 2057 |   | 
        
           |  |  | 2058 |         $strparams = $this->get_params_for_iconstr($element);
 | 
        
           |  |  | 2059 |         $strshow = get_string('showverbose', 'grades', $strparams);
 | 
        
           |  |  | 2060 |         $strhide = get_string('hideverbose', 'grades', $strparams);
 | 
        
           |  |  | 2061 |   | 
        
           |  |  | 2062 |         $url = new moodle_url('/grade/edit/tree/action.php', array('id' => $this->courseid, 'sesskey' => sesskey(), 'eid' => $element['eid']));
 | 
        
           |  |  | 2063 |         $url = $gpr->add_url_params($url);
 | 
        
           |  |  | 2064 |   | 
        
           |  |  | 2065 |         if ($element['object']->is_hidden()) {
 | 
        
           |  |  | 2066 |             $type = 'show';
 | 
        
           |  |  | 2067 |             $tooltip = $strshow;
 | 
        
           |  |  | 2068 |   | 
        
           |  |  | 2069 |             // Change the icon and add a tooltip showing the date
 | 
        
           |  |  | 2070 |             if ($element['type'] != 'category' and $element['object']->get_hidden() > 1) {
 | 
        
           |  |  | 2071 |                 $type = 'hiddenuntil';
 | 
        
           |  |  | 2072 |                 $tooltip = get_string('hiddenuntildate', 'grades',
 | 
        
           |  |  | 2073 |                         userdate($element['object']->get_hidden()));
 | 
        
           |  |  | 2074 |             }
 | 
        
           |  |  | 2075 |   | 
        
           |  |  | 2076 |             $url->param('action', 'show');
 | 
        
           |  |  | 2077 |   | 
        
           |  |  | 2078 |             if ($returnactionmenulink) {
 | 
        
           |  |  | 2079 |                 $hideicon = new action_menu_link_secondary($url, new pix_icon('t/'.$type, $tooltip), get_string('show'));
 | 
        
           |  |  | 2080 |             } else {
 | 
        
           |  |  | 2081 |                 $hideicon = $OUTPUT->action_icon($url, new pix_icon('t/'.$type, $tooltip, 'moodle', array('alt'=>$strshow, 'class'=>'smallicon')));
 | 
        
           |  |  | 2082 |             }
 | 
        
           |  |  | 2083 |   | 
        
           |  |  | 2084 |         } else {
 | 
        
           |  |  | 2085 |             $url->param('action', 'hide');
 | 
        
           |  |  | 2086 |             if ($returnactionmenulink) {
 | 
        
           |  |  | 2087 |                 $hideicon = new action_menu_link_secondary($url, new pix_icon('t/hide', $strhide), get_string('hide'));
 | 
        
           |  |  | 2088 |             } else {
 | 
        
           |  |  | 2089 |                 $hideicon = $OUTPUT->action_icon($url, new pix_icon('t/hide', $strhide));
 | 
        
           |  |  | 2090 |             }
 | 
        
           |  |  | 2091 |         }
 | 
        
           |  |  | 2092 |   | 
        
           |  |  | 2093 |         return $hideicon;
 | 
        
           |  |  | 2094 |     }
 | 
        
           |  |  | 2095 |   | 
        
           |  |  | 2096 |     /**
 | 
        
           |  |  | 2097 |      * Returns a link with url to hide/unhide grade/grade item/grade category
 | 
        
           |  |  | 2098 |      *
 | 
        
           |  |  | 2099 |      * @param array  $element An array representing an element in the grade_tree
 | 
        
           |  |  | 2100 |      * @param object $gpr A grade_plugin_return object
 | 
        
           |  |  | 2101 |      * @return string|null
 | 
        
           |  |  | 2102 |      */
 | 
        
           |  |  | 2103 |     public function get_hiding_link(array $element, object $gpr): ?string {
 | 
        
           |  |  | 2104 |         if (!$element['object']->can_control_visibility() || !has_capability('moodle/grade:manage', $this->context) ||
 | 
        
           |  |  | 2105 |             !has_capability('moodle/grade:hide', $this->context)) {
 | 
        
           |  |  | 2106 |             return null;
 | 
        
           |  |  | 2107 |         }
 | 
        
           |  |  | 2108 |   | 
        
           |  |  | 2109 |         $url = new moodle_url('/grade/edit/tree/action.php',
 | 
        
           |  |  | 2110 |             ['id' => $this->courseid, 'sesskey' => sesskey(), 'eid' => $element['eid']]);
 | 
        
           |  |  | 2111 |         $url = $gpr->add_url_params($url);
 | 
        
           |  |  | 2112 |   | 
        
           |  |  | 2113 |         if ($element['object']->is_hidden()) {
 | 
        
           |  |  | 2114 |             $url->param('action', 'show');
 | 
        
           |  |  | 2115 |             $title = get_string('show');
 | 
        
           |  |  | 2116 |         } else {
 | 
        
           |  |  | 2117 |             $url->param('action', 'hide');
 | 
        
           |  |  | 2118 |             $title = get_string('hide');
 | 
        
           |  |  | 2119 |         }
 | 
        
           |  |  | 2120 |   | 
        
           |  |  | 2121 |         $url = html_writer::link($url, $title,
 | 
        
           |  |  | 2122 |             ['class' => 'dropdown-item', 'aria-label' => $title, 'role' => 'menuitem']);
 | 
        
           |  |  | 2123 |   | 
        
           |  |  | 2124 |         if ($element['type'] == 'grade') {
 | 
        
           |  |  | 2125 |             $item = $element['object']->grade_item;
 | 
        
           |  |  | 2126 |             if ($item->hidden) {
 | 
        
           |  |  | 2127 |                 $strparamobj = new stdClass();
 | 
        
           |  |  | 2128 |                 $strparamobj->itemname = $item->get_name(true, true);
 | 
        
           |  |  | 2129 |                 $strnonunhideable = get_string('nonunhideableverbose', 'grades', $strparamobj);
 | 
        
           |  |  | 2130 |                 $url = html_writer::span($title, 'text-muted dropdown-item',
 | 
        
           |  |  | 2131 |                     ['title' => $strnonunhideable, 'aria-label' => $title, 'role' => 'menuitem']);
 | 
        
           |  |  | 2132 |             }
 | 
        
           |  |  | 2133 |         }
 | 
        
           |  |  | 2134 |   | 
        
           |  |  | 2135 |         return $url;
 | 
        
           |  |  | 2136 |     }
 | 
        
           |  |  | 2137 |   | 
        
           |  |  | 2138 |     /**
 | 
        
           |  |  | 2139 |      * Return locking icon for given element
 | 
        
           |  |  | 2140 |      *
 | 
        
           |  |  | 2141 |      * @param array  $element An array representing an element in the grade_tree
 | 
        
           |  |  | 2142 |      * @param object $gpr A grade_plugin_return object
 | 
        
           |  |  | 2143 |      *
 | 
        
           |  |  | 2144 |      * @return string
 | 
        
           |  |  | 2145 |      * @deprecated since Moodle 4.2 - The row is not shown anymore - we have actions menu.
 | 
        
           |  |  | 2146 |      * @todo MDL-77307 This will be deleted in Moodle 4.6.
 | 
        
           |  |  | 2147 |      */
 | 
        
           |  |  | 2148 |     public function get_locking_icon($element, $gpr) {
 | 
        
           |  |  | 2149 |         global $CFG, $OUTPUT;
 | 
        
           |  |  | 2150 |         debugging('The function get_locking_icon() is deprecated, please do not use it anymore.',
 | 
        
           |  |  | 2151 |             DEBUG_DEVELOPER);
 | 
        
           |  |  | 2152 |   | 
        
           |  |  | 2153 |         $strparams = $this->get_params_for_iconstr($element);
 | 
        
           |  |  | 2154 |         $strunlock = get_string('unlockverbose', 'grades', $strparams);
 | 
        
           |  |  | 2155 |         $strlock = get_string('lockverbose', 'grades', $strparams);
 | 
        
           |  |  | 2156 |   | 
        
           |  |  | 2157 |         $url = new moodle_url('/grade/edit/tree/action.php', array('id' => $this->courseid, 'sesskey' => sesskey(), 'eid' => $element['eid']));
 | 
        
           |  |  | 2158 |         $url = $gpr->add_url_params($url);
 | 
        
           |  |  | 2159 |   | 
        
           |  |  | 2160 |         // Don't allow an unlocking action for a grade whose grade item is locked: just print a state icon
 | 
        
           |  |  | 2161 |         if ($element['type'] == 'grade' && $element['object']->grade_item->is_locked()) {
 | 
        
           |  |  | 2162 |             $strparamobj = new stdClass();
 | 
        
           |  |  | 2163 |             $strparamobj->itemname = $element['object']->grade_item->itemname;
 | 
        
           |  |  | 2164 |             $strnonunlockable = get_string('nonunlockableverbose', 'grades', $strparamobj);
 | 
        
           |  |  | 2165 |   | 
        
           |  |  | 2166 |             $action = html_writer::tag('span', $OUTPUT->pix_icon('t/locked', $strnonunlockable),
 | 
        
           |  |  | 2167 |                     array('class' => 'action-icon'));
 | 
        
           |  |  | 2168 |   | 
        
           |  |  | 2169 |         } else if ($element['object']->is_locked()) {
 | 
        
           |  |  | 2170 |             $type = 'unlock';
 | 
        
           |  |  | 2171 |             $tooltip = $strunlock;
 | 
        
           |  |  | 2172 |   | 
        
           |  |  | 2173 |             // Change the icon and add a tooltip showing the date
 | 
        
           |  |  | 2174 |             if ($element['type'] != 'category' and $element['object']->get_locktime() > 1) {
 | 
        
           |  |  | 2175 |                 $type = 'locktime';
 | 
        
           |  |  | 2176 |                 $tooltip = get_string('locktimedate', 'grades',
 | 
        
           |  |  | 2177 |                         userdate($element['object']->get_locktime()));
 | 
        
           |  |  | 2178 |             }
 | 
        
           |  |  | 2179 |   | 
        
           |  |  | 2180 |             if (!has_capability('moodle/grade:manage', $this->context) and !has_capability('moodle/grade:unlock', $this->context)) {
 | 
        
           |  |  | 2181 |                 $action = '';
 | 
        
           |  |  | 2182 |             } else {
 | 
        
           |  |  | 2183 |                 $url->param('action', 'unlock');
 | 
        
           |  |  | 2184 |                 $action = $OUTPUT->action_icon($url, new pix_icon('t/'.$type, $tooltip, 'moodle', array('alt'=>$strunlock, 'class'=>'smallicon')));
 | 
        
           |  |  | 2185 |             }
 | 
        
           |  |  | 2186 |   | 
        
           |  |  | 2187 |         } else {
 | 
        
           |  |  | 2188 |             if (!has_capability('moodle/grade:manage', $this->context) and !has_capability('moodle/grade:lock', $this->context)) {
 | 
        
           |  |  | 2189 |                 $action = '';
 | 
        
           |  |  | 2190 |             } else {
 | 
        
           |  |  | 2191 |                 $url->param('action', 'lock');
 | 
        
           |  |  | 2192 |                 $action = $OUTPUT->action_icon($url, new pix_icon('t/lock', $strlock));
 | 
        
           |  |  | 2193 |             }
 | 
        
           |  |  | 2194 |         }
 | 
        
           |  |  | 2195 |   | 
        
           |  |  | 2196 |         return $action;
 | 
        
           |  |  | 2197 |     }
 | 
        
           |  |  | 2198 |   | 
        
           |  |  | 2199 |     /**
 | 
        
           |  |  | 2200 |      * Returns link to lock/unlock grade/grade item/grade category
 | 
        
           |  |  | 2201 |      *
 | 
        
           |  |  | 2202 |      * @param array  $element An array representing an element in the grade_tree
 | 
        
           |  |  | 2203 |      * @param object $gpr A grade_plugin_return object
 | 
        
           |  |  | 2204 |      *
 | 
        
           |  |  | 2205 |      * @return string|null
 | 
        
           |  |  | 2206 |      */
 | 
        
           |  |  | 2207 |     public function get_locking_link(array $element, object $gpr): ?string {
 | 
        
           |  |  | 2208 |   | 
        
           |  |  | 2209 |         if (has_capability('moodle/grade:manage', $this->context) && isset($element['object'])) {
 | 
        
           |  |  | 2210 |             $title = '';
 | 
        
           |  |  | 2211 |             $url = new moodle_url('/grade/edit/tree/action.php',
 | 
        
           |  |  | 2212 |                 ['id' => $this->courseid, 'sesskey' => sesskey(), 'eid' => $element['eid']]);
 | 
        
           |  |  | 2213 |             $url = $gpr->add_url_params($url);
 | 
        
           |  |  | 2214 |   | 
        
           |  |  | 2215 |             if ($element['type'] == 'category') {
 | 
        
           |  |  | 2216 |                 // Grade categories themselves cannot be locked. We lock/unlock their grade items.
 | 
        
           |  |  | 2217 |                 $children = $element['object']->get_children(true);
 | 
        
           |  |  | 2218 |                 $alllocked = true;
 | 
        
           |  |  | 2219 |                 foreach ($children as $child) {
 | 
        
           |  |  | 2220 |                     if (!$child['object']->is_locked()) {
 | 
        
           |  |  | 2221 |                         $alllocked = false;
 | 
        
           |  |  | 2222 |                         break;
 | 
        
           |  |  | 2223 |                     }
 | 
        
           |  |  | 2224 |                 }
 | 
        
           |  |  | 2225 |                 if ($alllocked && has_capability('moodle/grade:unlock', $this->context)) {
 | 
        
           |  |  | 2226 |                     $title = get_string('unlock', 'grades');
 | 
        
           |  |  | 2227 |                     $url->param('action', 'unlock');
 | 
        
           |  |  | 2228 |                 } else if (!$alllocked && has_capability('moodle/grade:lock', $this->context)) {
 | 
        
           |  |  | 2229 |                     $title = get_string('lock', 'grades');
 | 
        
           |  |  | 2230 |                     $url->param('action', 'lock');
 | 
        
           |  |  | 2231 |                 } else {
 | 
        
           |  |  | 2232 |                     return null;
 | 
        
           |  |  | 2233 |                 }
 | 
        
           |  |  | 2234 |             } else if (($element['type'] == 'grade') && ($element['object']->grade_item->is_locked())) {
 | 
        
           |  |  | 2235 |                 // Don't allow an unlocking action for a grade whose grade item is locked: just print a state icon.
 | 
        
           |  |  | 2236 |                 $strparamobj = new stdClass();
 | 
        
           |  |  | 2237 |                 $strparamobj->itemname = $element['object']->grade_item->get_name(true, true);
 | 
        
           |  |  | 2238 |                 $strnonunlockable = get_string('nonunlockableverbose', 'grades', $strparamobj);
 | 
        
           |  |  | 2239 |                 $title = get_string('unlock', 'grades');
 | 
        
           |  |  | 2240 |                 return html_writer::span($title, 'text-muted dropdown-item', ['title' => $strnonunlockable,
 | 
        
           |  |  | 2241 |                     'aria-label' => $title, 'role' => 'menuitem']);
 | 
        
           |  |  | 2242 |             } else if ($element['object']->is_locked()) {
 | 
        
           |  |  | 2243 |                 if (has_capability('moodle/grade:unlock', $this->context)) {
 | 
        
           |  |  | 2244 |                     $title = get_string('unlock', 'grades');
 | 
        
           |  |  | 2245 |                     $url->param('action', 'unlock');
 | 
        
           |  |  | 2246 |                 } else {
 | 
        
           |  |  | 2247 |                     return null;
 | 
        
           |  |  | 2248 |                 }
 | 
        
           |  |  | 2249 |             } else {
 | 
        
           |  |  | 2250 |                 if (has_capability('moodle/grade:lock', $this->context)) {
 | 
        
           |  |  | 2251 |                     $title = get_string('lock', 'grades');
 | 
        
           |  |  | 2252 |                     $url->param('action', 'lock');
 | 
        
           |  |  | 2253 |                 } else {
 | 
        
           |  |  | 2254 |                     return null;
 | 
        
           |  |  | 2255 |                 }
 | 
        
           |  |  | 2256 |             }
 | 
        
           |  |  | 2257 |   | 
        
           |  |  | 2258 |             return html_writer::link($url, $title,
 | 
        
           |  |  | 2259 |                 ['class' => 'dropdown-item', 'aria-label' => $title, 'role' => 'menuitem']);
 | 
        
           |  |  | 2260 |         } else {
 | 
        
           |  |  | 2261 |             return null;
 | 
        
           |  |  | 2262 |         }
 | 
        
           |  |  | 2263 |     }
 | 
        
           |  |  | 2264 |   | 
        
           |  |  | 2265 |     /**
 | 
        
           |  |  | 2266 |      * Return calculation icon for given element
 | 
        
           |  |  | 2267 |      *
 | 
        
           |  |  | 2268 |      * @param array  $element An array representing an element in the grade_tree
 | 
        
           |  |  | 2269 |      * @param object $gpr A grade_plugin_return object
 | 
        
           |  |  | 2270 |      * @param bool $returnactionmenulink return the instance of action_menu_link instead of string
 | 
        
           |  |  | 2271 |      * @return string|action_menu_link
 | 
        
           |  |  | 2272 |      * @deprecated since Moodle 4.2 - The row is not shown anymore - we have actions menu.
 | 
        
           |  |  | 2273 |      * @todo MDL-77307 This will be deleted in Moodle 4.6.
 | 
        
           |  |  | 2274 |      */
 | 
        
           |  |  | 2275 |     public function get_calculation_icon($element, $gpr, $returnactionmenulink = false) {
 | 
        
           |  |  | 2276 |         global $CFG, $OUTPUT;
 | 
        
           |  |  | 2277 |         debugging('The function get_calculation_icon() is deprecated, please do not use it anymore.',
 | 
        
           |  |  | 2278 |             DEBUG_DEVELOPER);
 | 
        
           |  |  | 2279 |   | 
        
           |  |  | 2280 |         if (!has_capability('moodle/grade:manage', $this->context)) {
 | 
        
           |  |  | 2281 |             return $returnactionmenulink ? null : '';
 | 
        
           |  |  | 2282 |         }
 | 
        
           |  |  | 2283 |   | 
        
           |  |  | 2284 |         $type   = $element['type'];
 | 
        
           |  |  | 2285 |         $object = $element['object'];
 | 
        
           |  |  | 2286 |   | 
        
           |  |  | 2287 |         if ($type == 'item' or $type == 'courseitem' or $type == 'categoryitem') {
 | 
        
           |  |  | 2288 |             $strparams = $this->get_params_for_iconstr($element);
 | 
        
           |  |  | 2289 |             $streditcalculation = get_string('editcalculationverbose', 'grades', $strparams);
 | 
        
           |  |  | 2290 |   | 
        
           |  |  | 2291 |             $is_scale = $object->gradetype == GRADE_TYPE_SCALE;
 | 
        
           |  |  | 2292 |             $is_value = $object->gradetype == GRADE_TYPE_VALUE;
 | 
        
           |  |  | 2293 |   | 
        
           |  |  | 2294 |             // show calculation icon only when calculation possible
 | 
        
           |  |  | 2295 |             if (!$object->is_external_item() and ($is_scale or $is_value)) {
 | 
        
           |  |  | 2296 |                 if ($object->is_calculated()) {
 | 
        
           |  |  | 2297 |                     $icon = 't/calc';
 | 
        
           |  |  | 2298 |                 } else {
 | 
        
           |  |  | 2299 |                     $icon = 't/calc_off';
 | 
        
           |  |  | 2300 |                 }
 | 
        
           |  |  | 2301 |   | 
        
           |  |  | 2302 |                 $url = new moodle_url('/grade/edit/tree/calculation.php', array('courseid' => $this->courseid, 'id' => $object->id));
 | 
        
           |  |  | 2303 |                 $url = $gpr->add_url_params($url);
 | 
        
           |  |  | 2304 |                 if ($returnactionmenulink) {
 | 
        
           |  |  | 2305 |                     return new action_menu_link_secondary($url,
 | 
        
           |  |  | 2306 |                         new pix_icon($icon, $streditcalculation),
 | 
        
           |  |  | 2307 |                         get_string('editcalculation', 'grades'));
 | 
        
           |  |  | 2308 |                 } else {
 | 
        
           |  |  | 2309 |                     return $OUTPUT->action_icon($url, new pix_icon($icon, $streditcalculation));
 | 
        
           |  |  | 2310 |                 }
 | 
        
           |  |  | 2311 |             }
 | 
        
           |  |  | 2312 |         }
 | 
        
           |  |  | 2313 |   | 
        
           |  |  | 2314 |         return $returnactionmenulink ? null : '';
 | 
        
           |  |  | 2315 |     }
 | 
        
           |  |  | 2316 |   | 
        
           |  |  | 2317 |     /**
 | 
        
           |  |  | 2318 |      * Returns link to edit calculation for a grade item.
 | 
        
           |  |  | 2319 |      *
 | 
        
           |  |  | 2320 |      * @param array  $element An array representing an element in the grade_tree
 | 
        
           |  |  | 2321 |      * @param object $gpr A grade_plugin_return object
 | 
        
           |  |  | 2322 |      *
 | 
        
           |  |  | 2323 |      * @return string|null
 | 
        
           |  |  | 2324 |      */
 | 
        
           |  |  | 2325 |     public function get_edit_calculation_link(array $element, object $gpr): ?string {
 | 
        
           |  |  | 2326 |   | 
        
           |  |  | 2327 |         if (has_capability('moodle/grade:manage', $this->context) && isset($element['object'])) {
 | 
        
           |  |  | 2328 |             $object = $element['object'];
 | 
        
           |  |  | 2329 |             $isscale = $object->gradetype == GRADE_TYPE_SCALE;
 | 
        
           |  |  | 2330 |             $isvalue = $object->gradetype == GRADE_TYPE_VALUE;
 | 
        
           |  |  | 2331 |   | 
        
           |  |  | 2332 |             // Show calculation icon only when calculation possible.
 | 
        
           |  |  | 2333 |             if (!$object->is_external_item() && ($isscale || $isvalue)) {
 | 
        
           |  |  | 2334 |                 $editcalculationstring = get_string('editcalculation', 'grades');
 | 
        
           |  |  | 2335 |                 $url = new moodle_url('/grade/edit/tree/calculation.php',
 | 
        
           |  |  | 2336 |                     ['courseid' => $this->courseid, 'id' => $object->id]);
 | 
        
           |  |  | 2337 |                 $url = $gpr->add_url_params($url);
 | 
        
           |  |  | 2338 |                 return html_writer::link($url, $editcalculationstring,
 | 
        
           |  |  | 2339 |                     ['class' => 'dropdown-item', 'aria-label' => $editcalculationstring, 'role' => 'menuitem']);
 | 
        
           |  |  | 2340 |             }
 | 
        
           |  |  | 2341 |         }
 | 
        
           |  |  | 2342 |         return null;
 | 
        
           |  |  | 2343 |     }
 | 
        
           |  |  | 2344 |   | 
        
           |  |  | 2345 |     /**
 | 
        
           |  |  | 2346 |      * Sets status icons for the grade.
 | 
        
           |  |  | 2347 |      *
 | 
        
           |  |  | 2348 |      * @param array $element array with grade item info
 | 
        
           |  |  | 2349 |      * @return string|null status icons container HTML
 | 
        
           |  |  | 2350 |      */
 | 
        
           |  |  | 2351 |     public function set_grade_status_icons(array $element): ?string {
 | 
        
           |  |  | 2352 |         global $OUTPUT;
 | 
        
           |  |  | 2353 |   | 
        
           |  |  | 2354 |         $context = [
 | 
        
           |  |  | 2355 |             'hidden' => $element['object']->is_hidden(),
 | 
        
           |  |  | 2356 |         ];
 | 
        
           |  |  | 2357 |   | 
        
           |  |  | 2358 |         if ($element['object'] instanceof grade_grade) {
 | 
        
           |  |  | 2359 |             $grade = $element['object'];
 | 
        
           |  |  | 2360 |             $context['overridden'] = $grade->is_overridden();
 | 
        
           |  |  | 2361 |             $context['excluded'] = $grade->is_excluded();
 | 
        
           |  |  | 2362 |             $context['feedback'] = !empty($grade->feedback) && $grade->load_grade_item()->gradetype != GRADE_TYPE_TEXT;
 | 
        
           |  |  | 2363 |         }
 | 
        
           |  |  | 2364 |   | 
        
           |  |  | 2365 |         $context['classes'] = 'grade_icons data-collapse_gradeicons';
 | 
        
           |  |  | 2366 |   | 
        
           |  |  | 2367 |         if ($element['object'] instanceof grade_category) {
 | 
        
           |  |  | 2368 |             $context['classes'] = 'category_grade_icons';
 | 
        
           |  |  | 2369 |   | 
        
           |  |  | 2370 |             $children = $element['object']->get_children(true);
 | 
        
           |  |  | 2371 |             $alllocked = true;
 | 
        
           |  |  | 2372 |             foreach ($children as $child) {
 | 
        
           |  |  | 2373 |                 if (!$child['object']->is_locked()) {
 | 
        
           |  |  | 2374 |                     $alllocked = false;
 | 
        
           |  |  | 2375 |                     break;
 | 
        
           |  |  | 2376 |                 }
 | 
        
           |  |  | 2377 |             }
 | 
        
           |  |  | 2378 |             if ($alllocked) {
 | 
        
           |  |  | 2379 |                 $context['locked'] = true;
 | 
        
           |  |  | 2380 |             }
 | 
        
           |  |  | 2381 |         } else {
 | 
        
           |  |  | 2382 |             $context['locked'] = $element['object']->is_locked();
 | 
        
           |  |  | 2383 |         }
 | 
        
           |  |  | 2384 |   | 
        
           |  |  | 2385 |         // Don't even attempt rendering if there is no status to show.
 | 
        
           |  |  | 2386 |         if (in_array(true, $context)) {
 | 
        
           |  |  | 2387 |             return $OUTPUT->render_from_template('core_grades/status_icons', $context);
 | 
        
           |  |  | 2388 |         } else {
 | 
        
           |  |  | 2389 |             return null;
 | 
        
           |  |  | 2390 |         }
 | 
        
           |  |  | 2391 |     }
 | 
        
           |  |  | 2392 |   | 
        
           |  |  | 2393 |     /**
 | 
        
           |  |  | 2394 |      * Returns an action menu for the grade.
 | 
        
           |  |  | 2395 |      *
 | 
        
           |  |  | 2396 |      * @param array $element Array with cell info.
 | 
        
           |  |  | 2397 |      * @param string $mode Mode - gradeitem or user
 | 
        
           |  |  | 2398 |      * @param grade_plugin_return $gpr
 | 
        
           |  |  | 2399 |      * @param moodle_url|null $baseurl
 | 
        
           |  |  | 2400 |      * @return string
 | 
        
           |  |  | 2401 |      */
 | 
        
           |  |  | 2402 |     public function get_cell_action_menu(array $element, string $mode, grade_plugin_return $gpr,
 | 
        
           |  |  | 2403 |             ?moodle_url $baseurl = null): string {
 | 
        
           |  |  | 2404 |         global $OUTPUT, $USER;
 | 
        
           |  |  | 2405 |   | 
        
           |  |  | 2406 |         $context = new stdClass();
 | 
        
           |  |  | 2407 |   | 
        
           |  |  | 2408 |         if ($mode == 'gradeitem' || $mode == 'setup') {
 | 
        
           |  |  | 2409 |             $editable = true;
 | 
        
           |  |  | 2410 |   | 
        
           |  |  | 2411 |             if ($element['type'] == 'grade') {
 | 
        
           |  |  | 2412 |                 $context->datatype = 'grade';
 | 
        
           |  |  | 2413 |   | 
        
           |  |  | 2414 |                 $item = $element['object']->grade_item;
 | 
        
           |  |  | 2415 |                 if ($item->is_course_item() || $item->is_category_item()) {
 | 
        
           |  |  | 2416 |                     $editable = (bool)get_config('moodle', 'grade_overridecat');;
 | 
        
           |  |  | 2417 |                 }
 | 
        
           |  |  | 2418 |   | 
        
           |  |  | 2419 |                 if (!empty($USER->editing)) {
 | 
        
           |  |  | 2420 |                     if ($editable) {
 | 
        
           |  |  | 2421 |                         $context->editurl = $this->get_edit_link($element, $gpr);
 | 
        
           |  |  | 2422 |                     }
 | 
        
           |  |  | 2423 |                     $context->hideurl = $this->get_hiding_link($element, $gpr);
 | 
        
           |  |  | 2424 |                     $context->lockurl = $this->get_locking_link($element, $gpr);
 | 
        
           |  |  | 2425 |                 }
 | 
        
           |  |  | 2426 |   | 
        
           |  |  | 2427 |                 $context->gradeanalysisurl = $this->get_grade_analysis_link($element['object']);
 | 
        
           |  |  | 2428 |             } else if (($element['type'] == 'item') || ($element['type'] == 'categoryitem') ||
 | 
        
           |  |  | 2429 |                     ($element['type'] == 'courseitem') || ($element['type'] == 'userfield')) {
 | 
        
           |  |  | 2430 |   | 
        
           |  |  | 2431 |                 $context->datatype = 'item';
 | 
        
           |  |  | 2432 |   | 
        
           |  |  | 2433 |                 if ($element['type'] == 'item') {
 | 
        
           |  |  | 2434 |                     if ($mode == 'setup') {
 | 
        
           |  |  | 2435 |                         $context->deleteurl = $this->get_delete_link($element, $gpr);
 | 
        
           |  |  | 2436 |                         $context->duplicateurl = $this->get_duplicate_link($element, $gpr);
 | 
        
           |  |  | 2437 |                     } else {
 | 
        
           |  |  | 2438 |                         $context =
 | 
        
           |  |  | 2439 |                             grade_report::get_additional_context($this->context, $this->courseid,
 | 
        
           |  |  | 2440 |                                 $element, $gpr, $mode, $context, true);
 | 
        
           |  |  | 2441 |                         $context->advancedgradingurl = $this->get_advanced_grading_link($element, $gpr);
 | 
        
           |  |  | 2442 |                     }
 | 
        
           |  |  | 2443 |                     $context->divider1 = true;
 | 
        
           |  |  | 2444 |                 }
 | 
        
           |  |  | 2445 |   | 
        
           |  |  | 2446 |                 if (($element['type'] == 'item') ||
 | 
        
           |  |  | 2447 |                     (($element['type'] == 'userfield') && ($element['name'] !== 'fullname'))) {
 | 
        
           |  |  | 2448 |                     $context->divider2 = true;
 | 
        
           |  |  | 2449 |                 }
 | 
        
           |  |  | 2450 |   | 
        
           |  |  | 2451 |                 if (!empty($USER->editing) || $mode == 'setup') {
 | 
        
           |  |  | 2452 |                     if (($element['type'] == 'userfield') && ($element['name'] !== 'fullname')) {
 | 
        
           |  |  | 2453 |                         $context->divider2 = true;
 | 
        
           |  |  | 2454 |                     } else if (($mode !== 'setup') && ($element['type'] !== 'userfield')) {
 | 
        
           |  |  | 2455 |                         $context->divider1 = true;
 | 
        
           |  |  | 2456 |                         $context->divider2 = true;
 | 
        
           |  |  | 2457 |                     }
 | 
        
           |  |  | 2458 |   | 
        
           |  |  | 2459 |                     if ($element['type'] == 'item') {
 | 
        
           |  |  | 2460 |                         $context->editurl = $this->get_edit_link($element, $gpr);
 | 
        
           |  |  | 2461 |                     }
 | 
        
           |  |  | 2462 |   | 
        
           |  |  | 2463 |                     $context->editcalculationurl =
 | 
        
           |  |  | 2464 |                         $this->get_edit_calculation_link($element, $gpr);
 | 
        
           |  |  | 2465 |   | 
        
           |  |  | 2466 |                     if (isset($element['object'])) {
 | 
        
           |  |  | 2467 |                         $object = $element['object'];
 | 
        
           |  |  | 2468 |                         if ($object->itemmodule !== 'quiz') {
 | 
        
           |  |  | 2469 |                             $context->hideurl = $this->get_hiding_link($element, $gpr);
 | 
        
           |  |  | 2470 |                         }
 | 
        
           |  |  | 2471 |                     }
 | 
        
           |  |  | 2472 |                     $context->lockurl = $this->get_locking_link($element, $gpr);
 | 
        
           |  |  | 2473 |                 }
 | 
        
           |  |  | 2474 |   | 
        
           |  |  | 2475 |                 // Sorting item.
 | 
        
           |  |  | 2476 |                 if ($baseurl) {
 | 
        
           |  |  | 2477 |                     $sortlink = clone($baseurl);
 | 
        
           |  |  | 2478 |                     if (isset($element['object']->id)) {
 | 
        
           |  |  | 2479 |                         $sortlink->param('sortitemid', $element['object']->id);
 | 
        
           |  |  | 2480 |                     } else if ($element['type'] == 'userfield') {
 | 
        
           |  |  | 2481 |                         $context->datatype = $element['name'];
 | 
        
           |  |  | 2482 |                         $sortlink->param('sortitemid', $element['name']);
 | 
        
           |  |  | 2483 |                     }
 | 
        
           |  |  | 2484 |   | 
        
           |  |  | 2485 |                     if (($element['type'] == 'userfield') && ($element['name'] == 'fullname')) {
 | 
        
           |  |  | 2486 |                         $sortlink->param('sortitemid', 'firstname');
 | 
        
           |  |  | 2487 |                         $context->ascendingfirstnameurl = $this->get_sorting_link($sortlink, $gpr);
 | 
        
           |  |  | 2488 |                         $context->descendingfirstnameurl = $this->get_sorting_link($sortlink, $gpr, 'desc');
 | 
        
           |  |  | 2489 |   | 
        
           |  |  | 2490 |                         $sortlink->param('sortitemid', 'lastname');
 | 
        
           |  |  | 2491 |                         $context->ascendinglastnameurl = $this->get_sorting_link($sortlink, $gpr);
 | 
        
           |  |  | 2492 |                         $context->descendinglastnameurl = $this->get_sorting_link($sortlink, $gpr, 'desc');
 | 
        
           |  |  | 2493 |                     } else {
 | 
        
           |  |  | 2494 |                         $context->ascendingurl = $this->get_sorting_link($sortlink, $gpr);
 | 
        
           |  |  | 2495 |                         $context->descendingurl = $this->get_sorting_link($sortlink, $gpr, 'desc');
 | 
        
           |  |  | 2496 |                     }
 | 
        
           |  |  | 2497 |                 }
 | 
        
           |  |  | 2498 |                 if ($mode !== 'setup') {
 | 
        
           |  |  | 2499 |                     $context = grade_report::get_additional_context($this->context, $this->courseid,
 | 
        
           |  |  | 2500 |                         $element, $gpr, $mode, $context);
 | 
        
           |  |  | 2501 |                 }
 | 
        
           |  |  | 2502 |             } else if ($element['type'] == 'category') {
 | 
        
           |  |  | 2503 |                 $context->datatype = 'category';
 | 
        
           |  |  | 2504 |                 if ($mode !== 'setup') {
 | 
        
           |  |  | 2505 |                     $mode = 'category';
 | 
        
           |  |  | 2506 |                     $context = grade_report::get_additional_context($this->context, $this->courseid,
 | 
        
           |  |  | 2507 |                         $element, $gpr, $mode, $context);
 | 
        
           |  |  | 2508 |                 } else {
 | 
        
           |  |  | 2509 |                     $context->deleteurl = $this->get_delete_link($element, $gpr);
 | 
        
           |  |  | 2510 |                     $context->resetweightsurl = $this->get_reset_weights_link($element, $gpr);
 | 
        
           |  |  | 2511 |                 }
 | 
        
           |  |  | 2512 |   | 
        
           |  |  | 2513 |                 if (!empty($USER->editing) || $mode == 'setup') {
 | 
        
           |  |  | 2514 |                     if ($mode !== 'setup') {
 | 
        
           |  |  | 2515 |                         $context->divider1 = true;
 | 
        
           |  |  | 2516 |                     }
 | 
        
           |  |  | 2517 |                     $context->editurl = $this->get_edit_link($element, $gpr);
 | 
        
           |  |  | 2518 |                     $context->hideurl = $this->get_hiding_link($element, $gpr);
 | 
        
           |  |  | 2519 |                     $context->lockurl = $this->get_locking_link($element, $gpr);
 | 
        
           |  |  | 2520 |                 }
 | 
        
           |  |  | 2521 |             }
 | 
        
           |  |  | 2522 |   | 
        
           |  |  | 2523 |             if (isset($element['object'])) {
 | 
        
           |  |  | 2524 |                 $context->dataid = $element['object']->id;
 | 
        
           |  |  | 2525 |             } else if ($element['type'] == 'userfield') {
 | 
        
           |  |  | 2526 |                 $context->dataid = $element['name'];
 | 
        
           |  |  | 2527 |             }
 | 
        
           |  |  | 2528 |   | 
        
           |  |  | 2529 |             if ($element['type'] != 'text' && !empty($element['object']->feedback)) {
 | 
        
           |  |  | 2530 |                 $viewfeedbackstring = get_string('viewfeedback', 'grades');
 | 
        
           |  |  | 2531 |                 $context->viewfeedbackurl = html_writer::link('#', $viewfeedbackstring, ['class' => 'dropdown-item',
 | 
        
           |  |  | 2532 |                     'aria-label' => $viewfeedbackstring, 'role' => 'menuitem', 'data-action' => 'feedback',
 | 
        
           |  |  | 2533 |                     'data-courseid' => $this->courseid]);
 | 
        
           |  |  | 2534 |             }
 | 
        
           |  |  | 2535 |         } else if ($mode == 'user') {
 | 
        
           |  |  | 2536 |             $context->datatype = 'user';
 | 
        
           |  |  | 2537 |             $context = grade_report::get_additional_context($this->context, $this->courseid, $element, $gpr, $mode, $context, true);
 | 
        
           |  |  | 2538 |             $context->dataid = $element['userid'];
 | 
        
           |  |  | 2539 |         }
 | 
        
           |  |  | 2540 |   | 
        
           |  |  | 2541 |         // Omit the second divider if there is nothing between it and the first divider.
 | 
        
           |  |  | 2542 |         if (!isset($context->ascendingfirstnameurl) && !isset($context->ascendingurl)) {
 | 
        
           |  |  | 2543 |             $context->divider2 = false;
 | 
        
           |  |  | 2544 |         }
 | 
        
           |  |  | 2545 |   | 
        
           |  |  | 2546 |         if ($mode == 'setup') {
 | 
        
           |  |  | 2547 |             $context->databoundary = 'window';
 | 
        
           |  |  | 2548 |         }
 | 
        
           |  |  | 2549 |   | 
        
           |  |  | 2550 |         if (!empty($USER->editing) || isset($context->gradeanalysisurl) || isset($context->gradesonlyurl)
 | 
        
           |  |  | 2551 |                 || isset($context->aggregatesonlyurl) || isset($context->fullmodeurl) || isset($context->reporturl0)
 | 
        
           |  |  | 2552 |                 || isset($context->ascendingfirstnameurl) || isset($context->ascendingurl)
 | 
        
           |  |  | 2553 |                 || isset($context->viewfeedbackurl) || ($mode == 'setup')) {
 | 
        
           |  |  | 2554 |             return $OUTPUT->render_from_template('core_grades/cellmenu', $context);
 | 
        
           |  |  | 2555 |         }
 | 
        
           |  |  | 2556 |         return '';
 | 
        
           |  |  | 2557 |     }
 | 
        
           |  |  | 2558 |   | 
        
           |  |  | 2559 |     /**
 | 
        
           |  |  | 2560 |      * Returns link to sort grade item column
 | 
        
           |  |  | 2561 |      *
 | 
        
           |  |  | 2562 |      * @param moodle_url $sortlink A base link for sorting
 | 
        
           |  |  | 2563 |      * @param object $gpr A grade_plugin_return object
 | 
        
           |  |  | 2564 |      * @param string $direction Direction od sorting
 | 
        
           |  |  | 2565 |      * @return string
 | 
        
           |  |  | 2566 |      */
 | 
        
           |  |  | 2567 |     public function get_sorting_link(moodle_url $sortlink, object $gpr, string $direction = 'asc'): string {
 | 
        
           |  |  | 2568 |   | 
        
           |  |  | 2569 |         if ($direction == 'asc') {
 | 
        
           |  |  | 2570 |             $title = get_string('asc');
 | 
        
           |  |  | 2571 |         } else {
 | 
        
           |  |  | 2572 |             $title = get_string('desc');
 | 
        
           |  |  | 2573 |         }
 | 
        
           |  |  | 2574 |   | 
        
           |  |  | 2575 |         $sortlink->param('sort', $direction);
 | 
        
           |  |  | 2576 |         $gpr->add_url_params($sortlink);
 | 
        
           |  |  | 2577 |         return html_writer::link($sortlink, $title,
 | 
        
           |  |  | 2578 |             ['class' => 'dropdown-item', 'aria-label' => $title, 'role' => 'menuitem']);
 | 
        
           |  |  | 2579 |     }
 | 
        
           |  |  | 2580 |   | 
        
           |  |  | 2581 | }
 | 
        
           |  |  | 2582 |   | 
        
           |  |  | 2583 | /**
 | 
        
           |  |  | 2584 |  * Flat structure similar to grade tree.
 | 
        
           |  |  | 2585 |  *
 | 
        
           |  |  | 2586 |  * @uses grade_structure
 | 
        
           |  |  | 2587 |  * @package core_grades
 | 
        
           |  |  | 2588 |  * @copyright 2009 Nicolas Connault
 | 
        
           |  |  | 2589 |  * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
 | 
        
           |  |  | 2590 |  */
 | 
        
           |  |  | 2591 | class grade_seq extends grade_structure {
 | 
        
           |  |  | 2592 |   | 
        
           |  |  | 2593 |     /**
 | 
        
           |  |  | 2594 |      * 1D array of elements
 | 
        
           |  |  | 2595 |      */
 | 
        
           |  |  | 2596 |     public $elements;
 | 
        
           |  |  | 2597 |   | 
        
           |  |  | 2598 |     /**
 | 
        
           |  |  | 2599 |      * Constructor, retrieves and stores array of all grade_category and grade_item
 | 
        
           |  |  | 2600 |      * objects for the given courseid. Full objects are instantiated. Ordering sequence is fixed if needed.
 | 
        
           |  |  | 2601 |      *
 | 
        
           |  |  | 2602 |      * @param int  $courseid The course id
 | 
        
           |  |  | 2603 |      * @param bool $category_grade_last category grade item is the last child
 | 
        
           |  |  | 2604 |      * @param bool $nooutcomes Whether or not outcomes should be included
 | 
        
           |  |  | 2605 |      */
 | 
        
           |  |  | 2606 |     public function __construct($courseid, $category_grade_last=false, $nooutcomes=false) {
 | 
        
           |  |  | 2607 |         global $USER, $CFG;
 | 
        
           |  |  | 2608 |   | 
        
           |  |  | 2609 |         $this->courseid   = $courseid;
 | 
        
           |  |  | 2610 |         $this->context    = context_course::instance($courseid);
 | 
        
           |  |  | 2611 |   | 
        
           |  |  | 2612 |         // get course grade tree
 | 
        
           |  |  | 2613 |         $top_element = grade_category::fetch_course_tree($courseid, true);
 | 
        
           |  |  | 2614 |   | 
        
           |  |  | 2615 |         $this->elements = grade_seq::flatten($top_element, $category_grade_last, $nooutcomes);
 | 
        
           |  |  | 2616 |   | 
        
           |  |  | 2617 |         foreach ($this->elements as $key=>$unused) {
 | 
        
           |  |  | 2618 |             $this->items[$this->elements[$key]['object']->id] =& $this->elements[$key]['object'];
 | 
        
           |  |  | 2619 |         }
 | 
        
           |  |  | 2620 |     }
 | 
        
           |  |  | 2621 |   | 
        
           |  |  | 2622 |     /**
 | 
        
           |  |  | 2623 |      * Old syntax of class constructor. Deprecated in PHP7.
 | 
        
           |  |  | 2624 |      *
 | 
        
           |  |  | 2625 |      * @deprecated since Moodle 3.1
 | 
        
           |  |  | 2626 |      */
 | 
        
           |  |  | 2627 |     public function grade_seq($courseid, $category_grade_last=false, $nooutcomes=false) {
 | 
        
           |  |  | 2628 |         debugging('Use of class name as constructor is deprecated', DEBUG_DEVELOPER);
 | 
        
           |  |  | 2629 |         self::__construct($courseid, $category_grade_last, $nooutcomes);
 | 
        
           |  |  | 2630 |     }
 | 
        
           |  |  | 2631 |   | 
        
           |  |  | 2632 |     /**
 | 
        
           |  |  | 2633 |      * Static recursive helper - makes the grade_item for category the last children
 | 
        
           |  |  | 2634 |      *
 | 
        
           |  |  | 2635 |      * @param array &$element The seed of the recursion
 | 
        
           |  |  | 2636 |      * @param bool $category_grade_last category grade item is the last child
 | 
        
           |  |  | 2637 |      * @param bool $nooutcomes Whether or not outcomes should be included
 | 
        
           |  |  | 2638 |      *
 | 
        
           |  |  | 2639 |      * @return array
 | 
        
           |  |  | 2640 |      */
 | 
        
           |  |  | 2641 |     public function flatten(&$element, $category_grade_last, $nooutcomes) {
 | 
        
           |  |  | 2642 |         if (empty($element['children'])) {
 | 
        
           |  |  | 2643 |             return array();
 | 
        
           |  |  | 2644 |         }
 | 
        
           |  |  | 2645 |         $children = array();
 | 
        
           |  |  | 2646 |   | 
        
           |  |  | 2647 |         foreach ($element['children'] as $sortorder=>$unused) {
 | 
        
           |  |  | 2648 |             if ($nooutcomes and $element['type'] != 'category' and
 | 
        
           |  |  | 2649 |                 $element['children'][$sortorder]['object']->is_outcome_item()) {
 | 
        
           |  |  | 2650 |                 continue;
 | 
        
           |  |  | 2651 |             }
 | 
        
           |  |  | 2652 |             $children[] = $element['children'][$sortorder];
 | 
        
           |  |  | 2653 |         }
 | 
        
           |  |  | 2654 |         unset($element['children']);
 | 
        
           |  |  | 2655 |   | 
        
           |  |  | 2656 |         if ($category_grade_last and count($children) > 1 and
 | 
        
           |  |  | 2657 |             (
 | 
        
           |  |  | 2658 |                 $children[0]['type'] === 'courseitem' or
 | 
        
           |  |  | 2659 |                 $children[0]['type'] === 'categoryitem'
 | 
        
           |  |  | 2660 |             )
 | 
        
           |  |  | 2661 |         ) {
 | 
        
           |  |  | 2662 |             $cat_item = array_shift($children);
 | 
        
           |  |  | 2663 |             array_push($children, $cat_item);
 | 
        
           |  |  | 2664 |         }
 | 
        
           |  |  | 2665 |   | 
        
           |  |  | 2666 |         $result = array();
 | 
        
           |  |  | 2667 |         foreach ($children as $child) {
 | 
        
           |  |  | 2668 |             if ($child['type'] == 'category') {
 | 
        
           |  |  | 2669 |                 $result = $result + grade_seq::flatten($child, $category_grade_last, $nooutcomes);
 | 
        
           |  |  | 2670 |             } else {
 | 
        
           |  |  | 2671 |                 $child['eid'] = 'i'.$child['object']->id;
 | 
        
           |  |  | 2672 |                 $result[$child['object']->id] = $child;
 | 
        
           |  |  | 2673 |             }
 | 
        
           |  |  | 2674 |         }
 | 
        
           |  |  | 2675 |   | 
        
           |  |  | 2676 |         return $result;
 | 
        
           |  |  | 2677 |     }
 | 
        
           |  |  | 2678 |   | 
        
           |  |  | 2679 |     /**
 | 
        
           |  |  | 2680 |      * Parses the array in search of a given eid and returns a element object with
 | 
        
           |  |  | 2681 |      * information about the element it has found.
 | 
        
           |  |  | 2682 |      *
 | 
        
           |  |  | 2683 |      * @param int $eid Gradetree Element ID
 | 
        
           |  |  | 2684 |      *
 | 
        
           |  |  | 2685 |      * @return object element
 | 
        
           |  |  | 2686 |      */
 | 
        
           |  |  | 2687 |     public function locate_element($eid) {
 | 
        
           |  |  | 2688 |         // it is a grade - construct a new object
 | 
        
           |  |  | 2689 |         if (strpos($eid, 'n') === 0) {
 | 
        
           |  |  | 2690 |             if (!preg_match('/n(\d+)u(\d+)/', $eid, $matches)) {
 | 
        
           |  |  | 2691 |                 return null;
 | 
        
           |  |  | 2692 |             }
 | 
        
           |  |  | 2693 |   | 
        
           |  |  | 2694 |             $itemid = $matches[1];
 | 
        
           |  |  | 2695 |             $userid = $matches[2];
 | 
        
           |  |  | 2696 |   | 
        
           |  |  | 2697 |             //extra security check - the grade item must be in this tree
 | 
        
           |  |  | 2698 |             if (!$item_el = $this->locate_element('ig'.$itemid)) {
 | 
        
           |  |  | 2699 |                 return null;
 | 
        
           |  |  | 2700 |             }
 | 
        
           |  |  | 2701 |   | 
        
           |  |  | 2702 |             // $gradea->id may be null - means does not exist yet
 | 
        
           |  |  | 2703 |             $grade = new grade_grade(array('itemid'=>$itemid, 'userid'=>$userid));
 | 
        
           |  |  | 2704 |   | 
        
           |  |  | 2705 |             $grade->grade_item =& $item_el['object']; // this may speedup grade_grade methods!
 | 
        
           |  |  | 2706 |             return array('eid'=>'n'.$itemid.'u'.$userid,'object'=>$grade, 'type'=>'grade');
 | 
        
           |  |  | 2707 |   | 
        
           |  |  | 2708 |         } else if (strpos($eid, 'g') === 0) {
 | 
        
           |  |  | 2709 |             $id = (int) substr($eid, 1);
 | 
        
           |  |  | 2710 |             if (!$grade = grade_grade::fetch(array('id'=>$id))) {
 | 
        
           |  |  | 2711 |                 return null;
 | 
        
           |  |  | 2712 |             }
 | 
        
           |  |  | 2713 |             //extra security check - the grade item must be in this tree
 | 
        
           |  |  | 2714 |             if (!$item_el = $this->locate_element('ig'.$grade->itemid)) {
 | 
        
           |  |  | 2715 |                 return null;
 | 
        
           |  |  | 2716 |             }
 | 
        
           |  |  | 2717 |             $grade->grade_item =& $item_el['object']; // this may speedup grade_grade methods!
 | 
        
           |  |  | 2718 |             return array('eid'=>'g'.$id,'object'=>$grade, 'type'=>'grade');
 | 
        
           |  |  | 2719 |         }
 | 
        
           |  |  | 2720 |   | 
        
           |  |  | 2721 |         // it is a category or item
 | 
        
           |  |  | 2722 |         foreach ($this->elements as $element) {
 | 
        
           |  |  | 2723 |             if ($element['eid'] == $eid) {
 | 
        
           |  |  | 2724 |                 return $element;
 | 
        
           |  |  | 2725 |             }
 | 
        
           |  |  | 2726 |         }
 | 
        
           |  |  | 2727 |   | 
        
           |  |  | 2728 |         return null;
 | 
        
           |  |  | 2729 |     }
 | 
        
           |  |  | 2730 | }
 | 
        
           |  |  | 2731 |   | 
        
           |  |  | 2732 | /**
 | 
        
           |  |  | 2733 |  * This class represents a complete tree of categories, grade_items and final grades,
 | 
        
           |  |  | 2734 |  * organises as an array primarily, but which can also be converted to other formats.
 | 
        
           |  |  | 2735 |  * It has simple method calls with complex implementations, allowing for easy insertion,
 | 
        
           |  |  | 2736 |  * deletion and moving of items and categories within the tree.
 | 
        
           |  |  | 2737 |  *
 | 
        
           |  |  | 2738 |  * @uses grade_structure
 | 
        
           |  |  | 2739 |  * @package core_grades
 | 
        
           |  |  | 2740 |  * @copyright 2009 Nicolas Connault
 | 
        
           |  |  | 2741 |  * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
 | 
        
           |  |  | 2742 |  */
 | 
        
           |  |  | 2743 | class grade_tree extends grade_structure {
 | 
        
           |  |  | 2744 |   | 
        
           |  |  | 2745 |     /**
 | 
        
           |  |  | 2746 |      * The basic representation of the tree as a hierarchical, 3-tiered array.
 | 
        
           |  |  | 2747 |      * @var object $top_element
 | 
        
           |  |  | 2748 |      */
 | 
        
           |  |  | 2749 |     public $top_element;
 | 
        
           |  |  | 2750 |   | 
        
           |  |  | 2751 |     /**
 | 
        
           |  |  | 2752 |      * 2D array of grade items and categories
 | 
        
           |  |  | 2753 |      * @var array $levels
 | 
        
           |  |  | 2754 |      */
 | 
        
           |  |  | 2755 |     public $levels;
 | 
        
           |  |  | 2756 |   | 
        
           |  |  | 2757 |     /**
 | 
        
           |  |  | 2758 |      * Grade items
 | 
        
           |  |  | 2759 |      * @var array $items
 | 
        
           |  |  | 2760 |      */
 | 
        
           |  |  | 2761 |     public $items;
 | 
        
           |  |  | 2762 |   | 
        
           |  |  | 2763 |     /**
 | 
        
           |  |  | 2764 |      * Constructor, retrieves and stores a hierarchical array of all grade_category and grade_item
 | 
        
           |  |  | 2765 |      * objects for the given courseid. Full objects are instantiated. Ordering sequence is fixed if needed.
 | 
        
           |  |  | 2766 |      *
 | 
        
           |  |  | 2767 |      * @param int   $courseid The Course ID
 | 
        
           |  |  | 2768 |      * @param bool  $fillers include fillers and colspans, make the levels var "rectangular"
 | 
        
           |  |  | 2769 |      * @param bool  $category_grade_last category grade item is the last child
 | 
        
           |  |  | 2770 |      * @param array $collapsed array of collapsed categories
 | 
        
           |  |  | 2771 |      * @param bool  $nooutcomes Whether or not outcomes should be included
 | 
        
           |  |  | 2772 |      */
 | 
        
           |  |  | 2773 |     public function __construct($courseid, $fillers=true, $category_grade_last=false,
 | 
        
           |  |  | 2774 |                                $collapsed=null, $nooutcomes=false) {
 | 
        
           |  |  | 2775 |         global $USER, $CFG, $COURSE, $DB;
 | 
        
           |  |  | 2776 |   | 
        
           |  |  | 2777 |         $this->courseid   = $courseid;
 | 
        
           |  |  | 2778 |         $this->levels     = array();
 | 
        
           |  |  | 2779 |         $this->context    = context_course::instance($courseid);
 | 
        
           | 1441 | ariadna | 2780 |         $this->items      = [];
 | 
        
           | 1 | efrain | 2781 |   | 
        
           |  |  | 2782 |         if (!empty($COURSE->id) && $COURSE->id == $this->courseid) {
 | 
        
           |  |  | 2783 |             $course = $COURSE;
 | 
        
           |  |  | 2784 |         } else {
 | 
        
           |  |  | 2785 |             $course = $DB->get_record('course', array('id' => $this->courseid));
 | 
        
           |  |  | 2786 |         }
 | 
        
           |  |  | 2787 |         $this->modinfo = get_fast_modinfo($course);
 | 
        
           |  |  | 2788 |   | 
        
           |  |  | 2789 |         // get course grade tree
 | 
        
           |  |  | 2790 |         $this->top_element = grade_category::fetch_course_tree($courseid, true);
 | 
        
           |  |  | 2791 |   | 
        
           |  |  | 2792 |         // collapse the categories if requested
 | 
        
           |  |  | 2793 |         if (!empty($collapsed)) {
 | 
        
           |  |  | 2794 |             grade_tree::category_collapse($this->top_element, $collapsed);
 | 
        
           |  |  | 2795 |         }
 | 
        
           |  |  | 2796 |   | 
        
           |  |  | 2797 |         // no otucomes if requested
 | 
        
           |  |  | 2798 |         if (!empty($nooutcomes)) {
 | 
        
           |  |  | 2799 |             grade_tree::no_outcomes($this->top_element);
 | 
        
           |  |  | 2800 |         }
 | 
        
           |  |  | 2801 |   | 
        
           |  |  | 2802 |         // move category item to last position in category
 | 
        
           |  |  | 2803 |         if ($category_grade_last) {
 | 
        
           |  |  | 2804 |             grade_tree::category_grade_last($this->top_element);
 | 
        
           |  |  | 2805 |         }
 | 
        
           |  |  | 2806 |   | 
        
           |  |  | 2807 |         if ($fillers) {
 | 
        
           |  |  | 2808 |             // inject fake categories == fillers
 | 
        
           |  |  | 2809 |             grade_tree::inject_fillers($this->top_element, 0);
 | 
        
           |  |  | 2810 |             // add colspans to categories and fillers
 | 
        
           |  |  | 2811 |             grade_tree::inject_colspans($this->top_element);
 | 
        
           |  |  | 2812 |         }
 | 
        
           |  |  | 2813 |   | 
        
           |  |  | 2814 |         grade_tree::fill_levels($this->levels, $this->top_element, 0);
 | 
        
           |  |  | 2815 |   | 
        
           |  |  | 2816 |     }
 | 
        
           |  |  | 2817 |   | 
        
           |  |  | 2818 |     /**
 | 
        
           |  |  | 2819 |      * Old syntax of class constructor. Deprecated in PHP7.
 | 
        
           |  |  | 2820 |      *
 | 
        
           |  |  | 2821 |      * @deprecated since Moodle 3.1
 | 
        
           |  |  | 2822 |      */
 | 
        
           |  |  | 2823 |     public function grade_tree($courseid, $fillers=true, $category_grade_last=false,
 | 
        
           |  |  | 2824 |                                $collapsed=null, $nooutcomes=false) {
 | 
        
           |  |  | 2825 |         debugging('Use of class name as constructor is deprecated', DEBUG_DEVELOPER);
 | 
        
           |  |  | 2826 |         self::__construct($courseid, $fillers, $category_grade_last, $collapsed, $nooutcomes);
 | 
        
           |  |  | 2827 |     }
 | 
        
           |  |  | 2828 |   | 
        
           |  |  | 2829 |     /**
 | 
        
           |  |  | 2830 |      * Static recursive helper - removes items from collapsed categories
 | 
        
           |  |  | 2831 |      *
 | 
        
           |  |  | 2832 |      * @param array &$element The seed of the recursion
 | 
        
           |  |  | 2833 |      * @param array $collapsed array of collapsed categories
 | 
        
           |  |  | 2834 |      *
 | 
        
           |  |  | 2835 |      * @return void
 | 
        
           |  |  | 2836 |      */
 | 
        
           |  |  | 2837 |     public function category_collapse(&$element, $collapsed) {
 | 
        
           |  |  | 2838 |         if ($element['type'] != 'category') {
 | 
        
           |  |  | 2839 |             return;
 | 
        
           |  |  | 2840 |         }
 | 
        
           |  |  | 2841 |         if (empty($element['children']) or count($element['children']) < 2) {
 | 
        
           |  |  | 2842 |             return;
 | 
        
           |  |  | 2843 |         }
 | 
        
           |  |  | 2844 |   | 
        
           |  |  | 2845 |         if (in_array($element['object']->id, $collapsed['aggregatesonly'])) {
 | 
        
           |  |  | 2846 |             $category_item = reset($element['children']); //keep only category item
 | 
        
           |  |  | 2847 |             $element['children'] = array(key($element['children'])=>$category_item);
 | 
        
           |  |  | 2848 |   | 
        
           |  |  | 2849 |         } else {
 | 
        
           |  |  | 2850 |             if (in_array($element['object']->id, $collapsed['gradesonly'])) { // Remove category item
 | 
        
           |  |  | 2851 |                 reset($element['children']);
 | 
        
           |  |  | 2852 |                 $first_key = key($element['children']);
 | 
        
           |  |  | 2853 |                 unset($element['children'][$first_key]);
 | 
        
           |  |  | 2854 |             }
 | 
        
           |  |  | 2855 |             foreach ($element['children'] as $sortorder=>$child) { // Recurse through the element's children
 | 
        
           |  |  | 2856 |                 grade_tree::category_collapse($element['children'][$sortorder], $collapsed);
 | 
        
           |  |  | 2857 |             }
 | 
        
           |  |  | 2858 |         }
 | 
        
           |  |  | 2859 |     }
 | 
        
           |  |  | 2860 |   | 
        
           |  |  | 2861 |     /**
 | 
        
           |  |  | 2862 |      * Static recursive helper - removes all outcomes
 | 
        
           |  |  | 2863 |      *
 | 
        
           |  |  | 2864 |      * @param array &$element The seed of the recursion
 | 
        
           |  |  | 2865 |      *
 | 
        
           |  |  | 2866 |      * @return void
 | 
        
           |  |  | 2867 |      */
 | 
        
           |  |  | 2868 |     public function no_outcomes(&$element) {
 | 
        
           |  |  | 2869 |         if ($element['type'] != 'category') {
 | 
        
           |  |  | 2870 |             return;
 | 
        
           |  |  | 2871 |         }
 | 
        
           |  |  | 2872 |         foreach ($element['children'] as $sortorder=>$child) {
 | 
        
           |  |  | 2873 |             if ($element['children'][$sortorder]['type'] == 'item'
 | 
        
           |  |  | 2874 |               and $element['children'][$sortorder]['object']->is_outcome_item()) {
 | 
        
           |  |  | 2875 |                 unset($element['children'][$sortorder]);
 | 
        
           |  |  | 2876 |   | 
        
           |  |  | 2877 |             } else if ($element['children'][$sortorder]['type'] == 'category') {
 | 
        
           |  |  | 2878 |                 grade_tree::no_outcomes($element['children'][$sortorder]);
 | 
        
           |  |  | 2879 |             }
 | 
        
           |  |  | 2880 |         }
 | 
        
           |  |  | 2881 |     }
 | 
        
           |  |  | 2882 |   | 
        
           |  |  | 2883 |     /**
 | 
        
           |  |  | 2884 |      * Static recursive helper - makes the grade_item for category the last children
 | 
        
           |  |  | 2885 |      *
 | 
        
           |  |  | 2886 |      * @param array &$element The seed of the recursion
 | 
        
           |  |  | 2887 |      *
 | 
        
           |  |  | 2888 |      * @return void
 | 
        
           |  |  | 2889 |      */
 | 
        
           |  |  | 2890 |     public function category_grade_last(&$element) {
 | 
        
           |  |  | 2891 |         if (empty($element['children'])) {
 | 
        
           |  |  | 2892 |             return;
 | 
        
           |  |  | 2893 |         }
 | 
        
           |  |  | 2894 |         if (count($element['children']) < 2) {
 | 
        
           |  |  | 2895 |             return;
 | 
        
           |  |  | 2896 |         }
 | 
        
           |  |  | 2897 |         $first_item = reset($element['children']);
 | 
        
           |  |  | 2898 |         if ($first_item['type'] == 'categoryitem' or $first_item['type'] == 'courseitem') {
 | 
        
           |  |  | 2899 |             // the category item might have been already removed
 | 
        
           |  |  | 2900 |             $order = key($element['children']);
 | 
        
           |  |  | 2901 |             unset($element['children'][$order]);
 | 
        
           |  |  | 2902 |             $element['children'][$order] =& $first_item;
 | 
        
           |  |  | 2903 |         }
 | 
        
           |  |  | 2904 |         foreach ($element['children'] as $sortorder => $child) {
 | 
        
           |  |  | 2905 |             grade_tree::category_grade_last($element['children'][$sortorder]);
 | 
        
           |  |  | 2906 |         }
 | 
        
           |  |  | 2907 |     }
 | 
        
           |  |  | 2908 |   | 
        
           |  |  | 2909 |     /**
 | 
        
           |  |  | 2910 |      * Static recursive helper - fills the levels array, useful when accessing tree elements of one level
 | 
        
           |  |  | 2911 |      *
 | 
        
           |  |  | 2912 |      * @param array &$levels The levels of the grade tree through which to recurse
 | 
        
           |  |  | 2913 |      * @param array &$element The seed of the recursion
 | 
        
           |  |  | 2914 |      * @param int   $depth How deep are we?
 | 
        
           |  |  | 2915 |      * @return void
 | 
        
           |  |  | 2916 |      */
 | 
        
           |  |  | 2917 |     public function fill_levels(&$levels, &$element, $depth) {
 | 
        
           |  |  | 2918 |         if (!array_key_exists($depth, $levels)) {
 | 
        
           |  |  | 2919 |             $levels[$depth] = array();
 | 
        
           |  |  | 2920 |         }
 | 
        
           |  |  | 2921 |   | 
        
           |  |  | 2922 |         // prepare unique identifier
 | 
        
           |  |  | 2923 |         if ($element['type'] == 'category') {
 | 
        
           |  |  | 2924 |             $element['eid'] = 'cg'.$element['object']->id;
 | 
        
           |  |  | 2925 |         } else if (in_array($element['type'], array('item', 'courseitem', 'categoryitem'))) {
 | 
        
           |  |  | 2926 |             $element['eid'] = 'ig'.$element['object']->id;
 | 
        
           |  |  | 2927 |             $this->items[$element['object']->id] =& $element['object'];
 | 
        
           |  |  | 2928 |         }
 | 
        
           |  |  | 2929 |   | 
        
           |  |  | 2930 |         $levels[$depth][] =& $element;
 | 
        
           |  |  | 2931 |         $depth++;
 | 
        
           |  |  | 2932 |         if (empty($element['children'])) {
 | 
        
           |  |  | 2933 |             return;
 | 
        
           |  |  | 2934 |         }
 | 
        
           |  |  | 2935 |         $prev = 0;
 | 
        
           |  |  | 2936 |         foreach ($element['children'] as $sortorder=>$child) {
 | 
        
           |  |  | 2937 |             grade_tree::fill_levels($levels, $element['children'][$sortorder], $depth);
 | 
        
           |  |  | 2938 |             $element['children'][$sortorder]['prev'] = $prev;
 | 
        
           |  |  | 2939 |             $element['children'][$sortorder]['next'] = 0;
 | 
        
           |  |  | 2940 |             if ($prev) {
 | 
        
           |  |  | 2941 |                 $element['children'][$prev]['next'] = $sortorder;
 | 
        
           |  |  | 2942 |             }
 | 
        
           |  |  | 2943 |             $prev = $sortorder;
 | 
        
           |  |  | 2944 |         }
 | 
        
           |  |  | 2945 |     }
 | 
        
           |  |  | 2946 |   | 
        
           |  |  | 2947 |     /**
 | 
        
           |  |  | 2948 |      * Determines whether the grade tree item can be displayed.
 | 
        
           |  |  | 2949 |      * This is particularly targeted for grade categories that have no total (None) when rendering the grade tree.
 | 
        
           |  |  | 2950 |      * It checks if the grade tree item is of type 'category', and makes sure that the category, or at least one of children,
 | 
        
           |  |  | 2951 |      * can be output.
 | 
        
           |  |  | 2952 |      *
 | 
        
           |  |  | 2953 |      * @param array $element The grade category element.
 | 
        
           |  |  | 2954 |      * @return bool True if the grade tree item can be displayed. False, otherwise.
 | 
        
           |  |  | 2955 |      */
 | 
        
           |  |  | 2956 |     public static function can_output_item($element) {
 | 
        
           |  |  | 2957 |         $canoutput = true;
 | 
        
           |  |  | 2958 |   | 
        
           |  |  | 2959 |         if ($element['type'] === 'category') {
 | 
        
           |  |  | 2960 |             $object = $element['object'];
 | 
        
           |  |  | 2961 |             $category = grade_category::fetch(array('id' => $object->id));
 | 
        
           |  |  | 2962 |             // Category has total, we can output this.
 | 
        
           |  |  | 2963 |             if ($category->get_grade_item()->gradetype != GRADE_TYPE_NONE) {
 | 
        
           |  |  | 2964 |                 return true;
 | 
        
           |  |  | 2965 |             }
 | 
        
           |  |  | 2966 |   | 
        
           |  |  | 2967 |             // Category has no total and has no children, no need to output this.
 | 
        
           |  |  | 2968 |             if (empty($element['children'])) {
 | 
        
           |  |  | 2969 |                 return false;
 | 
        
           |  |  | 2970 |             }
 | 
        
           |  |  | 2971 |   | 
        
           |  |  | 2972 |             $canoutput = false;
 | 
        
           |  |  | 2973 |             // Loop over children and make sure at least one child can be output.
 | 
        
           |  |  | 2974 |             foreach ($element['children'] as $child) {
 | 
        
           |  |  | 2975 |                 $canoutput = self::can_output_item($child);
 | 
        
           |  |  | 2976 |                 if ($canoutput) {
 | 
        
           |  |  | 2977 |                     break;
 | 
        
           |  |  | 2978 |                 }
 | 
        
           |  |  | 2979 |             }
 | 
        
           |  |  | 2980 |         }
 | 
        
           |  |  | 2981 |   | 
        
           |  |  | 2982 |         return $canoutput;
 | 
        
           |  |  | 2983 |     }
 | 
        
           |  |  | 2984 |   | 
        
           |  |  | 2985 |     /**
 | 
        
           |  |  | 2986 |      * Static recursive helper - makes full tree (all leafes are at the same level)
 | 
        
           |  |  | 2987 |      *
 | 
        
           |  |  | 2988 |      * @param array &$element The seed of the recursion
 | 
        
           |  |  | 2989 |      * @param int   $depth How deep are we?
 | 
        
           |  |  | 2990 |      *
 | 
        
           |  |  | 2991 |      * @return int
 | 
        
           |  |  | 2992 |      */
 | 
        
           |  |  | 2993 |     public function inject_fillers(&$element, $depth) {
 | 
        
           |  |  | 2994 |         $depth++;
 | 
        
           |  |  | 2995 |   | 
        
           |  |  | 2996 |         if (empty($element['children'])) {
 | 
        
           |  |  | 2997 |             return $depth;
 | 
        
           |  |  | 2998 |         }
 | 
        
           |  |  | 2999 |         $chdepths = array();
 | 
        
           |  |  | 3000 |         $chids = array_keys($element['children']);
 | 
        
           |  |  | 3001 |         $last_child  = end($chids);
 | 
        
           |  |  | 3002 |         $first_child = reset($chids);
 | 
        
           |  |  | 3003 |   | 
        
           |  |  | 3004 |         foreach ($chids as $chid) {
 | 
        
           |  |  | 3005 |             $chdepths[$chid] = grade_tree::inject_fillers($element['children'][$chid], $depth);
 | 
        
           |  |  | 3006 |         }
 | 
        
           |  |  | 3007 |         arsort($chdepths);
 | 
        
           |  |  | 3008 |   | 
        
           |  |  | 3009 |         $maxdepth = reset($chdepths);
 | 
        
           |  |  | 3010 |         foreach ($chdepths as $chid=>$chd) {
 | 
        
           |  |  | 3011 |             if ($chd == $maxdepth) {
 | 
        
           |  |  | 3012 |                 continue;
 | 
        
           |  |  | 3013 |             }
 | 
        
           |  |  | 3014 |             if (!self::can_output_item($element['children'][$chid])) {
 | 
        
           |  |  | 3015 |                 continue;
 | 
        
           |  |  | 3016 |             }
 | 
        
           |  |  | 3017 |             for ($i=0; $i < $maxdepth-$chd; $i++) {
 | 
        
           |  |  | 3018 |                 if ($chid == $first_child) {
 | 
        
           |  |  | 3019 |                     $type = 'fillerfirst';
 | 
        
           |  |  | 3020 |                 } else if ($chid == $last_child) {
 | 
        
           |  |  | 3021 |                     $type = 'fillerlast';
 | 
        
           |  |  | 3022 |                 } else {
 | 
        
           |  |  | 3023 |                     $type = 'filler';
 | 
        
           |  |  | 3024 |                 }
 | 
        
           |  |  | 3025 |                 $oldchild =& $element['children'][$chid];
 | 
        
           |  |  | 3026 |                 $element['children'][$chid] = array('object'=>'filler', 'type'=>$type,
 | 
        
           |  |  | 3027 |                                                     'eid'=>'', 'depth'=>$element['object']->depth,
 | 
        
           |  |  | 3028 |                                                     'children'=>array($oldchild));
 | 
        
           |  |  | 3029 |             }
 | 
        
           |  |  | 3030 |         }
 | 
        
           |  |  | 3031 |   | 
        
           |  |  | 3032 |         return $maxdepth;
 | 
        
           |  |  | 3033 |     }
 | 
        
           |  |  | 3034 |   | 
        
           |  |  | 3035 |     /**
 | 
        
           |  |  | 3036 |      * Static recursive helper - add colspan information into categories
 | 
        
           |  |  | 3037 |      *
 | 
        
           |  |  | 3038 |      * @param array &$element The seed of the recursion
 | 
        
           |  |  | 3039 |      *
 | 
        
           |  |  | 3040 |      * @return int
 | 
        
           |  |  | 3041 |      */
 | 
        
           |  |  | 3042 |     public function inject_colspans(&$element) {
 | 
        
           |  |  | 3043 |         if (empty($element['children'])) {
 | 
        
           |  |  | 3044 |             return 1;
 | 
        
           |  |  | 3045 |         }
 | 
        
           |  |  | 3046 |         $count = 0;
 | 
        
           |  |  | 3047 |         foreach ($element['children'] as $key=>$child) {
 | 
        
           |  |  | 3048 |             if (!self::can_output_item($child)) {
 | 
        
           |  |  | 3049 |                 continue;
 | 
        
           |  |  | 3050 |             }
 | 
        
           |  |  | 3051 |             $count += grade_tree::inject_colspans($element['children'][$key]);
 | 
        
           |  |  | 3052 |         }
 | 
        
           |  |  | 3053 |         $element['colspan'] = $count;
 | 
        
           |  |  | 3054 |         return $count;
 | 
        
           |  |  | 3055 |     }
 | 
        
           |  |  | 3056 |   | 
        
           |  |  | 3057 |     /**
 | 
        
           |  |  | 3058 |      * Parses the array in search of a given eid and returns a element object with
 | 
        
           |  |  | 3059 |      * information about the element it has found.
 | 
        
           |  |  | 3060 |      * @param int $eid Gradetree Element ID
 | 
        
           |  |  | 3061 |      * @return object element
 | 
        
           |  |  | 3062 |      */
 | 
        
           |  |  | 3063 |     public function locate_element($eid) {
 | 
        
           |  |  | 3064 |         // it is a grade - construct a new object
 | 
        
           |  |  | 3065 |         if (strpos($eid, 'n') === 0) {
 | 
        
           |  |  | 3066 |             if (!preg_match('/n(\d+)u(\d+)/', $eid, $matches)) {
 | 
        
           |  |  | 3067 |                 return null;
 | 
        
           |  |  | 3068 |             }
 | 
        
           |  |  | 3069 |   | 
        
           |  |  | 3070 |             $itemid = $matches[1];
 | 
        
           |  |  | 3071 |             $userid = $matches[2];
 | 
        
           |  |  | 3072 |   | 
        
           |  |  | 3073 |             //extra security check - the grade item must be in this tree
 | 
        
           |  |  | 3074 |             if (!$item_el = $this->locate_element('ig'.$itemid)) {
 | 
        
           |  |  | 3075 |                 return null;
 | 
        
           |  |  | 3076 |             }
 | 
        
           |  |  | 3077 |   | 
        
           |  |  | 3078 |             // $gradea->id may be null - means does not exist yet
 | 
        
           |  |  | 3079 |             $grade = new grade_grade(array('itemid'=>$itemid, 'userid'=>$userid));
 | 
        
           |  |  | 3080 |   | 
        
           |  |  | 3081 |             $grade->grade_item =& $item_el['object']; // this may speedup grade_grade methods!
 | 
        
           |  |  | 3082 |             return array('eid'=>'n'.$itemid.'u'.$userid,'object'=>$grade, 'type'=>'grade');
 | 
        
           |  |  | 3083 |   | 
        
           |  |  | 3084 |         } else if (strpos($eid, 'g') === 0) {
 | 
        
           |  |  | 3085 |             $id = (int) substr($eid, 1);
 | 
        
           |  |  | 3086 |             if (!$grade = grade_grade::fetch(array('id'=>$id))) {
 | 
        
           |  |  | 3087 |                 return null;
 | 
        
           |  |  | 3088 |             }
 | 
        
           |  |  | 3089 |             //extra security check - the grade item must be in this tree
 | 
        
           |  |  | 3090 |             if (!$item_el = $this->locate_element('ig'.$grade->itemid)) {
 | 
        
           |  |  | 3091 |                 return null;
 | 
        
           |  |  | 3092 |             }
 | 
        
           |  |  | 3093 |             $grade->grade_item =& $item_el['object']; // this may speedup grade_grade methods!
 | 
        
           |  |  | 3094 |             return array('eid'=>'g'.$id,'object'=>$grade, 'type'=>'grade');
 | 
        
           |  |  | 3095 |         }
 | 
        
           |  |  | 3096 |   | 
        
           |  |  | 3097 |         // it is a category or item
 | 
        
           |  |  | 3098 |         foreach ($this->levels as $row) {
 | 
        
           |  |  | 3099 |             foreach ($row as $element) {
 | 
        
           |  |  | 3100 |                 if ($element['type'] == 'filler') {
 | 
        
           |  |  | 3101 |                     continue;
 | 
        
           |  |  | 3102 |                 }
 | 
        
           |  |  | 3103 |                 if ($element['eid'] == $eid) {
 | 
        
           |  |  | 3104 |                     return $element;
 | 
        
           |  |  | 3105 |                 }
 | 
        
           |  |  | 3106 |             }
 | 
        
           |  |  | 3107 |         }
 | 
        
           |  |  | 3108 |   | 
        
           |  |  | 3109 |         return null;
 | 
        
           |  |  | 3110 |     }
 | 
        
           |  |  | 3111 |   | 
        
           |  |  | 3112 |     /**
 | 
        
           |  |  | 3113 |      * Returns a well-formed XML representation of the grade-tree using recursion.
 | 
        
           |  |  | 3114 |      *
 | 
        
           |  |  | 3115 |      * @param array  $root The current element in the recursion. If null, starts at the top of the tree.
 | 
        
           |  |  | 3116 |      * @param string $tabs The control character to use for tabs
 | 
        
           |  |  | 3117 |      *
 | 
        
           |  |  | 3118 |      * @return string $xml
 | 
        
           |  |  | 3119 |      */
 | 
        
           |  |  | 3120 |     public function exporttoxml($root=null, $tabs="\t") {
 | 
        
           |  |  | 3121 |         $xml = null;
 | 
        
           |  |  | 3122 |         $first = false;
 | 
        
           |  |  | 3123 |         if (is_null($root)) {
 | 
        
           |  |  | 3124 |             $root = $this->top_element;
 | 
        
           |  |  | 3125 |             $xml = '<?xml version="1.0" encoding="UTF-8" ?>' . "\n";
 | 
        
           |  |  | 3126 |             $xml .= "<gradetree>\n";
 | 
        
           |  |  | 3127 |             $first = true;
 | 
        
           |  |  | 3128 |         }
 | 
        
           |  |  | 3129 |   | 
        
           |  |  | 3130 |         $type = 'undefined';
 | 
        
           |  |  | 3131 |         if (strpos($root['object']->table, 'grade_categories') !== false) {
 | 
        
           |  |  | 3132 |             $type = 'category';
 | 
        
           |  |  | 3133 |         } else if (strpos($root['object']->table, 'grade_items') !== false) {
 | 
        
           |  |  | 3134 |             $type = 'item';
 | 
        
           |  |  | 3135 |         } else if (strpos($root['object']->table, 'grade_outcomes') !== false) {
 | 
        
           |  |  | 3136 |             $type = 'outcome';
 | 
        
           |  |  | 3137 |         }
 | 
        
           |  |  | 3138 |   | 
        
           |  |  | 3139 |         $xml .= "$tabs<element type=\"$type\">\n";
 | 
        
           |  |  | 3140 |         foreach ($root['object'] as $var => $value) {
 | 
        
           |  |  | 3141 |             if (!is_object($value) && !is_array($value) && !empty($value)) {
 | 
        
           |  |  | 3142 |                 $xml .= "$tabs\t<$var>$value</$var>\n";
 | 
        
           |  |  | 3143 |             }
 | 
        
           |  |  | 3144 |         }
 | 
        
           |  |  | 3145 |   | 
        
           |  |  | 3146 |         if (!empty($root['children'])) {
 | 
        
           |  |  | 3147 |             $xml .= "$tabs\t<children>\n";
 | 
        
           |  |  | 3148 |             foreach ($root['children'] as $sortorder => $child) {
 | 
        
           |  |  | 3149 |                 $xml .= $this->exportToXML($child, $tabs."\t\t");
 | 
        
           |  |  | 3150 |             }
 | 
        
           |  |  | 3151 |             $xml .= "$tabs\t</children>\n";
 | 
        
           |  |  | 3152 |         }
 | 
        
           |  |  | 3153 |   | 
        
           |  |  | 3154 |         $xml .= "$tabs</element>\n";
 | 
        
           |  |  | 3155 |   | 
        
           |  |  | 3156 |         if ($first) {
 | 
        
           |  |  | 3157 |             $xml .= "</gradetree>";
 | 
        
           |  |  | 3158 |         }
 | 
        
           |  |  | 3159 |   | 
        
           |  |  | 3160 |         return $xml;
 | 
        
           |  |  | 3161 |     }
 | 
        
           |  |  | 3162 |   | 
        
           |  |  | 3163 |     /**
 | 
        
           |  |  | 3164 |      * Returns a JSON representation of the grade-tree using recursion.
 | 
        
           |  |  | 3165 |      *
 | 
        
           |  |  | 3166 |      * @param array $root The current element in the recursion. If null, starts at the top of the tree.
 | 
        
           |  |  | 3167 |      * @param string $tabs Tab characters used to indent the string nicely for humans to enjoy
 | 
        
           |  |  | 3168 |      *
 | 
        
           |  |  | 3169 |      * @return string
 | 
        
           |  |  | 3170 |      */
 | 
        
           |  |  | 3171 |     public function exporttojson($root=null, $tabs="\t") {
 | 
        
           |  |  | 3172 |         $json = null;
 | 
        
           |  |  | 3173 |         $first = false;
 | 
        
           |  |  | 3174 |         if (is_null($root)) {
 | 
        
           |  |  | 3175 |             $root = $this->top_element;
 | 
        
           |  |  | 3176 |             $first = true;
 | 
        
           |  |  | 3177 |         }
 | 
        
           |  |  | 3178 |   | 
        
           |  |  | 3179 |         $name = '';
 | 
        
           |  |  | 3180 |   | 
        
           |  |  | 3181 |   | 
        
           |  |  | 3182 |         if (strpos($root['object']->table, 'grade_categories') !== false) {
 | 
        
           |  |  | 3183 |             $name = $root['object']->fullname;
 | 
        
           |  |  | 3184 |             if ($name == '?') {
 | 
        
           |  |  | 3185 |                 $name = $root['object']->get_name();
 | 
        
           |  |  | 3186 |             }
 | 
        
           |  |  | 3187 |         } else if (strpos($root['object']->table, 'grade_items') !== false) {
 | 
        
           |  |  | 3188 |             $name = $root['object']->itemname;
 | 
        
           |  |  | 3189 |         } else if (strpos($root['object']->table, 'grade_outcomes') !== false) {
 | 
        
           |  |  | 3190 |             $name = $root['object']->itemname;
 | 
        
           |  |  | 3191 |         }
 | 
        
           |  |  | 3192 |   | 
        
           |  |  | 3193 |         $json .= "$tabs {\n";
 | 
        
           |  |  | 3194 |         $json .= "$tabs\t \"type\": \"{$root['type']}\",\n";
 | 
        
           |  |  | 3195 |         $json .= "$tabs\t \"name\": \"$name\",\n";
 | 
        
           |  |  | 3196 |   | 
        
           |  |  | 3197 |         foreach ($root['object'] as $var => $value) {
 | 
        
           |  |  | 3198 |             if (!is_object($value) && !is_array($value) && !empty($value)) {
 | 
        
           |  |  | 3199 |                 $json .= "$tabs\t \"$var\": \"$value\",\n";
 | 
        
           |  |  | 3200 |             }
 | 
        
           |  |  | 3201 |         }
 | 
        
           |  |  | 3202 |   | 
        
           |  |  | 3203 |         $json = substr($json, 0, strrpos($json, ','));
 | 
        
           |  |  | 3204 |   | 
        
           |  |  | 3205 |         if (!empty($root['children'])) {
 | 
        
           |  |  | 3206 |             $json .= ",\n$tabs\t\"children\": [\n";
 | 
        
           |  |  | 3207 |             foreach ($root['children'] as $sortorder => $child) {
 | 
        
           |  |  | 3208 |                 $json .= $this->exportToJSON($child, $tabs."\t\t");
 | 
        
           |  |  | 3209 |             }
 | 
        
           |  |  | 3210 |             $json = substr($json, 0, strrpos($json, ','));
 | 
        
           |  |  | 3211 |             $json .= "\n$tabs\t]\n";
 | 
        
           |  |  | 3212 |         }
 | 
        
           |  |  | 3213 |   | 
        
           |  |  | 3214 |         if ($first) {
 | 
        
           |  |  | 3215 |             $json .= "\n}";
 | 
        
           |  |  | 3216 |         } else {
 | 
        
           |  |  | 3217 |             $json .= "\n$tabs},\n";
 | 
        
           |  |  | 3218 |         }
 | 
        
           |  |  | 3219 |   | 
        
           |  |  | 3220 |         return $json;
 | 
        
           |  |  | 3221 |     }
 | 
        
           |  |  | 3222 |   | 
        
           |  |  | 3223 |     /**
 | 
        
           |  |  | 3224 |      * Returns the array of levels
 | 
        
           |  |  | 3225 |      *
 | 
        
           |  |  | 3226 |      * @return array
 | 
        
           |  |  | 3227 |      */
 | 
        
           |  |  | 3228 |     public function get_levels() {
 | 
        
           |  |  | 3229 |         return $this->levels;
 | 
        
           |  |  | 3230 |     }
 | 
        
           |  |  | 3231 |   | 
        
           |  |  | 3232 |     /**
 | 
        
           |  |  | 3233 |      * Returns the array of grade items
 | 
        
           |  |  | 3234 |      *
 | 
        
           |  |  | 3235 |      * @return array
 | 
        
           |  |  | 3236 |      */
 | 
        
           |  |  | 3237 |     public function get_items() {
 | 
        
           |  |  | 3238 |         return $this->items;
 | 
        
           |  |  | 3239 |     }
 | 
        
           |  |  | 3240 |   | 
        
           |  |  | 3241 |     /**
 | 
        
           |  |  | 3242 |      * Returns a specific Grade Item
 | 
        
           |  |  | 3243 |      *
 | 
        
           |  |  | 3244 |      * @param int $itemid The ID of the grade_item object
 | 
        
           |  |  | 3245 |      *
 | 
        
           |  |  | 3246 |      * @return grade_item
 | 
        
           |  |  | 3247 |      */
 | 
        
           |  |  | 3248 |     public function get_item($itemid) {
 | 
        
           |  |  | 3249 |         if (array_key_exists($itemid, $this->items)) {
 | 
        
           |  |  | 3250 |             return $this->items[$itemid];
 | 
        
           |  |  | 3251 |         } else {
 | 
        
           |  |  | 3252 |             return false;
 | 
        
           |  |  | 3253 |         }
 | 
        
           |  |  | 3254 |     }
 | 
        
           |  |  | 3255 | }
 | 
        
           |  |  | 3256 |   | 
        
           |  |  | 3257 | /**
 | 
        
           |  |  | 3258 |  * Local shortcut function for creating an edit/delete button for a grade_* object.
 | 
        
           |  |  | 3259 |  * @param string $type 'edit' or 'delete'
 | 
        
           |  |  | 3260 |  * @param int $courseid The Course ID
 | 
        
           |  |  | 3261 |  * @param grade_* $object The grade_* object
 | 
        
           |  |  | 3262 |  * @return string html
 | 
        
           |  |  | 3263 |  */
 | 
        
           |  |  | 3264 | function grade_button($type, $courseid, $object) {
 | 
        
           |  |  | 3265 |     global $CFG, $OUTPUT;
 | 
        
           |  |  | 3266 |     if (preg_match('/grade_(.*)/', get_class($object), $matches)) {
 | 
        
           |  |  | 3267 |         $objectidstring = $matches[1] . 'id';
 | 
        
           |  |  | 3268 |     } else {
 | 
        
           |  |  | 3269 |         throw new coding_exception('grade_button() only accepts grade_* objects as third parameter!');
 | 
        
           |  |  | 3270 |     }
 | 
        
           |  |  | 3271 |   | 
        
           |  |  | 3272 |     $strdelete = get_string('delete');
 | 
        
           |  |  | 3273 |     $stredit   = get_string('edit');
 | 
        
           |  |  | 3274 |   | 
        
           |  |  | 3275 |     if ($type == 'delete') {
 | 
        
           |  |  | 3276 |         $url = new moodle_url('index.php', array('id' => $courseid, $objectidstring => $object->id, 'action' => 'delete', 'sesskey' => sesskey()));
 | 
        
           |  |  | 3277 |     } else if ($type == 'edit') {
 | 
        
           |  |  | 3278 |         $url = new moodle_url('edit.php', array('courseid' => $courseid, 'id' => $object->id));
 | 
        
           |  |  | 3279 |     }
 | 
        
           |  |  | 3280 |   | 
        
           |  |  | 3281 |     return $OUTPUT->action_icon($url, new pix_icon('t/'.$type, ${'str'.$type}, '', array('class' => 'iconsmall')));
 | 
        
           |  |  | 3282 |   | 
        
           |  |  | 3283 | }
 | 
        
           |  |  | 3284 |   | 
        
           |  |  | 3285 | /**
 | 
        
           |  |  | 3286 |  * This method adds settings to the settings block for the grade system and its
 | 
        
           |  |  | 3287 |  * plugins
 | 
        
           |  |  | 3288 |  *
 | 
        
           |  |  | 3289 |  * @global moodle_page $PAGE
 | 
        
           |  |  | 3290 |  */
 | 
        
           |  |  | 3291 | function grade_extend_settings($plugininfo, $courseid) {
 | 
        
           |  |  | 3292 |     global $PAGE;
 | 
        
           |  |  | 3293 |   | 
        
           |  |  | 3294 |     $gradenode = $PAGE->settingsnav->prepend(get_string('gradeadministration', 'grades'), null, navigation_node::TYPE_CONTAINER,
 | 
        
           |  |  | 3295 |         null, 'gradeadmin');
 | 
        
           |  |  | 3296 |   | 
        
           |  |  | 3297 |     $strings = array_shift($plugininfo);
 | 
        
           |  |  | 3298 |   | 
        
           |  |  | 3299 |     if ($reports = grade_helper::get_plugins_reports($courseid)) {
 | 
        
           |  |  | 3300 |         foreach ($reports as $report) {
 | 
        
           |  |  | 3301 |             $gradenode->add($report->string, $report->link, navigation_node::TYPE_SETTING, null, $report->id, new pix_icon('i/report', ''));
 | 
        
           |  |  | 3302 |         }
 | 
        
           |  |  | 3303 |     }
 | 
        
           |  |  | 3304 |   | 
        
           |  |  | 3305 |     if ($settings = grade_helper::get_info_manage_settings($courseid)) {
 | 
        
           |  |  | 3306 |         $settingsnode = $gradenode->add($strings['settings'], null, navigation_node::TYPE_CONTAINER);
 | 
        
           |  |  | 3307 |         foreach ($settings as $setting) {
 | 
        
           |  |  | 3308 |             $settingsnode->add($setting->string, $setting->link, navigation_node::TYPE_SETTING, null, $setting->id, new pix_icon('i/settings', ''));
 | 
        
           |  |  | 3309 |         }
 | 
        
           |  |  | 3310 |     }
 | 
        
           |  |  | 3311 |   | 
        
           |  |  | 3312 |     if ($imports = grade_helper::get_plugins_import($courseid)) {
 | 
        
           |  |  | 3313 |         $importnode = $gradenode->add($strings['import'], null, navigation_node::TYPE_CONTAINER);
 | 
        
           |  |  | 3314 |         foreach ($imports as $import) {
 | 
        
           |  |  | 3315 |             $importnode->add($import->string, $import->link, navigation_node::TYPE_SETTING, null, $import->id, new pix_icon('i/import', ''));
 | 
        
           |  |  | 3316 |         }
 | 
        
           |  |  | 3317 |     }
 | 
        
           |  |  | 3318 |   | 
        
           |  |  | 3319 |     if ($exports = grade_helper::get_plugins_export($courseid)) {
 | 
        
           |  |  | 3320 |         $exportnode = $gradenode->add($strings['export'], null, navigation_node::TYPE_CONTAINER);
 | 
        
           |  |  | 3321 |         foreach ($exports as $export) {
 | 
        
           |  |  | 3322 |             $exportnode->add($export->string, $export->link, navigation_node::TYPE_SETTING, null, $export->id, new pix_icon('i/export', ''));
 | 
        
           |  |  | 3323 |         }
 | 
        
           |  |  | 3324 |     }
 | 
        
           |  |  | 3325 |   | 
        
           |  |  | 3326 |     if ($letters = grade_helper::get_info_letters($courseid)) {
 | 
        
           |  |  | 3327 |         $letters = array_shift($letters);
 | 
        
           |  |  | 3328 |         $gradenode->add($strings['letter'], $letters->link, navigation_node::TYPE_SETTING, null, $letters->id, new pix_icon('i/settings', ''));
 | 
        
           |  |  | 3329 |     }
 | 
        
           |  |  | 3330 |   | 
        
           |  |  | 3331 |     if ($outcomes = grade_helper::get_info_outcomes($courseid)) {
 | 
        
           |  |  | 3332 |         $outcomes = array_shift($outcomes);
 | 
        
           |  |  | 3333 |         $gradenode->add($strings['outcome'], $outcomes->link, navigation_node::TYPE_SETTING, null, $outcomes->id, new pix_icon('i/outcomes', ''));
 | 
        
           |  |  | 3334 |     }
 | 
        
           |  |  | 3335 |   | 
        
           |  |  | 3336 |     if ($scales = grade_helper::get_info_scales($courseid)) {
 | 
        
           |  |  | 3337 |         $gradenode->add($strings['scale'], $scales->link, navigation_node::TYPE_SETTING, null, $scales->id, new pix_icon('i/scales', ''));
 | 
        
           |  |  | 3338 |     }
 | 
        
           |  |  | 3339 |   | 
        
           |  |  | 3340 |     if ($gradenode->contains_active_node()) {
 | 
        
           |  |  | 3341 |         // If the gradenode is active include the settings base node (gradeadministration) in
 | 
        
           |  |  | 3342 |         // the navbar, typcially this is ignored.
 | 
        
           |  |  | 3343 |         $PAGE->navbar->includesettingsbase = true;
 | 
        
           |  |  | 3344 |   | 
        
           |  |  | 3345 |         // If we can get the course admin node make sure it is closed by default
 | 
        
           |  |  | 3346 |         // as in this case the gradenode will be opened
 | 
        
           |  |  | 3347 |         if ($coursenode = $PAGE->settingsnav->get('courseadmin', navigation_node::TYPE_COURSE)){
 | 
        
           |  |  | 3348 |             $coursenode->make_inactive();
 | 
        
           |  |  | 3349 |             $coursenode->forceopen = false;
 | 
        
           |  |  | 3350 |         }
 | 
        
           |  |  | 3351 |     }
 | 
        
           |  |  | 3352 | }
 | 
        
           |  |  | 3353 |   | 
        
           |  |  | 3354 | /**
 | 
        
           |  |  | 3355 |  * Grade helper class
 | 
        
           |  |  | 3356 |  *
 | 
        
           |  |  | 3357 |  * This class provides several helpful functions that work irrespective of any
 | 
        
           |  |  | 3358 |  * current state.
 | 
        
           |  |  | 3359 |  *
 | 
        
           |  |  | 3360 |  * @copyright 2010 Sam Hemelryk
 | 
        
           |  |  | 3361 |  * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
 | 
        
           |  |  | 3362 |  */
 | 
        
           |  |  | 3363 | abstract class grade_helper {
 | 
        
           |  |  | 3364 |     /**
 | 
        
           |  |  | 3365 |      * Cached manage settings info {@see get_info_settings}
 | 
        
           |  |  | 3366 |      * @var grade_plugin_info|false
 | 
        
           |  |  | 3367 |      */
 | 
        
           |  |  | 3368 |     protected static $managesetting = null;
 | 
        
           |  |  | 3369 |     /**
 | 
        
           |  |  | 3370 |      * Cached grade report plugins {@see get_plugins_reports}
 | 
        
           |  |  | 3371 |      * @var array|false
 | 
        
           |  |  | 3372 |      */
 | 
        
           |  |  | 3373 |     protected static $gradereports = null;
 | 
        
           |  |  | 3374 |     /**
 | 
        
           |  |  | 3375 |      * Cached grade report plugins preferences {@see get_info_scales}
 | 
        
           |  |  | 3376 |      * @var array|false
 | 
        
           |  |  | 3377 |      */
 | 
        
           |  |  | 3378 |     protected static $gradereportpreferences = null;
 | 
        
           |  |  | 3379 |     /**
 | 
        
           |  |  | 3380 |      * Cached scale info {@see get_info_scales}
 | 
        
           |  |  | 3381 |      * @var grade_plugin_info|false
 | 
        
           |  |  | 3382 |      */
 | 
        
           |  |  | 3383 |     protected static $scaleinfo = null;
 | 
        
           |  |  | 3384 |     /**
 | 
        
           |  |  | 3385 |      * Cached outcome info {@see get_info_outcomes}
 | 
        
           |  |  | 3386 |      * @var grade_plugin_info|false
 | 
        
           |  |  | 3387 |      */
 | 
        
           |  |  | 3388 |     protected static $outcomeinfo = null;
 | 
        
           |  |  | 3389 |     /**
 | 
        
           |  |  | 3390 |      * Cached leftter info {@see get_info_letters}
 | 
        
           |  |  | 3391 |      * @var grade_plugin_info|false
 | 
        
           |  |  | 3392 |      */
 | 
        
           |  |  | 3393 |     protected static $letterinfo = null;
 | 
        
           |  |  | 3394 |     /**
 | 
        
           |  |  | 3395 |      * Cached grade import plugins {@see get_plugins_import}
 | 
        
           |  |  | 3396 |      * @var array|false
 | 
        
           |  |  | 3397 |      */
 | 
        
           |  |  | 3398 |     protected static $importplugins = null;
 | 
        
           |  |  | 3399 |     /**
 | 
        
           |  |  | 3400 |      * Cached grade export plugins {@see get_plugins_export}
 | 
        
           |  |  | 3401 |      * @var array|false
 | 
        
           |  |  | 3402 |      */
 | 
        
           |  |  | 3403 |     protected static $exportplugins = null;
 | 
        
           |  |  | 3404 |     /**
 | 
        
           |  |  | 3405 |      * Cached grade plugin strings
 | 
        
           |  |  | 3406 |      * @var array
 | 
        
           |  |  | 3407 |      */
 | 
        
           |  |  | 3408 |     protected static $pluginstrings = null;
 | 
        
           |  |  | 3409 |     /**
 | 
        
           |  |  | 3410 |      * Cached grade aggregation strings
 | 
        
           |  |  | 3411 |      * @var array
 | 
        
           |  |  | 3412 |      */
 | 
        
           |  |  | 3413 |     protected static $aggregationstrings = null;
 | 
        
           |  |  | 3414 |   | 
        
           |  |  | 3415 |     /**
 | 
        
           |  |  | 3416 |      * @deprecated since 4.3
 | 
        
           |  |  | 3417 |      */
 | 
        
           | 1441 | ariadna | 3418 |     #[\core\attribute\deprecated('get_string', since: '4.3', mdl: 'MDL-78561', final: true)]
 | 
        
           |  |  | 3419 |     public static function get_lang_string(): void {
 | 
        
           |  |  | 3420 |         \core\deprecation::emit_deprecation([self::class, __FUNCTION__]);
 | 
        
           | 1 | efrain | 3421 |     }
 | 
        
           |  |  | 3422 |   | 
        
           |  |  | 3423 |     /**
 | 
        
           |  |  | 3424 |      * Gets strings commonly used by the describe plugins
 | 
        
           |  |  | 3425 |      *
 | 
        
           |  |  | 3426 |      * report => get_string('view'),
 | 
        
           |  |  | 3427 |      * scale => get_string('scales'),
 | 
        
           |  |  | 3428 |      * outcome => get_string('outcomes', 'grades'),
 | 
        
           |  |  | 3429 |      * letter => get_string('letters', 'grades'),
 | 
        
           |  |  | 3430 |      * export => get_string('export', 'grades'),
 | 
        
           |  |  | 3431 |      * import => get_string('import'),
 | 
        
           |  |  | 3432 |      * settings => get_string('settings')
 | 
        
           |  |  | 3433 |      *
 | 
        
           |  |  | 3434 |      * @return array
 | 
        
           |  |  | 3435 |      */
 | 
        
           |  |  | 3436 |     public static function get_plugin_strings() {
 | 
        
           |  |  | 3437 |         if (self::$pluginstrings === null) {
 | 
        
           |  |  | 3438 |             self::$pluginstrings = array(
 | 
        
           |  |  | 3439 |                 'report' => get_string('view'),
 | 
        
           |  |  | 3440 |                 'scale' => get_string('scales'),
 | 
        
           |  |  | 3441 |                 'outcome' => get_string('outcomes', 'grades'),
 | 
        
           |  |  | 3442 |                 'letter' => get_string('letters', 'grades'),
 | 
        
           |  |  | 3443 |                 'export' => get_string('export', 'grades'),
 | 
        
           |  |  | 3444 |                 'import' => get_string('import'),
 | 
        
           |  |  | 3445 |                 'settings' => get_string('edittree', 'grades')
 | 
        
           |  |  | 3446 |             );
 | 
        
           |  |  | 3447 |         }
 | 
        
           |  |  | 3448 |         return self::$pluginstrings;
 | 
        
           |  |  | 3449 |     }
 | 
        
           |  |  | 3450 |   | 
        
           |  |  | 3451 |     /**
 | 
        
           |  |  | 3452 |      * Gets strings describing the available aggregation methods.
 | 
        
           |  |  | 3453 |      *
 | 
        
           |  |  | 3454 |      * @return array
 | 
        
           |  |  | 3455 |      */
 | 
        
           |  |  | 3456 |     public static function get_aggregation_strings() {
 | 
        
           |  |  | 3457 |         if (self::$aggregationstrings === null) {
 | 
        
           |  |  | 3458 |             self::$aggregationstrings = array(
 | 
        
           |  |  | 3459 |                 GRADE_AGGREGATE_MEAN             => get_string('aggregatemean', 'grades'),
 | 
        
           |  |  | 3460 |                 GRADE_AGGREGATE_WEIGHTED_MEAN    => get_string('aggregateweightedmean', 'grades'),
 | 
        
           |  |  | 3461 |                 GRADE_AGGREGATE_WEIGHTED_MEAN2   => get_string('aggregateweightedmean2', 'grades'),
 | 
        
           |  |  | 3462 |                 GRADE_AGGREGATE_EXTRACREDIT_MEAN => get_string('aggregateextracreditmean', 'grades'),
 | 
        
           |  |  | 3463 |                 GRADE_AGGREGATE_MEDIAN           => get_string('aggregatemedian', 'grades'),
 | 
        
           |  |  | 3464 |                 GRADE_AGGREGATE_MIN              => get_string('aggregatemin', 'grades'),
 | 
        
           |  |  | 3465 |                 GRADE_AGGREGATE_MAX              => get_string('aggregatemax', 'grades'),
 | 
        
           |  |  | 3466 |                 GRADE_AGGREGATE_MODE             => get_string('aggregatemode', 'grades'),
 | 
        
           |  |  | 3467 |                 GRADE_AGGREGATE_SUM              => get_string('aggregatesum', 'grades')
 | 
        
           |  |  | 3468 |             );
 | 
        
           |  |  | 3469 |         }
 | 
        
           |  |  | 3470 |         return self::$aggregationstrings;
 | 
        
           |  |  | 3471 |     }
 | 
        
           |  |  | 3472 |   | 
        
           |  |  | 3473 |     /**
 | 
        
           |  |  | 3474 |      * Get grade_plugin_info object for managing settings if the user can
 | 
        
           |  |  | 3475 |      *
 | 
        
           |  |  | 3476 |      * @param int $courseid
 | 
        
           |  |  | 3477 |      * @return grade_plugin_info[]
 | 
        
           |  |  | 3478 |      */
 | 
        
           |  |  | 3479 |     public static function get_info_manage_settings($courseid) {
 | 
        
           |  |  | 3480 |         if (self::$managesetting !== null) {
 | 
        
           |  |  | 3481 |             return self::$managesetting;
 | 
        
           |  |  | 3482 |         }
 | 
        
           |  |  | 3483 |         $context = context_course::instance($courseid);
 | 
        
           |  |  | 3484 |         self::$managesetting = array();
 | 
        
           |  |  | 3485 |         if ($courseid != SITEID && has_capability('moodle/grade:manage', $context)) {
 | 
        
           |  |  | 3486 |             self::$managesetting['gradebooksetup'] = new grade_plugin_info('setup',
 | 
        
           |  |  | 3487 |                 new moodle_url('/grade/edit/tree/index.php', array('id' => $courseid)),
 | 
        
           |  |  | 3488 |                 get_string('gradebooksetup', 'grades'));
 | 
        
           |  |  | 3489 |             self::$managesetting['coursesettings'] = new grade_plugin_info('coursesettings',
 | 
        
           |  |  | 3490 |                 new moodle_url('/grade/edit/settings/index.php', array('id'=>$courseid)),
 | 
        
           |  |  | 3491 |                 get_string('coursegradesettings', 'grades'));
 | 
        
           |  |  | 3492 |         }
 | 
        
           |  |  | 3493 |         if (self::$gradereportpreferences === null) {
 | 
        
           |  |  | 3494 |             self::get_plugins_reports($courseid);
 | 
        
           |  |  | 3495 |         }
 | 
        
           |  |  | 3496 |         if (self::$gradereportpreferences) {
 | 
        
           |  |  | 3497 |             self::$managesetting = array_merge(self::$managesetting, self::$gradereportpreferences);
 | 
        
           |  |  | 3498 |         }
 | 
        
           |  |  | 3499 |         return self::$managesetting;
 | 
        
           |  |  | 3500 |     }
 | 
        
           |  |  | 3501 |     /**
 | 
        
           |  |  | 3502 |      * Returns an array of plugin reports as grade_plugin_info objects
 | 
        
           |  |  | 3503 |      *
 | 
        
           |  |  | 3504 |      * @param int $courseid
 | 
        
           |  |  | 3505 |      * @return array
 | 
        
           |  |  | 3506 |      */
 | 
        
           |  |  | 3507 |     public static function get_plugins_reports($courseid) {
 | 
        
           |  |  | 3508 |         global $SITE, $CFG;
 | 
        
           |  |  | 3509 |   | 
        
           |  |  | 3510 |         if (self::$gradereports !== null) {
 | 
        
           |  |  | 3511 |             return self::$gradereports;
 | 
        
           |  |  | 3512 |         }
 | 
        
           |  |  | 3513 |         $context = context_course::instance($courseid);
 | 
        
           |  |  | 3514 |         $gradereports = array();
 | 
        
           |  |  | 3515 |         $gradepreferences = array();
 | 
        
           |  |  | 3516 |         foreach (core_component::get_plugin_list('gradereport') as $plugin => $plugindir) {
 | 
        
           |  |  | 3517 |             //some reports make no sense if we're not within a course
 | 
        
           |  |  | 3518 |             if ($courseid==$SITE->id && ($plugin=='grader' || $plugin=='user')) {
 | 
        
           |  |  | 3519 |                 continue;
 | 
        
           |  |  | 3520 |             }
 | 
        
           |  |  | 3521 |   | 
        
           |  |  | 3522 |             // Remove outcomes report if outcomes not enabled.
 | 
        
           |  |  | 3523 |             if ($plugin === 'outcomes' && empty($CFG->enableoutcomes)) {
 | 
        
           |  |  | 3524 |                 continue;
 | 
        
           |  |  | 3525 |             }
 | 
        
           |  |  | 3526 |   | 
        
           |  |  | 3527 |             // Remove ones we can't see
 | 
        
           |  |  | 3528 |             if (!has_capability('gradereport/'.$plugin.':view', $context)) {
 | 
        
           |  |  | 3529 |                 continue;
 | 
        
           |  |  | 3530 |             }
 | 
        
           |  |  | 3531 |   | 
        
           |  |  | 3532 |             // Singleview doesn't doesn't accomodate for all cap combos yet, so this is hardcoded..
 | 
        
           |  |  | 3533 |             if ($plugin === 'singleview' && !has_all_capabilities(array('moodle/grade:viewall',
 | 
        
           |  |  | 3534 |                     'moodle/grade:edit'), $context)) {
 | 
        
           |  |  | 3535 |                 continue;
 | 
        
           |  |  | 3536 |             }
 | 
        
           |  |  | 3537 |   | 
        
           |  |  | 3538 |             $pluginstr = get_string('pluginname', 'gradereport_'.$plugin);
 | 
        
           |  |  | 3539 |             $url = new moodle_url('/grade/report/'.$plugin.'/index.php', array('id'=>$courseid));
 | 
        
           |  |  | 3540 |             $gradereports[$plugin] = new grade_plugin_info($plugin, $url, $pluginstr);
 | 
        
           |  |  | 3541 |   | 
        
           |  |  | 3542 |             // Add link to preferences tab if such a page exists
 | 
        
           |  |  | 3543 |             if (file_exists($plugindir.'/preferences.php')) {
 | 
        
           |  |  | 3544 |                 $url = new moodle_url('/grade/report/'.$plugin.'/preferences.php', array('id' => $courseid));
 | 
        
           |  |  | 3545 |                 $gradepreferences[$plugin] = new grade_plugin_info($plugin, $url,
 | 
        
           |  |  | 3546 |                     get_string('preferences', 'grades') . ': ' . $pluginstr);
 | 
        
           |  |  | 3547 |             }
 | 
        
           |  |  | 3548 |         }
 | 
        
           |  |  | 3549 |         if (count($gradereports) == 0) {
 | 
        
           |  |  | 3550 |             $gradereports = false;
 | 
        
           |  |  | 3551 |             $gradepreferences = false;
 | 
        
           |  |  | 3552 |         } else if (count($gradepreferences) == 0) {
 | 
        
           |  |  | 3553 |             $gradepreferences = false;
 | 
        
           |  |  | 3554 |             asort($gradereports);
 | 
        
           |  |  | 3555 |         } else {
 | 
        
           |  |  | 3556 |             asort($gradereports);
 | 
        
           |  |  | 3557 |             asort($gradepreferences);
 | 
        
           |  |  | 3558 |         }
 | 
        
           |  |  | 3559 |         self::$gradereports = $gradereports;
 | 
        
           |  |  | 3560 |         self::$gradereportpreferences = $gradepreferences;
 | 
        
           |  |  | 3561 |         return self::$gradereports;
 | 
        
           |  |  | 3562 |     }
 | 
        
           |  |  | 3563 |   | 
        
           |  |  | 3564 |     /**
 | 
        
           |  |  | 3565 |      * Get information on scales
 | 
        
           |  |  | 3566 |      * @param int $courseid
 | 
        
           |  |  | 3567 |      * @return grade_plugin_info
 | 
        
           |  |  | 3568 |      */
 | 
        
           |  |  | 3569 |     public static function get_info_scales($courseid) {
 | 
        
           |  |  | 3570 |         if (self::$scaleinfo !== null) {
 | 
        
           |  |  | 3571 |             return self::$scaleinfo;
 | 
        
           |  |  | 3572 |         }
 | 
        
           |  |  | 3573 |         if (has_capability('moodle/course:managescales', context_course::instance($courseid))) {
 | 
        
           |  |  | 3574 |             $url = new moodle_url('/grade/edit/scale/index.php', array('id'=>$courseid));
 | 
        
           |  |  | 3575 |             self::$scaleinfo = new grade_plugin_info('scale', $url, get_string('view'));
 | 
        
           |  |  | 3576 |         } else {
 | 
        
           |  |  | 3577 |             self::$scaleinfo = false;
 | 
        
           |  |  | 3578 |         }
 | 
        
           |  |  | 3579 |         return self::$scaleinfo;
 | 
        
           |  |  | 3580 |     }
 | 
        
           |  |  | 3581 |     /**
 | 
        
           |  |  | 3582 |      * Get information on outcomes
 | 
        
           |  |  | 3583 |      * @param int $courseid
 | 
        
           |  |  | 3584 |      * @return grade_plugin_info[]|false
 | 
        
           |  |  | 3585 |      */
 | 
        
           |  |  | 3586 |     public static function get_info_outcomes($courseid) {
 | 
        
           |  |  | 3587 |         global $CFG, $SITE;
 | 
        
           |  |  | 3588 |   | 
        
           |  |  | 3589 |         if (self::$outcomeinfo !== null) {
 | 
        
           |  |  | 3590 |             return self::$outcomeinfo;
 | 
        
           |  |  | 3591 |         }
 | 
        
           |  |  | 3592 |         $context = context_course::instance($courseid);
 | 
        
           |  |  | 3593 |         $canmanage = has_capability('moodle/grade:manage', $context);
 | 
        
           |  |  | 3594 |         $canupdate = has_capability('moodle/course:update', $context);
 | 
        
           |  |  | 3595 |         if (!empty($CFG->enableoutcomes) && ($canmanage || $canupdate)) {
 | 
        
           |  |  | 3596 |             $outcomes = array();
 | 
        
           |  |  | 3597 |             if ($canupdate) {
 | 
        
           |  |  | 3598 |                 if ($courseid!=$SITE->id) {
 | 
        
           |  |  | 3599 |                     $url = new moodle_url('/grade/edit/outcome/course.php', array('id'=>$courseid));
 | 
        
           |  |  | 3600 |                     $outcomes['course'] = new grade_plugin_info('course', $url, get_string('outcomescourse', 'grades'));
 | 
        
           |  |  | 3601 |                 }
 | 
        
           |  |  | 3602 |                 $url = new moodle_url('/grade/edit/outcome/index.php', array('id'=>$courseid));
 | 
        
           |  |  | 3603 |                 $outcomes['edit'] = new grade_plugin_info('edit', $url, get_string('editoutcomes', 'grades'));
 | 
        
           |  |  | 3604 |                 $url = new moodle_url('/grade/edit/outcome/import.php', array('courseid'=>$courseid));
 | 
        
           |  |  | 3605 |                 $outcomes['import'] = new grade_plugin_info('import', $url, get_string('importoutcomes', 'grades'));
 | 
        
           |  |  | 3606 |             } else {
 | 
        
           |  |  | 3607 |                 if ($courseid!=$SITE->id) {
 | 
        
           |  |  | 3608 |                     $url = new moodle_url('/grade/edit/outcome/course.php', array('id'=>$courseid));
 | 
        
           |  |  | 3609 |                     $outcomes['edit'] = new grade_plugin_info('edit', $url, get_string('outcomescourse', 'grades'));
 | 
        
           |  |  | 3610 |                 }
 | 
        
           |  |  | 3611 |             }
 | 
        
           |  |  | 3612 |             self::$outcomeinfo = $outcomes;
 | 
        
           |  |  | 3613 |         } else {
 | 
        
           |  |  | 3614 |             self::$outcomeinfo = false;
 | 
        
           |  |  | 3615 |         }
 | 
        
           |  |  | 3616 |         return self::$outcomeinfo;
 | 
        
           |  |  | 3617 |     }
 | 
        
           |  |  | 3618 |     /**
 | 
        
           |  |  | 3619 |      * Get information on letters
 | 
        
           |  |  | 3620 |      * @param int $courseid
 | 
        
           |  |  | 3621 |      * @return array
 | 
        
           |  |  | 3622 |      */
 | 
        
           |  |  | 3623 |     public static function get_info_letters($courseid) {
 | 
        
           |  |  | 3624 |         global $SITE;
 | 
        
           |  |  | 3625 |         if (self::$letterinfo !== null) {
 | 
        
           |  |  | 3626 |             return self::$letterinfo;
 | 
        
           |  |  | 3627 |         }
 | 
        
           |  |  | 3628 |         $context = context_course::instance($courseid);
 | 
        
           |  |  | 3629 |         $canmanage = has_capability('moodle/grade:manage', $context);
 | 
        
           |  |  | 3630 |         $canmanageletters = has_capability('moodle/grade:manageletters', $context);
 | 
        
           |  |  | 3631 |         if ($canmanage || $canmanageletters) {
 | 
        
           |  |  | 3632 |             // Redirect to system context when report is accessed from admin settings MDL-31633
 | 
        
           |  |  | 3633 |             if ($context->instanceid == $SITE->id) {
 | 
        
           |  |  | 3634 |                 $param = array('edit' => 1);
 | 
        
           |  |  | 3635 |             } else {
 | 
        
           |  |  | 3636 |                 $param = array('edit' => 1,'id' => $context->id);
 | 
        
           |  |  | 3637 |             }
 | 
        
           |  |  | 3638 |             self::$letterinfo = array(
 | 
        
           |  |  | 3639 |                 'view' => new grade_plugin_info('view', new moodle_url('/grade/edit/letter/index.php', array('id'=>$context->id)), get_string('view')),
 | 
        
           |  |  | 3640 |                 'edit' => new grade_plugin_info('edit', new moodle_url('/grade/edit/letter/index.php', $param), get_string('edit'))
 | 
        
           |  |  | 3641 |             );
 | 
        
           |  |  | 3642 |         } else {
 | 
        
           |  |  | 3643 |             self::$letterinfo = false;
 | 
        
           |  |  | 3644 |         }
 | 
        
           |  |  | 3645 |         return self::$letterinfo;
 | 
        
           |  |  | 3646 |     }
 | 
        
           |  |  | 3647 |     /**
 | 
        
           |  |  | 3648 |      * Get information import plugins
 | 
        
           |  |  | 3649 |      * @param int $courseid
 | 
        
           |  |  | 3650 |      * @return array
 | 
        
           |  |  | 3651 |      */
 | 
        
           |  |  | 3652 |     public static function get_plugins_import($courseid) {
 | 
        
           |  |  | 3653 |         global $CFG;
 | 
        
           |  |  | 3654 |   | 
        
           |  |  | 3655 |         if (self::$importplugins !== null) {
 | 
        
           |  |  | 3656 |             return self::$importplugins;
 | 
        
           |  |  | 3657 |         }
 | 
        
           |  |  | 3658 |         $importplugins = array();
 | 
        
           |  |  | 3659 |         $context = context_course::instance($courseid);
 | 
        
           |  |  | 3660 |   | 
        
           |  |  | 3661 |         if (has_capability('moodle/grade:import', $context)) {
 | 
        
           |  |  | 3662 |             foreach (core_component::get_plugin_list('gradeimport') as $plugin => $plugindir) {
 | 
        
           |  |  | 3663 |                 if (!has_capability('gradeimport/'.$plugin.':view', $context)) {
 | 
        
           |  |  | 3664 |                     continue;
 | 
        
           |  |  | 3665 |                 }
 | 
        
           |  |  | 3666 |                 $pluginstr = get_string('pluginname', 'gradeimport_'.$plugin);
 | 
        
           |  |  | 3667 |                 $url = new moodle_url('/grade/import/'.$plugin.'/index.php', array('id'=>$courseid));
 | 
        
           |  |  | 3668 |                 $importplugins[$plugin] = new grade_plugin_info($plugin, $url, $pluginstr);
 | 
        
           |  |  | 3669 |             }
 | 
        
           |  |  | 3670 |   | 
        
           |  |  | 3671 |             // Show key manager if grade publishing is enabled and the user has xml publishing capability.
 | 
        
           |  |  | 3672 |             // XML is the only grade import plugin that has publishing feature.
 | 
        
           |  |  | 3673 |             if ($CFG->gradepublishing && has_capability('gradeimport/xml:publish', $context)) {
 | 
        
           |  |  | 3674 |                 $url = new moodle_url('/grade/import/keymanager.php', array('id'=>$courseid));
 | 
        
           |  |  | 3675 |                 $importplugins['keymanager'] = new grade_plugin_info('keymanager', $url, get_string('keymanager', 'grades'));
 | 
        
           |  |  | 3676 |             }
 | 
        
           |  |  | 3677 |         }
 | 
        
           |  |  | 3678 |   | 
        
           |  |  | 3679 |         if (count($importplugins) > 0) {
 | 
        
           |  |  | 3680 |             asort($importplugins);
 | 
        
           |  |  | 3681 |             self::$importplugins = $importplugins;
 | 
        
           |  |  | 3682 |         } else {
 | 
        
           |  |  | 3683 |             self::$importplugins = false;
 | 
        
           |  |  | 3684 |         }
 | 
        
           |  |  | 3685 |         return self::$importplugins;
 | 
        
           |  |  | 3686 |     }
 | 
        
           |  |  | 3687 |     /**
 | 
        
           |  |  | 3688 |      * Get information export plugins
 | 
        
           |  |  | 3689 |      * @param int $courseid
 | 
        
           |  |  | 3690 |      * @return array
 | 
        
           |  |  | 3691 |      */
 | 
        
           |  |  | 3692 |     public static function get_plugins_export($courseid) {
 | 
        
           |  |  | 3693 |         global $CFG;
 | 
        
           |  |  | 3694 |   | 
        
           |  |  | 3695 |         if (self::$exportplugins !== null) {
 | 
        
           |  |  | 3696 |             return self::$exportplugins;
 | 
        
           |  |  | 3697 |         }
 | 
        
           |  |  | 3698 |         $context = context_course::instance($courseid);
 | 
        
           |  |  | 3699 |         $exportplugins = array();
 | 
        
           |  |  | 3700 |         $canpublishgrades = 0;
 | 
        
           |  |  | 3701 |         if (has_capability('moodle/grade:export', $context)) {
 | 
        
           |  |  | 3702 |             foreach (core_component::get_plugin_list('gradeexport') as $plugin => $plugindir) {
 | 
        
           |  |  | 3703 |                 if (!has_capability('gradeexport/'.$plugin.':view', $context)) {
 | 
        
           |  |  | 3704 |                     continue;
 | 
        
           |  |  | 3705 |                 }
 | 
        
           |  |  | 3706 |                 // All the grade export plugins has grade publishing capabilities.
 | 
        
           |  |  | 3707 |                 if (has_capability('gradeexport/'.$plugin.':publish', $context)) {
 | 
        
           |  |  | 3708 |                     $canpublishgrades++;
 | 
        
           |  |  | 3709 |                 }
 | 
        
           |  |  | 3710 |   | 
        
           |  |  | 3711 |                 $pluginstr = get_string('pluginname', 'gradeexport_'.$plugin);
 | 
        
           |  |  | 3712 |                 $url = new moodle_url('/grade/export/'.$plugin.'/index.php', array('id'=>$courseid));
 | 
        
           |  |  | 3713 |                 $exportplugins[$plugin] = new grade_plugin_info($plugin, $url, $pluginstr);
 | 
        
           |  |  | 3714 |             }
 | 
        
           |  |  | 3715 |   | 
        
           |  |  | 3716 |             // Show key manager if grade publishing is enabled and the user has at least one grade publishing capability.
 | 
        
           |  |  | 3717 |             if ($CFG->gradepublishing && $canpublishgrades != 0) {
 | 
        
           |  |  | 3718 |                 $url = new moodle_url('/grade/export/keymanager.php', array('id'=>$courseid));
 | 
        
           |  |  | 3719 |                 $exportplugins['keymanager'] = new grade_plugin_info('keymanager', $url, get_string('keymanager', 'grades'));
 | 
        
           |  |  | 3720 |             }
 | 
        
           |  |  | 3721 |         }
 | 
        
           |  |  | 3722 |         if (count($exportplugins) > 0) {
 | 
        
           |  |  | 3723 |             asort($exportplugins);
 | 
        
           |  |  | 3724 |             self::$exportplugins = $exportplugins;
 | 
        
           |  |  | 3725 |         } else {
 | 
        
           |  |  | 3726 |             self::$exportplugins = false;
 | 
        
           |  |  | 3727 |         }
 | 
        
           |  |  | 3728 |         return self::$exportplugins;
 | 
        
           |  |  | 3729 |     }
 | 
        
           |  |  | 3730 |   | 
        
           |  |  | 3731 |     /**
 | 
        
           |  |  | 3732 |      * Returns the value of a field from a user record
 | 
        
           |  |  | 3733 |      *
 | 
        
           |  |  | 3734 |      * @param stdClass $user object
 | 
        
           |  |  | 3735 |      * @param stdClass $field object
 | 
        
           |  |  | 3736 |      * @return string value of the field
 | 
        
           |  |  | 3737 |      */
 | 
        
           |  |  | 3738 |     public static function get_user_field_value($user, $field) {
 | 
        
           |  |  | 3739 |         if (!empty($field->customid)) {
 | 
        
           |  |  | 3740 |             $fieldname = 'customfield_' . $field->customid;
 | 
        
           |  |  | 3741 |             if (!empty($user->{$fieldname}) || is_numeric($user->{$fieldname})) {
 | 
        
           |  |  | 3742 |                 $fieldvalue = $user->{$fieldname};
 | 
        
           |  |  | 3743 |             } else {
 | 
        
           |  |  | 3744 |                 $fieldvalue = $field->default;
 | 
        
           |  |  | 3745 |             }
 | 
        
           |  |  | 3746 |         } else {
 | 
        
           |  |  | 3747 |             $fieldvalue = $user->{$field->shortname};
 | 
        
           |  |  | 3748 |         }
 | 
        
           |  |  | 3749 |         return $fieldvalue;
 | 
        
           |  |  | 3750 |     }
 | 
        
           |  |  | 3751 |   | 
        
           |  |  | 3752 |     /**
 | 
        
           |  |  | 3753 |      * Returns an array of user profile fields to be included in export
 | 
        
           |  |  | 3754 |      *
 | 
        
           |  |  | 3755 |      * @param int $courseid
 | 
        
           |  |  | 3756 |      * @param bool $includecustomfields
 | 
        
           |  |  | 3757 |      * @return array An array of stdClass instances with customid, shortname, datatype, default and fullname fields
 | 
        
           |  |  | 3758 |      */
 | 
        
           |  |  | 3759 |     public static function get_user_profile_fields($courseid, $includecustomfields = false) {
 | 
        
           |  |  | 3760 |         global $CFG, $DB;
 | 
        
           |  |  | 3761 |   | 
        
           |  |  | 3762 |         // Gets the fields that have to be hidden
 | 
        
           |  |  | 3763 |         $hiddenfields = array_map('trim', explode(',', $CFG->hiddenuserfields));
 | 
        
           |  |  | 3764 |         $context = context_course::instance($courseid);
 | 
        
           |  |  | 3765 |         $canseehiddenfields = has_capability('moodle/course:viewhiddenuserfields', $context);
 | 
        
           |  |  | 3766 |         if ($canseehiddenfields) {
 | 
        
           |  |  | 3767 |             $hiddenfields = array();
 | 
        
           |  |  | 3768 |         }
 | 
        
           |  |  | 3769 |   | 
        
           |  |  | 3770 |         $fields = array();
 | 
        
           |  |  | 3771 |         require_once($CFG->dirroot.'/user/lib.php');                // Loads user_get_default_fields()
 | 
        
           |  |  | 3772 |         require_once($CFG->dirroot.'/user/profile/lib.php');        // Loads constants, such as PROFILE_VISIBLE_ALL
 | 
        
           |  |  | 3773 |         $userdefaultfields = user_get_default_fields();
 | 
        
           |  |  | 3774 |   | 
        
           |  |  | 3775 |         // Sets the list of profile fields
 | 
        
           |  |  | 3776 |         $userprofilefields = array_map('trim', explode(',', $CFG->grade_export_userprofilefields));
 | 
        
           |  |  | 3777 |         if (!empty($userprofilefields)) {
 | 
        
           |  |  | 3778 |             foreach ($userprofilefields as $field) {
 | 
        
           |  |  | 3779 |                 $field = trim($field);
 | 
        
           |  |  | 3780 |                 if (in_array($field, $hiddenfields) || !in_array($field, $userdefaultfields)) {
 | 
        
           |  |  | 3781 |                     continue;
 | 
        
           |  |  | 3782 |                 }
 | 
        
           |  |  | 3783 |                 $obj = new stdClass();
 | 
        
           |  |  | 3784 |                 $obj->customid  = 0;
 | 
        
           |  |  | 3785 |                 $obj->shortname = $field;
 | 
        
           |  |  | 3786 |                 $obj->fullname  = get_string($field);
 | 
        
           |  |  | 3787 |                 $fields[] = $obj;
 | 
        
           |  |  | 3788 |             }
 | 
        
           |  |  | 3789 |         }
 | 
        
           |  |  | 3790 |   | 
        
           |  |  | 3791 |         // Sets the list of custom profile fields
 | 
        
           |  |  | 3792 |         $customprofilefields = array_map('trim', explode(',', $CFG->grade_export_customprofilefields));
 | 
        
           |  |  | 3793 |         if ($includecustomfields && !empty($customprofilefields)) {
 | 
        
           |  |  | 3794 |             $customfields = profile_get_user_fields_with_data(0);
 | 
        
           |  |  | 3795 |   | 
        
           |  |  | 3796 |             foreach ($customfields as $fieldobj) {
 | 
        
           |  |  | 3797 |                 $field = (object)$fieldobj->get_field_config_for_external();
 | 
        
           |  |  | 3798 |                 // Make sure we can display this custom field
 | 
        
           |  |  | 3799 |                 if (!in_array($field->shortname, $customprofilefields)) {
 | 
        
           |  |  | 3800 |                     continue;
 | 
        
           |  |  | 3801 |                 } else if (in_array($field->shortname, $hiddenfields)) {
 | 
        
           |  |  | 3802 |                     continue;
 | 
        
           |  |  | 3803 |                 } else if ($field->visible != PROFILE_VISIBLE_ALL && !$canseehiddenfields) {
 | 
        
           |  |  | 3804 |                     continue;
 | 
        
           |  |  | 3805 |                 }
 | 
        
           |  |  | 3806 |   | 
        
           |  |  | 3807 |                 $obj = new stdClass();
 | 
        
           |  |  | 3808 |                 $obj->customid  = $field->id;
 | 
        
           |  |  | 3809 |                 $obj->shortname = $field->shortname;
 | 
        
           |  |  | 3810 |                 $obj->fullname  = format_string($field->name);
 | 
        
           |  |  | 3811 |                 $obj->datatype  = $field->datatype;
 | 
        
           |  |  | 3812 |                 $obj->default   = $field->defaultdata;
 | 
        
           |  |  | 3813 |                 $fields[] = $obj;
 | 
        
           |  |  | 3814 |             }
 | 
        
           |  |  | 3815 |         }
 | 
        
           |  |  | 3816 |   | 
        
           |  |  | 3817 |         return $fields;
 | 
        
           |  |  | 3818 |     }
 | 
        
           |  |  | 3819 |   | 
        
           |  |  | 3820 |     /**
 | 
        
           |  |  | 3821 |      * This helper method gets a snapshot of all the weights for a course.
 | 
        
           |  |  | 3822 |      * It is used as a quick method to see if any wieghts have been automatically adjusted.
 | 
        
           |  |  | 3823 |      * @param int $courseid
 | 
        
           |  |  | 3824 |      * @return array of itemid -> aggregationcoef2
 | 
        
           |  |  | 3825 |      */
 | 
        
           |  |  | 3826 |     public static function fetch_all_natural_weights_for_course($courseid) {
 | 
        
           |  |  | 3827 |         global $DB;
 | 
        
           |  |  | 3828 |         $result = array();
 | 
        
           |  |  | 3829 |   | 
        
           |  |  | 3830 |         $records = $DB->get_records('grade_items', array('courseid'=>$courseid), 'id', 'id, aggregationcoef2');
 | 
        
           |  |  | 3831 |         foreach ($records as $record) {
 | 
        
           |  |  | 3832 |             $result[$record->id] = $record->aggregationcoef2;
 | 
        
           |  |  | 3833 |         }
 | 
        
           |  |  | 3834 |         return $result;
 | 
        
           |  |  | 3835 |     }
 | 
        
           |  |  | 3836 |   | 
        
           |  |  | 3837 |     /**
 | 
        
           |  |  | 3838 |      * Resets all static caches.
 | 
        
           |  |  | 3839 |      *
 | 
        
           |  |  | 3840 |      * @return void
 | 
        
           |  |  | 3841 |      */
 | 
        
           |  |  | 3842 |     public static function reset_caches() {
 | 
        
           |  |  | 3843 |         self::$managesetting = null;
 | 
        
           |  |  | 3844 |         self::$gradereports = null;
 | 
        
           |  |  | 3845 |         self::$gradereportpreferences = null;
 | 
        
           |  |  | 3846 |         self::$scaleinfo = null;
 | 
        
           |  |  | 3847 |         self::$outcomeinfo = null;
 | 
        
           |  |  | 3848 |         self::$letterinfo = null;
 | 
        
           |  |  | 3849 |         self::$importplugins = null;
 | 
        
           |  |  | 3850 |         self::$exportplugins = null;
 | 
        
           |  |  | 3851 |         self::$pluginstrings = null;
 | 
        
           |  |  | 3852 |         self::$aggregationstrings = null;
 | 
        
           |  |  | 3853 |     }
 | 
        
           |  |  | 3854 |   | 
        
           |  |  | 3855 |     /**
 | 
        
           |  |  | 3856 |      * Returns icon of element
 | 
        
           |  |  | 3857 |      *
 | 
        
           |  |  | 3858 |      * @param array $element An array representing an element in the grade_tree
 | 
        
           |  |  | 3859 |      * @param bool  $spacerifnone return spacer if no icon found
 | 
        
           |  |  | 3860 |      *
 | 
        
           |  |  | 3861 |      * @return string icon or spacer
 | 
        
           |  |  | 3862 |      */
 | 
        
           |  |  | 3863 |     public static function get_element_icon(array $element, bool $spacerifnone = false): string {
 | 
        
           |  |  | 3864 |         global $CFG, $OUTPUT;
 | 
        
           |  |  | 3865 |         require_once($CFG->libdir . '/filelib.php');
 | 
        
           |  |  | 3866 |   | 
        
           |  |  | 3867 |         $outputstr = '';
 | 
        
           |  |  | 3868 |   | 
        
           |  |  | 3869 |         // Object holding pix_icon information before instantiation.
 | 
        
           |  |  | 3870 |         $icon = new stdClass();
 | 
        
           |  |  | 3871 |         $icon->attributes = ['class' => 'icon itemicon'];
 | 
        
           |  |  | 3872 |         $icon->component = 'moodle';
 | 
        
           |  |  | 3873 |   | 
        
           |  |  | 3874 |         $none = true;
 | 
        
           |  |  | 3875 |         switch ($element['type']) {
 | 
        
           |  |  | 3876 |             case 'item':
 | 
        
           |  |  | 3877 |             case 'courseitem':
 | 
        
           |  |  | 3878 |             case 'categoryitem':
 | 
        
           |  |  | 3879 |                 $none = false;
 | 
        
           |  |  | 3880 |   | 
        
           |  |  | 3881 |                 $iscourse   = $element['object']->is_course_item();
 | 
        
           |  |  | 3882 |                 $iscategory = $element['object']->is_category_item();
 | 
        
           |  |  | 3883 |                 $isscale    = $element['object']->gradetype == GRADE_TYPE_SCALE;
 | 
        
           |  |  | 3884 |                 $isvalue    = $element['object']->gradetype == GRADE_TYPE_VALUE;
 | 
        
           |  |  | 3885 |                 $isoutcome  = !empty($element['object']->outcomeid);
 | 
        
           |  |  | 3886 |   | 
        
           |  |  | 3887 |                 if ($element['object']->is_calculated()) {
 | 
        
           |  |  | 3888 |                     $icon->pix = 'i/calc';
 | 
        
           |  |  | 3889 |                     $icon->title = s(get_string('calculatedgrade', 'grades'));
 | 
        
           |  |  | 3890 |   | 
        
           |  |  | 3891 |                 } else if (($iscourse || $iscategory) && ($isscale || $isvalue)) {
 | 
        
           |  |  | 3892 |                     if ($category = $element['object']->get_item_category()) {
 | 
        
           |  |  | 3893 |                         $aggrstrings = self::get_aggregation_strings();
 | 
        
           |  |  | 3894 |                         $stragg = $aggrstrings[$category->aggregation];
 | 
        
           |  |  | 3895 |   | 
        
           |  |  | 3896 |                         $icon->pix = 'i/calc';
 | 
        
           |  |  | 3897 |                         $icon->title = s($stragg);
 | 
        
           |  |  | 3898 |   | 
        
           |  |  | 3899 |                         switch ($category->aggregation) {
 | 
        
           |  |  | 3900 |                             case GRADE_AGGREGATE_MEAN:
 | 
        
           |  |  | 3901 |                             case GRADE_AGGREGATE_MEDIAN:
 | 
        
           |  |  | 3902 |                             case GRADE_AGGREGATE_WEIGHTED_MEAN:
 | 
        
           |  |  | 3903 |                             case GRADE_AGGREGATE_WEIGHTED_MEAN2:
 | 
        
           |  |  | 3904 |                             case GRADE_AGGREGATE_EXTRACREDIT_MEAN:
 | 
        
           |  |  | 3905 |                                 $icon->pix = 'i/agg_mean';
 | 
        
           |  |  | 3906 |                                 break;
 | 
        
           |  |  | 3907 |                             case GRADE_AGGREGATE_SUM:
 | 
        
           |  |  | 3908 |                                 $icon->pix = 'i/agg_sum';
 | 
        
           |  |  | 3909 |                                 break;
 | 
        
           |  |  | 3910 |                         }
 | 
        
           |  |  | 3911 |                     }
 | 
        
           |  |  | 3912 |   | 
        
           |  |  | 3913 |                 } else if ($element['object']->itemtype == 'mod') {
 | 
        
           |  |  | 3914 |                     // Prevent outcomes displaying the same icon as the activity they are attached to.
 | 
        
           |  |  | 3915 |                     if ($isoutcome) {
 | 
        
           |  |  | 3916 |                         $icon->pix = 'i/outcomes';
 | 
        
           |  |  | 3917 |                         $icon->title = s(get_string('outcome', 'grades'));
 | 
        
           |  |  | 3918 |                     } else {
 | 
        
           |  |  | 3919 |                         $modinfo = get_fast_modinfo($element['object']->courseid);
 | 
        
           |  |  | 3920 |                         $module = $element['object']->itemmodule;
 | 
        
           |  |  | 3921 |                         $instanceid = $element['object']->iteminstance;
 | 
        
           |  |  | 3922 |                         if (isset($modinfo->instances[$module][$instanceid])) {
 | 
        
           |  |  | 3923 |                             $icon->url = $modinfo->instances[$module][$instanceid]->get_icon_url();
 | 
        
           |  |  | 3924 |                         } else {
 | 
        
           |  |  | 3925 |                             $icon->pix = 'monologo';
 | 
        
           |  |  | 3926 |                             $icon->component = $element['object']->itemmodule;
 | 
        
           |  |  | 3927 |                         }
 | 
        
           |  |  | 3928 |                         $icon->title = s(get_string('modulename', $element['object']->itemmodule));
 | 
        
           |  |  | 3929 |                     }
 | 
        
           |  |  | 3930 |                 } else if ($element['object']->itemtype == 'manual') {
 | 
        
           |  |  | 3931 |                     if ($element['object']->is_outcome_item()) {
 | 
        
           |  |  | 3932 |                         $icon->pix = 'i/outcomes';
 | 
        
           |  |  | 3933 |                         $icon->title = s(get_string('outcome', 'grades'));
 | 
        
           |  |  | 3934 |                     } else {
 | 
        
           |  |  | 3935 |                         $icon->pix = 'i/manual_item';
 | 
        
           |  |  | 3936 |                         $icon->title = s(get_string('manualitem', 'grades'));
 | 
        
           |  |  | 3937 |                     }
 | 
        
           |  |  | 3938 |                 }
 | 
        
           |  |  | 3939 |                 break;
 | 
        
           |  |  | 3940 |   | 
        
           |  |  | 3941 |             case 'category':
 | 
        
           |  |  | 3942 |                 $none = false;
 | 
        
           |  |  | 3943 |                 $icon->pix = 'i/folder';
 | 
        
           |  |  | 3944 |                 $icon->title = s(get_string('category', 'grades'));
 | 
        
           |  |  | 3945 |                 break;
 | 
        
           |  |  | 3946 |         }
 | 
        
           |  |  | 3947 |   | 
        
           |  |  | 3948 |         if ($none) {
 | 
        
           |  |  | 3949 |             if ($spacerifnone) {
 | 
        
           |  |  | 3950 |                 $outputstr = $OUTPUT->spacer() . ' ';
 | 
        
           |  |  | 3951 |             }
 | 
        
           |  |  | 3952 |         } else if (isset($icon->url)) {
 | 
        
           |  |  | 3953 |             $outputstr = html_writer::img($icon->url, $icon->title, $icon->attributes);
 | 
        
           |  |  | 3954 |         } else {
 | 
        
           |  |  | 3955 |             $outputstr = $OUTPUT->pix_icon($icon->pix, $icon->title, $icon->component, $icon->attributes);
 | 
        
           |  |  | 3956 |         }
 | 
        
           |  |  | 3957 |   | 
        
           |  |  | 3958 |         return $outputstr;
 | 
        
           |  |  | 3959 |     }
 | 
        
           |  |  | 3960 |   | 
        
           |  |  | 3961 |     /**
 | 
        
           |  |  | 3962 |      * Returns the string that describes the type of the element.
 | 
        
           |  |  | 3963 |      *
 | 
        
           |  |  | 3964 |      * @param array $element An array representing an element in the grade_tree
 | 
        
           |  |  | 3965 |      * @return string The string that describes the type of the grade element
 | 
        
           |  |  | 3966 |      */
 | 
        
           |  |  | 3967 |     public static function get_element_type_string(array $element): string {
 | 
        
           |  |  | 3968 |         // If the element is a grade category.
 | 
        
           |  |  | 3969 |         if ($element['type'] == 'category') {
 | 
        
           |  |  | 3970 |             return get_string('category', 'grades');
 | 
        
           |  |  | 3971 |         }
 | 
        
           |  |  | 3972 |         // If the element is a grade item.
 | 
        
           |  |  | 3973 |         if (in_array($element['type'], ['item', 'courseitem', 'categoryitem'])) {
 | 
        
           |  |  | 3974 |             // If calculated grade item.
 | 
        
           |  |  | 3975 |             if ($element['object']->is_calculated()) {
 | 
        
           |  |  | 3976 |                 return get_string('calculatedgrade', 'grades');
 | 
        
           |  |  | 3977 |             }
 | 
        
           |  |  | 3978 |             // If aggregated type grade item.
 | 
        
           |  |  | 3979 |             if ($element['object']->is_aggregate_item()) {
 | 
        
           |  |  | 3980 |                 return get_string('aggregation', 'core_grades');
 | 
        
           |  |  | 3981 |             }
 | 
        
           |  |  | 3982 |             // If external grade item (module, plugin, etc.).
 | 
        
           |  |  | 3983 |             if ($element['object']->is_external_item()) {
 | 
        
           |  |  | 3984 |                 // If outcome grade item.
 | 
        
           |  |  | 3985 |                 if ($element['object']->is_outcome_item()) {
 | 
        
           |  |  | 3986 |                     return get_string('outcome', 'grades');
 | 
        
           |  |  | 3987 |                 }
 | 
        
           |  |  | 3988 |                 return get_string('modulename', $element['object']->itemmodule);
 | 
        
           |  |  | 3989 |             }
 | 
        
           |  |  | 3990 |             // If manual grade item.
 | 
        
           |  |  | 3991 |             if ($element['object']->itemtype == 'manual') {
 | 
        
           |  |  | 3992 |                 // If outcome grade item.
 | 
        
           |  |  | 3993 |                 if ($element['object']->is_outcome_item()) {
 | 
        
           |  |  | 3994 |                     return get_string('outcome', 'grades');
 | 
        
           |  |  | 3995 |                 }
 | 
        
           |  |  | 3996 |                 return get_string('manualitem', 'grades');
 | 
        
           |  |  | 3997 |             }
 | 
        
           |  |  | 3998 |         }
 | 
        
           |  |  | 3999 |   | 
        
           |  |  | 4000 |         return '';
 | 
        
           |  |  | 4001 |     }
 | 
        
           |  |  | 4002 |   | 
        
           |  |  | 4003 |     /**
 | 
        
           |  |  | 4004 |      * Returns name of element optionally with icon and link
 | 
        
           |  |  | 4005 |      *
 | 
        
           |  |  | 4006 |      * @param array $element An array representing an element in the grade_tree
 | 
        
           |  |  | 4007 |      * @param bool  $withlink Whether or not this header has a link
 | 
        
           |  |  | 4008 |      * @param bool  $icon Whether or not to display an icon with this header
 | 
        
           |  |  | 4009 |      * @param bool  $spacerifnone return spacer if no icon found
 | 
        
           |  |  | 4010 |      * @param bool  $withdescription Show description if defined by this item.
 | 
        
           |  |  | 4011 |      * @param bool  $fulltotal If the item is a category total, returns $categoryname."total"
 | 
        
           |  |  | 4012 |      *                         instead of "Category total" or "Course total"
 | 
        
           |  |  | 4013 |      * @param moodle_url|null $sortlink Link to sort column.
 | 
        
           |  |  | 4014 |      *
 | 
        
           |  |  | 4015 |      * @return string header
 | 
        
           |  |  | 4016 |      */
 | 
        
           |  |  | 4017 |     public static function get_element_header(array $element, bool $withlink = false, bool $icon = true,
 | 
        
           |  |  | 4018 |             bool $spacerifnone = false, bool $withdescription = false, bool $fulltotal = false,
 | 
        
           |  |  | 4019 |             ?moodle_url $sortlink = null): string {
 | 
        
           |  |  | 4020 |         $header = '';
 | 
        
           |  |  | 4021 |   | 
        
           |  |  | 4022 |         if ($icon) {
 | 
        
           |  |  | 4023 |             $header .= self::get_element_icon($element, $spacerifnone);
 | 
        
           |  |  | 4024 |         }
 | 
        
           |  |  | 4025 |   | 
        
           |  |  | 4026 |         $title = $element['object']->get_name($fulltotal);
 | 
        
           |  |  | 4027 |         $titleunescaped = $element['object']->get_name($fulltotal, false);
 | 
        
           |  |  | 4028 |         $header .= $title;
 | 
        
           |  |  | 4029 |   | 
        
           |  |  | 4030 |         if ($element['type'] != 'item' && $element['type'] != 'categoryitem' && $element['type'] != 'courseitem') {
 | 
        
           |  |  | 4031 |             return $header;
 | 
        
           |  |  | 4032 |         }
 | 
        
           |  |  | 4033 |   | 
        
           |  |  | 4034 |         if ($sortlink) {
 | 
        
           |  |  | 4035 |             $url = $sortlink;
 | 
        
           |  |  | 4036 |             $header = html_writer::link($url, $header, [
 | 
        
           |  |  | 4037 |                 'title' => $titleunescaped,
 | 
        
           |  |  | 4038 |                 'class' => 'gradeitemheader ',
 | 
        
           |  |  | 4039 |             ]);
 | 
        
           |  |  | 4040 |         } else {
 | 
        
           |  |  | 4041 |             if ($withlink && $url = self::get_activity_link($element)) {
 | 
        
           |  |  | 4042 |                 $a = new stdClass();
 | 
        
           |  |  | 4043 |                 $a->name = get_string('modulename', $element['object']->itemmodule);
 | 
        
           |  |  | 4044 |                 $a->title = $titleunescaped;
 | 
        
           |  |  | 4045 |                 $title = get_string('linktoactivity', 'grades', $a);
 | 
        
           |  |  | 4046 |                 $header = html_writer::link($url, $header, [
 | 
        
           |  |  | 4047 |                     'title' => $title,
 | 
        
           |  |  | 4048 |                     'class' => 'gradeitemheader ',
 | 
        
           |  |  | 4049 |                 ]);
 | 
        
           |  |  | 4050 |             } else {
 | 
        
           |  |  | 4051 |                 $header = html_writer::span($header, 'gradeitemheader ', [
 | 
        
           |  |  | 4052 |                     'title' => $titleunescaped,
 | 
        
           |  |  | 4053 |                     'tabindex' => '0',
 | 
        
           |  |  | 4054 |                 ]);
 | 
        
           |  |  | 4055 |             }
 | 
        
           |  |  | 4056 |         }
 | 
        
           |  |  | 4057 |   | 
        
           |  |  | 4058 |         if ($withdescription) {
 | 
        
           |  |  | 4059 |             $desc = $element['object']->get_description();
 | 
        
           |  |  | 4060 |             if (!empty($desc)) {
 | 
        
           |  |  | 4061 |                 $header .= '<div class="gradeitemdescription">' . s($desc) . '</div><div class="gradeitemdescriptionfiller"></div>';
 | 
        
           |  |  | 4062 |             }
 | 
        
           |  |  | 4063 |         }
 | 
        
           |  |  | 4064 |   | 
        
           |  |  | 4065 |         return $header;
 | 
        
           |  |  | 4066 |     }
 | 
        
           |  |  | 4067 |   | 
        
           |  |  | 4068 |     /**
 | 
        
           |  |  | 4069 |      * Returns a link to activity
 | 
        
           |  |  | 4070 |      *
 | 
        
           |  |  | 4071 |      * @param array $element An array representing an element in the grade_tree
 | 
        
           |  |  | 4072 |      * @return moodle_url|null link to activity or null if not found
 | 
        
           |  |  | 4073 |      */
 | 
        
           |  |  | 4074 |     public static function get_activity_link(array $element): ?moodle_url {
 | 
        
           |  |  | 4075 |         $itemtype = $element['object']->itemtype;
 | 
        
           |  |  | 4076 |         $itemmodule = $element['object']->itemmodule;
 | 
        
           |  |  | 4077 |         $iteminstance = $element['object']->iteminstance;
 | 
        
           |  |  | 4078 |   | 
        
           |  |  | 4079 |         // Links only for module items that have valid instance, module and are
 | 
        
           |  |  | 4080 |         // called from grade_tree with valid modinfo.
 | 
        
           |  |  | 4081 |         $modinfo = get_fast_modinfo($element['object']->courseid);
 | 
        
           |  |  | 4082 |         if ($itemtype != 'mod' || !$iteminstance || !$itemmodule || !$modinfo) {
 | 
        
           |  |  | 4083 |             return null;
 | 
        
           |  |  | 4084 |         }
 | 
        
           |  |  | 4085 |   | 
        
           |  |  | 4086 |         // Get $cm efficiently and with visibility information using modinfo.
 | 
        
           |  |  | 4087 |         $instances = $modinfo->get_instances();
 | 
        
           |  |  | 4088 |         if (empty($instances[$itemmodule][$iteminstance])) {
 | 
        
           |  |  | 4089 |             return null;
 | 
        
           |  |  | 4090 |         }
 | 
        
           |  |  | 4091 |         $cm = $instances[$itemmodule][$iteminstance];
 | 
        
           |  |  | 4092 |   | 
        
           |  |  | 4093 |         // Do not add link if activity is not visible to the current user.
 | 
        
           |  |  | 4094 |         if (!$cm->uservisible) {
 | 
        
           |  |  | 4095 |             return null;
 | 
        
           |  |  | 4096 |         }
 | 
        
           |  |  | 4097 |   | 
        
           |  |  | 4098 |         return new moodle_url('/mod/' . $itemmodule . '/view.php', ['id' => $cm->id]);
 | 
        
           |  |  | 4099 |     }
 | 
        
           |  |  | 4100 | }
 |