| 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 |  * Grading method controller for the guide plugin
 | 
        
           |  |  | 19 |  *
 | 
        
           |  |  | 20 |  * @package    gradingform_guide
 | 
        
           |  |  | 21 |  * @copyright  2012 Dan Marsden <dan@danmarsden.com>
 | 
        
           |  |  | 22 |  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
 | 
        
           |  |  | 23 |  */
 | 
        
           |  |  | 24 |   | 
        
           |  |  | 25 | use core_external\external_format_value;
 | 
        
           |  |  | 26 | use core_external\external_multiple_structure;
 | 
        
           |  |  | 27 | use core_external\external_single_structure;
 | 
        
           |  |  | 28 | use core_external\external_value;
 | 
        
           |  |  | 29 |   | 
        
           |  |  | 30 | defined('MOODLE_INTERNAL') || die();
 | 
        
           |  |  | 31 |   | 
        
           |  |  | 32 | require_once($CFG->dirroot.'/grade/grading/form/lib.php');
 | 
        
           |  |  | 33 |   | 
        
           |  |  | 34 | /** guide: Used to compare our gradeitem_type against. */
 | 
        
           |  |  | 35 | const MARKING_GUIDE = 'guide';
 | 
        
           |  |  | 36 |   | 
        
           |  |  | 37 | /**
 | 
        
           |  |  | 38 |  * This controller encapsulates the guide grading logic
 | 
        
           |  |  | 39 |  *
 | 
        
           |  |  | 40 |  * @package    gradingform_guide
 | 
        
           |  |  | 41 |  * @copyright  2012 Dan Marsden <dan@danmarsden.com>
 | 
        
           |  |  | 42 |  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
 | 
        
           |  |  | 43 |  */
 | 
        
           |  |  | 44 | class gradingform_guide_controller extends gradingform_controller {
 | 
        
           |  |  | 45 |     // Modes of displaying the guide (used in gradingform_guide_renderer).
 | 
        
           |  |  | 46 |     /** guide display mode: For editing (moderator or teacher creates a guide) */
 | 
        
           |  |  | 47 |     const DISPLAY_EDIT_FULL     = 1;
 | 
        
           |  |  | 48 |     /** guide display mode: Preview the guide design with hidden fields */
 | 
        
           |  |  | 49 |     const DISPLAY_EDIT_FROZEN   = 2;
 | 
        
           |  |  | 50 |     /** guide display mode: Preview the guide design (for person with manage permission) */
 | 
        
           |  |  | 51 |     const DISPLAY_PREVIEW       = 3;
 | 
        
           |  |  | 52 |     /** guide display mode: Preview the guide (for people being graded) */
 | 
        
           |  |  | 53 |     const DISPLAY_PREVIEW_GRADED= 8;
 | 
        
           |  |  | 54 |     /** guide display mode: For evaluation, enabled (teacher grades a student) */
 | 
        
           |  |  | 55 |     const DISPLAY_EVAL          = 4;
 | 
        
           |  |  | 56 |     /** guide display mode: For evaluation, with hidden fields */
 | 
        
           |  |  | 57 |     const DISPLAY_EVAL_FROZEN   = 5;
 | 
        
           |  |  | 58 |     /** guide display mode: Teacher reviews filled guide */
 | 
        
           |  |  | 59 |     const DISPLAY_REVIEW        = 6;
 | 
        
           |  |  | 60 |     /** guide display mode: Dispaly filled guide (i.e. students see their grades) */
 | 
        
           |  |  | 61 |     const DISPLAY_VIEW          = 7;
 | 
        
           |  |  | 62 |   | 
        
           |  |  | 63 |     /** @var stdClass|false the definition structure */
 | 
        
           |  |  | 64 |     protected $moduleinstance = false;
 | 
        
           |  |  | 65 |   | 
        
           |  |  | 66 |     /**
 | 
        
           |  |  | 67 |      * Extends the module settings navigation with the guide grading settings
 | 
        
           |  |  | 68 |      *
 | 
        
           |  |  | 69 |      * This function is called when the context for the page is an activity module with the
 | 
        
           |  |  | 70 |      * FEATURE_ADVANCED_GRADING, the user has the permission moodle/grade:managegradingforms
 | 
        
           |  |  | 71 |      * and there is an area with the active grading method set to 'guide'.
 | 
        
           |  |  | 72 |      *
 | 
        
           |  |  | 73 |      * @param settings_navigation $settingsnav {@link settings_navigation}
 | 
        
           |  |  | 74 |      * @param navigation_node $node {@link navigation_node}
 | 
        
           |  |  | 75 |      */
 | 
        
           | 1441 | ariadna | 76 |     public function extend_settings_navigation(settings_navigation $settingsnav, ?navigation_node $node=null) {
 | 
        
           | 1 | efrain | 77 |         $node->add(get_string('definemarkingguide', 'gradingform_guide'),
 | 
        
           |  |  | 78 |             $this->get_editor_url(), settings_navigation::TYPE_CUSTOM,
 | 
        
           |  |  | 79 |             null, null, new pix_icon('icon', '', 'gradingform_guide'));
 | 
        
           |  |  | 80 |     }
 | 
        
           |  |  | 81 |   | 
        
           |  |  | 82 |     /**
 | 
        
           |  |  | 83 |      * Extends the module navigation
 | 
        
           |  |  | 84 |      *
 | 
        
           |  |  | 85 |      * This function is called when the context for the page is an activity module with the
 | 
        
           |  |  | 86 |      * FEATURE_ADVANCED_GRADING and there is an area with the active grading method set to the given plugin.
 | 
        
           |  |  | 87 |      *
 | 
        
           |  |  | 88 |      * @param global_navigation $navigation {@link global_navigation}
 | 
        
           |  |  | 89 |      * @param navigation_node $node {@link navigation_node}
 | 
        
           |  |  | 90 |      * @return void
 | 
        
           |  |  | 91 |      */
 | 
        
           | 1441 | ariadna | 92 |     public function extend_navigation(global_navigation $navigation, ?navigation_node $node=null) {
 | 
        
           | 1 | efrain | 93 |         if (has_capability('moodle/grade:managegradingforms', $this->get_context())) {
 | 
        
           |  |  | 94 |             // No need for preview if user can manage forms, he will have link to manage.php in settings instead.
 | 
        
           |  |  | 95 |             return;
 | 
        
           |  |  | 96 |         }
 | 
        
           |  |  | 97 |         if ($this->is_form_defined() && ($options = $this->get_options()) && !empty($options['alwaysshowdefinition'])) {
 | 
        
           |  |  | 98 |             $node->add(get_string('gradingof', 'gradingform_guide', get_grading_manager($this->get_areaid())->get_area_title()),
 | 
        
           |  |  | 99 |                     new moodle_url('/grade/grading/form/'.$this->get_method_name().'/preview.php',
 | 
        
           |  |  | 100 |                         array('areaid' => $this->get_areaid())), settings_navigation::TYPE_CUSTOM);
 | 
        
           |  |  | 101 |         }
 | 
        
           |  |  | 102 |     }
 | 
        
           |  |  | 103 |   | 
        
           |  |  | 104 |     /**
 | 
        
           |  |  | 105 |      * Saves the guide definition into the database
 | 
        
           |  |  | 106 |      *
 | 
        
           |  |  | 107 |      * @see parent::update_definition()
 | 
        
           |  |  | 108 |      * @param stdClass $newdefinition guide definition data as coming from gradingform_guide_editguide::get_data()
 | 
        
           |  |  | 109 |      * @param int $usermodified optional userid of the author of the definition, defaults to the current user
 | 
        
           |  |  | 110 |      */
 | 
        
           |  |  | 111 |     public function update_definition(stdClass $newdefinition, $usermodified = null) {
 | 
        
           |  |  | 112 |         $this->update_or_check_guide($newdefinition, $usermodified, true);
 | 
        
           |  |  | 113 |         if (isset($newdefinition->guide['regrade']) && $newdefinition->guide['regrade']) {
 | 
        
           |  |  | 114 |             $this->mark_for_regrade();
 | 
        
           |  |  | 115 |         }
 | 
        
           |  |  | 116 |     }
 | 
        
           |  |  | 117 |   | 
        
           |  |  | 118 |     /**
 | 
        
           |  |  | 119 |      * Either saves the guide definition into the database or check if it has been changed.
 | 
        
           |  |  | 120 |      *
 | 
        
           |  |  | 121 |      * Returns the level of changes:
 | 
        
           |  |  | 122 |      * 0 - no changes
 | 
        
           |  |  | 123 |      * 1 - only texts or criteria sortorders are changed, students probably do not require re-grading
 | 
        
           |  |  | 124 |      * 2 - added levels but maximum score on guide is the same, students still may not require re-grading
 | 
        
           |  |  | 125 |      * 3 - removed criteria or changed number of points, students require re-grading but may be re-graded automatically
 | 
        
           |  |  | 126 |      * 4 - removed levels - students require re-grading and not all students may be re-graded automatically
 | 
        
           |  |  | 127 |      * 5 - added criteria - all students require manual re-grading
 | 
        
           |  |  | 128 |      *
 | 
        
           |  |  | 129 |      * @param stdClass $newdefinition guide definition data as coming from gradingform_guide_editguide::get_data()
 | 
        
           |  |  | 130 |      * @param int|null $usermodified optional userid of the author of the definition, defaults to the current user
 | 
        
           |  |  | 131 |      * @param bool $doupdate if true actually updates DB, otherwise performs a check
 | 
        
           |  |  | 132 |      * @return int
 | 
        
           |  |  | 133 |      */
 | 
        
           |  |  | 134 |     public function update_or_check_guide(stdClass $newdefinition, $usermodified = null, $doupdate = false) {
 | 
        
           |  |  | 135 |         global $DB;
 | 
        
           |  |  | 136 |   | 
        
           |  |  | 137 |         // Firstly update the common definition data in the {grading_definition} table.
 | 
        
           |  |  | 138 |         if ($this->definition === false) {
 | 
        
           |  |  | 139 |             if (!$doupdate) {
 | 
        
           |  |  | 140 |                 // If we create the new definition there is no such thing as re-grading anyway.
 | 
        
           |  |  | 141 |                 return 5;
 | 
        
           |  |  | 142 |             }
 | 
        
           |  |  | 143 |             // If definition does not exist yet, create a blank one
 | 
        
           |  |  | 144 |             // (we need id to save files embedded in description).
 | 
        
           |  |  | 145 |             parent::update_definition(new stdClass(), $usermodified);
 | 
        
           |  |  | 146 |             parent::load_definition();
 | 
        
           |  |  | 147 |         }
 | 
        
           |  |  | 148 |         if (!isset($newdefinition->guide['options'])) {
 | 
        
           |  |  | 149 |             $newdefinition->guide['options'] = self::get_default_options();
 | 
        
           |  |  | 150 |         }
 | 
        
           |  |  | 151 |         $newdefinition->options = json_encode($newdefinition->guide['options']);
 | 
        
           |  |  | 152 |         $editoroptions = self::description_form_field_options($this->get_context());
 | 
        
           |  |  | 153 |         $newdefinition = file_postupdate_standard_editor($newdefinition, 'description', $editoroptions, $this->get_context(),
 | 
        
           |  |  | 154 |             'grading', 'description', $this->definition->id);
 | 
        
           |  |  | 155 |   | 
        
           |  |  | 156 |         // Reload the definition from the database.
 | 
        
           |  |  | 157 |         $currentdefinition = $this->get_definition(true);
 | 
        
           |  |  | 158 |   | 
        
           |  |  | 159 |         // Update guide data.
 | 
        
           |  |  | 160 |         $haschanges = array();
 | 
        
           |  |  | 161 |         if (empty($newdefinition->guide['criteria'])) {
 | 
        
           |  |  | 162 |             $newcriteria = array();
 | 
        
           |  |  | 163 |         } else {
 | 
        
           |  |  | 164 |             $newcriteria = $newdefinition->guide['criteria']; // New ones to be saved.
 | 
        
           |  |  | 165 |         }
 | 
        
           |  |  | 166 |         $currentcriteria = $currentdefinition->guide_criteria;
 | 
        
           |  |  | 167 |         $criteriafields = array('sortorder', 'description', 'descriptionformat', 'descriptionmarkers',
 | 
        
           |  |  | 168 |             'descriptionmarkersformat', 'shortname', 'maxscore');
 | 
        
           |  |  | 169 |         foreach ($newcriteria as $id => $criterion) {
 | 
        
           |  |  | 170 |             if (preg_match('/^NEWID\d+$/', $id)) {
 | 
        
           |  |  | 171 |                 // Insert criterion into DB.
 | 
        
           |  |  | 172 |                 $data = array('definitionid' => $this->definition->id, 'descriptionformat' => FORMAT_MOODLE,
 | 
        
           |  |  | 173 |                     'descriptionmarkersformat' => FORMAT_MOODLE); // TODO format is not supported yet.
 | 
        
           |  |  | 174 |                 foreach ($criteriafields as $key) {
 | 
        
           |  |  | 175 |                     if (array_key_exists($key, $criterion)) {
 | 
        
           |  |  | 176 |                         $data[$key] = $criterion[$key];
 | 
        
           |  |  | 177 |                     }
 | 
        
           |  |  | 178 |                 }
 | 
        
           |  |  | 179 |                 if ($doupdate) {
 | 
        
           |  |  | 180 |                     $id = $DB->insert_record('gradingform_guide_criteria', $data);
 | 
        
           |  |  | 181 |                 }
 | 
        
           |  |  | 182 |                 $haschanges[5] = true;
 | 
        
           |  |  | 183 |             } else {
 | 
        
           |  |  | 184 |                 // Update criterion in DB.
 | 
        
           |  |  | 185 |                 $data = array();
 | 
        
           |  |  | 186 |                 foreach ($criteriafields as $key) {
 | 
        
           |  |  | 187 |                     if (array_key_exists($key, $criterion) && $criterion[$key] != $currentcriteria[$id][$key]) {
 | 
        
           |  |  | 188 |                         $data[$key] = $criterion[$key];
 | 
        
           |  |  | 189 |                     }
 | 
        
           |  |  | 190 |                 }
 | 
        
           |  |  | 191 |                 if (!empty($data)) {
 | 
        
           |  |  | 192 |                     // Update only if something is changed.
 | 
        
           |  |  | 193 |                     $data['id'] = $id;
 | 
        
           |  |  | 194 |                     if ($doupdate) {
 | 
        
           |  |  | 195 |                         $DB->update_record('gradingform_guide_criteria', $data);
 | 
        
           |  |  | 196 |                     }
 | 
        
           |  |  | 197 |                     $haschanges[1] = true;
 | 
        
           |  |  | 198 |                 }
 | 
        
           |  |  | 199 |             }
 | 
        
           |  |  | 200 |         }
 | 
        
           |  |  | 201 |         // Remove deleted criteria from DB.
 | 
        
           |  |  | 202 |         foreach (array_keys($currentcriteria) as $id) {
 | 
        
           |  |  | 203 |             if (!array_key_exists($id, $newcriteria)) {
 | 
        
           |  |  | 204 |                 if ($doupdate) {
 | 
        
           |  |  | 205 |                     $DB->delete_records('gradingform_guide_criteria', array('id' => $id));
 | 
        
           |  |  | 206 |                 }
 | 
        
           |  |  | 207 |                 $haschanges[3] = true;
 | 
        
           |  |  | 208 |             }
 | 
        
           |  |  | 209 |         }
 | 
        
           |  |  | 210 |         // Now handle comments.
 | 
        
           |  |  | 211 |         if (empty($newdefinition->guide['comments'])) {
 | 
        
           |  |  | 212 |             $newcomment = array();
 | 
        
           |  |  | 213 |         } else {
 | 
        
           |  |  | 214 |             $newcomment = $newdefinition->guide['comments']; // New ones to be saved.
 | 
        
           |  |  | 215 |         }
 | 
        
           |  |  | 216 |         $currentcomments = $currentdefinition->guide_comments;
 | 
        
           |  |  | 217 |         $commentfields = array('sortorder', 'description');
 | 
        
           |  |  | 218 |         foreach ($newcomment as $id => $comment) {
 | 
        
           |  |  | 219 |             if (preg_match('/^NEWID\d+$/', $id)) {
 | 
        
           |  |  | 220 |                 // Insert criterion into DB.
 | 
        
           |  |  | 221 |                 $data = array('definitionid' => $this->definition->id, 'descriptionformat' => FORMAT_MOODLE);
 | 
        
           |  |  | 222 |                 foreach ($commentfields as $key) {
 | 
        
           |  |  | 223 |                     if (array_key_exists($key, $comment)) {
 | 
        
           |  |  | 224 |                         // Check if key is the comment's description.
 | 
        
           |  |  | 225 |                         if ($key === 'description') {
 | 
        
           |  |  | 226 |                             // Get a trimmed value for the comment description.
 | 
        
           |  |  | 227 |                             $description = trim($comment[$key]);
 | 
        
           |  |  | 228 |                             // Check if the comment description is empty.
 | 
        
           |  |  | 229 |                             if (empty($description)) {
 | 
        
           |  |  | 230 |                                 // Continue to the next comment object if the description is empty.
 | 
        
           |  |  | 231 |                                 continue 2;
 | 
        
           |  |  | 232 |                             }
 | 
        
           |  |  | 233 |                         }
 | 
        
           |  |  | 234 |                         $data[$key] = $comment[$key];
 | 
        
           |  |  | 235 |                     }
 | 
        
           |  |  | 236 |                 }
 | 
        
           |  |  | 237 |                 if ($doupdate) {
 | 
        
           |  |  | 238 |                     $id = $DB->insert_record('gradingform_guide_comments', $data);
 | 
        
           |  |  | 239 |                 }
 | 
        
           |  |  | 240 |             } else {
 | 
        
           |  |  | 241 |                 // Update criterion in DB.
 | 
        
           |  |  | 242 |                 $data = array();
 | 
        
           |  |  | 243 |                 foreach ($commentfields as $key) {
 | 
        
           |  |  | 244 |                     if (array_key_exists($key, $comment) && $comment[$key] != $currentcomments[$id][$key]) {
 | 
        
           |  |  | 245 |                         $data[$key] = $comment[$key];
 | 
        
           |  |  | 246 |                     }
 | 
        
           |  |  | 247 |                 }
 | 
        
           |  |  | 248 |                 if (!empty($data)) {
 | 
        
           |  |  | 249 |                     // Update only if something is changed.
 | 
        
           |  |  | 250 |                     $data['id'] = $id;
 | 
        
           |  |  | 251 |                     if ($doupdate) {
 | 
        
           |  |  | 252 |                         $DB->update_record('gradingform_guide_comments', $data);
 | 
        
           |  |  | 253 |                     }
 | 
        
           |  |  | 254 |                 }
 | 
        
           |  |  | 255 |             }
 | 
        
           |  |  | 256 |         }
 | 
        
           |  |  | 257 |         // Remove deleted criteria from DB.
 | 
        
           |  |  | 258 |         foreach (array_keys($currentcomments) as $id) {
 | 
        
           |  |  | 259 |             if (!array_key_exists($id, $newcomment)) {
 | 
        
           |  |  | 260 |                 if ($doupdate) {
 | 
        
           |  |  | 261 |                     $DB->delete_records('gradingform_guide_comments', array('id' => $id));
 | 
        
           |  |  | 262 |                 }
 | 
        
           |  |  | 263 |             }
 | 
        
           |  |  | 264 |         }
 | 
        
           |  |  | 265 |         // End comments handle.
 | 
        
           |  |  | 266 |         foreach (array('status', 'description', 'descriptionformat', 'name', 'options') as $key) {
 | 
        
           |  |  | 267 |             if (isset($newdefinition->$key) && $newdefinition->$key != $this->definition->$key) {
 | 
        
           |  |  | 268 |                 $haschanges[1] = true;
 | 
        
           |  |  | 269 |             }
 | 
        
           |  |  | 270 |         }
 | 
        
           |  |  | 271 |         if ($usermodified && $usermodified != $this->definition->usermodified) {
 | 
        
           |  |  | 272 |             $haschanges[1] = true;
 | 
        
           |  |  | 273 |         }
 | 
        
           |  |  | 274 |         if (!count($haschanges)) {
 | 
        
           |  |  | 275 |             return 0;
 | 
        
           |  |  | 276 |         }
 | 
        
           |  |  | 277 |         if ($doupdate) {
 | 
        
           |  |  | 278 |             parent::update_definition($newdefinition, $usermodified);
 | 
        
           |  |  | 279 |             $this->load_definition();
 | 
        
           |  |  | 280 |         }
 | 
        
           |  |  | 281 |         // Return the maximum level of changes.
 | 
        
           |  |  | 282 |         $changelevels = array_keys($haschanges);
 | 
        
           |  |  | 283 |         sort($changelevels);
 | 
        
           |  |  | 284 |         return array_pop($changelevels);
 | 
        
           |  |  | 285 |     }
 | 
        
           |  |  | 286 |   | 
        
           |  |  | 287 |     /**
 | 
        
           |  |  | 288 |      * Marks all instances filled with this guide with the status INSTANCE_STATUS_NEEDUPDATE
 | 
        
           |  |  | 289 |      */
 | 
        
           |  |  | 290 |     public function mark_for_regrade() {
 | 
        
           |  |  | 291 |         global $DB;
 | 
        
           |  |  | 292 |         if ($this->has_active_instances()) {
 | 
        
           |  |  | 293 |             $conditions = array('definitionid'  => $this->definition->id,
 | 
        
           |  |  | 294 |                         'status'  => gradingform_instance::INSTANCE_STATUS_ACTIVE);
 | 
        
           |  |  | 295 |             $DB->set_field('grading_instances', 'status', gradingform_instance::INSTANCE_STATUS_NEEDUPDATE, $conditions);
 | 
        
           |  |  | 296 |         }
 | 
        
           |  |  | 297 |     }
 | 
        
           |  |  | 298 |   | 
        
           |  |  | 299 |     /**
 | 
        
           |  |  | 300 |      * Loads the guide form definition if it exists
 | 
        
           |  |  | 301 |      *
 | 
        
           |  |  | 302 |      * There is a new array called 'guide_criteria' appended to the list of parent's definition properties.
 | 
        
           |  |  | 303 |      */
 | 
        
           |  |  | 304 |     protected function load_definition() {
 | 
        
           |  |  | 305 |         global $DB;
 | 
        
           |  |  | 306 |   | 
        
           |  |  | 307 |         // Check to see if the user prefs have changed - putting here as this function is called on post even when
 | 
        
           |  |  | 308 |         // validation on the page fails. - hard to find a better place to locate this as it is specific to the guide.
 | 
        
           |  |  | 309 |         $showdesc = optional_param('showmarkerdesc', null, PARAM_BOOL); // Check if we need to change pref.
 | 
        
           |  |  | 310 |         $showdescstudent = optional_param('showstudentdesc', null, PARAM_BOOL); // Check if we need to change pref.
 | 
        
           |  |  | 311 |         if ($showdesc !== null) {
 | 
        
           |  |  | 312 |             set_user_preference('gradingform_guide-showmarkerdesc', $showdesc);
 | 
        
           |  |  | 313 |         }
 | 
        
           |  |  | 314 |         if ($showdescstudent !== null) {
 | 
        
           |  |  | 315 |             set_user_preference('gradingform_guide-showstudentdesc', $showdescstudent);
 | 
        
           |  |  | 316 |         }
 | 
        
           |  |  | 317 |   | 
        
           |  |  | 318 |         // Get definition.
 | 
        
           |  |  | 319 |         $definition = $DB->get_record('grading_definitions', array('areaid' => $this->areaid,
 | 
        
           |  |  | 320 |             'method' => $this->get_method_name()), '*');
 | 
        
           |  |  | 321 |         if (!$definition) {
 | 
        
           |  |  | 322 |             // The definition doesn't have to exist. It may be that we are only now creating it.
 | 
        
           |  |  | 323 |             $this->definition = false;
 | 
        
           |  |  | 324 |             return false;
 | 
        
           |  |  | 325 |         }
 | 
        
           |  |  | 326 |   | 
        
           |  |  | 327 |         $this->definition = $definition;
 | 
        
           |  |  | 328 |         // Now get criteria.
 | 
        
           |  |  | 329 |         $this->definition->guide_criteria = array();
 | 
        
           |  |  | 330 |         $this->definition->guide_comments = array();
 | 
        
           |  |  | 331 |         $criteria = $DB->get_recordset('gradingform_guide_criteria', array('definitionid' => $this->definition->id), 'sortorder');
 | 
        
           |  |  | 332 |         foreach ($criteria as $criterion) {
 | 
        
           |  |  | 333 |             foreach (array('id', 'sortorder', 'description', 'descriptionformat',
 | 
        
           |  |  | 334 |                            'maxscore', 'descriptionmarkers', 'descriptionmarkersformat', 'shortname') as $fieldname) {
 | 
        
           |  |  | 335 |                 if ($fieldname == 'maxscore') {  // Strip any trailing 0.
 | 
        
           |  |  | 336 |                     $this->definition->guide_criteria[$criterion->id][$fieldname] = (float)$criterion->{$fieldname};
 | 
        
           |  |  | 337 |                 } else {
 | 
        
           |  |  | 338 |                     $this->definition->guide_criteria[$criterion->id][$fieldname] = $criterion->{$fieldname};
 | 
        
           |  |  | 339 |                 }
 | 
        
           |  |  | 340 |             }
 | 
        
           |  |  | 341 |         }
 | 
        
           |  |  | 342 |         $criteria->close();
 | 
        
           |  |  | 343 |   | 
        
           |  |  | 344 |         // Now get comments.
 | 
        
           |  |  | 345 |         $comments = $DB->get_recordset('gradingform_guide_comments', array('definitionid' => $this->definition->id), 'sortorder');
 | 
        
           |  |  | 346 |         foreach ($comments as $comment) {
 | 
        
           |  |  | 347 |             foreach (array('id', 'sortorder', 'description', 'descriptionformat') as $fieldname) {
 | 
        
           |  |  | 348 |                 $this->definition->guide_comments[$comment->id][$fieldname] = $comment->{$fieldname};
 | 
        
           |  |  | 349 |             }
 | 
        
           |  |  | 350 |         }
 | 
        
           |  |  | 351 |         $comments->close();
 | 
        
           |  |  | 352 |         if (empty($this->moduleinstance)) { // Only set if empty.
 | 
        
           |  |  | 353 |             $modulename = $this->get_component();
 | 
        
           |  |  | 354 |             $context = $this->get_context();
 | 
        
           |  |  | 355 |             if (strpos($modulename, 'mod_') === 0) {
 | 
        
           |  |  | 356 |                 $dbman = $DB->get_manager();
 | 
        
           |  |  | 357 |                 $modulename = substr($modulename, 4);
 | 
        
           |  |  | 358 |                 if ($dbman->table_exists($modulename)) {
 | 
        
           |  |  | 359 |                     $cm = get_coursemodule_from_id($modulename, $context->instanceid);
 | 
        
           |  |  | 360 |                     if (!empty($cm)) { // This should only occur when the course is being deleted.
 | 
        
           |  |  | 361 |                         $this->moduleinstance = $DB->get_record($modulename, array("id"=>$cm->instance));
 | 
        
           |  |  | 362 |                     }
 | 
        
           |  |  | 363 |                 }
 | 
        
           |  |  | 364 |             }
 | 
        
           |  |  | 365 |         }
 | 
        
           |  |  | 366 |     }
 | 
        
           |  |  | 367 |   | 
        
           |  |  | 368 |     /**
 | 
        
           |  |  | 369 |      * Returns the default options for the guide display
 | 
        
           |  |  | 370 |      *
 | 
        
           |  |  | 371 |      * @return array
 | 
        
           |  |  | 372 |      */
 | 
        
           |  |  | 373 |     public static function get_default_options() {
 | 
        
           |  |  | 374 |         $options = array(
 | 
        
           |  |  | 375 |             'alwaysshowdefinition' => 1,
 | 
        
           |  |  | 376 |             'showmarkspercriterionstudents' => 1,
 | 
        
           |  |  | 377 |         );
 | 
        
           |  |  | 378 |         return $options;
 | 
        
           |  |  | 379 |     }
 | 
        
           |  |  | 380 |   | 
        
           |  |  | 381 |     /**
 | 
        
           |  |  | 382 |      * Gets the options of this guide definition, fills the missing options with default values
 | 
        
           |  |  | 383 |      *
 | 
        
           |  |  | 384 |      * @return array
 | 
        
           |  |  | 385 |      */
 | 
        
           |  |  | 386 |     public function get_options() {
 | 
        
           |  |  | 387 |         $options = self::get_default_options();
 | 
        
           |  |  | 388 |         if (!empty($this->definition->options)) {
 | 
        
           |  |  | 389 |             $thisoptions = json_decode($this->definition->options);
 | 
        
           |  |  | 390 |             foreach ($thisoptions as $option => $value) {
 | 
        
           |  |  | 391 |                 $options[$option] = $value;
 | 
        
           |  |  | 392 |             }
 | 
        
           |  |  | 393 |         }
 | 
        
           |  |  | 394 |         return $options;
 | 
        
           |  |  | 395 |     }
 | 
        
           |  |  | 396 |   | 
        
           |  |  | 397 |     /**
 | 
        
           |  |  | 398 |      * Converts the current definition into an object suitable for the editor form's set_data()
 | 
        
           |  |  | 399 |      *
 | 
        
           |  |  | 400 |      * @param bool $addemptycriterion whether to add an empty criterion if the guide is completely empty (just being created)
 | 
        
           |  |  | 401 |      * @return stdClass
 | 
        
           |  |  | 402 |      */
 | 
        
           |  |  | 403 |     public function get_definition_for_editing($addemptycriterion = false) {
 | 
        
           |  |  | 404 |   | 
        
           |  |  | 405 |         $definition = $this->get_definition();
 | 
        
           |  |  | 406 |         $properties = new stdClass();
 | 
        
           |  |  | 407 |         $properties->areaid = $this->areaid;
 | 
        
           |  |  | 408 |         if (isset($this->moduleinstance->grade)) {
 | 
        
           |  |  | 409 |             $properties->modulegrade = $this->moduleinstance->grade;
 | 
        
           |  |  | 410 |         }
 | 
        
           |  |  | 411 |         if ($definition) {
 | 
        
           |  |  | 412 |             foreach (array('id', 'name', 'description', 'descriptionformat', 'status') as $key) {
 | 
        
           |  |  | 413 |                 $properties->$key = $definition->$key;
 | 
        
           |  |  | 414 |             }
 | 
        
           |  |  | 415 |             $options = self::description_form_field_options($this->get_context());
 | 
        
           |  |  | 416 |             $properties = file_prepare_standard_editor($properties, 'description', $options, $this->get_context(),
 | 
        
           |  |  | 417 |                 'grading', 'description', $definition->id);
 | 
        
           |  |  | 418 |         }
 | 
        
           |  |  | 419 |         $properties->guide = array('criteria' => array(), 'options' => $this->get_options(), 'comments' => array());
 | 
        
           |  |  | 420 |         if (!empty($definition->guide_criteria)) {
 | 
        
           |  |  | 421 |             $properties->guide['criteria'] = $definition->guide_criteria;
 | 
        
           |  |  | 422 |         } else if (!$definition && $addemptycriterion) {
 | 
        
           |  |  | 423 |             $properties->guide['criteria'] = array('addcriterion' => 1);
 | 
        
           |  |  | 424 |         }
 | 
        
           |  |  | 425 |         if (!empty($definition->guide_comments)) {
 | 
        
           |  |  | 426 |             $properties->guide['comments'] = $definition->guide_comments;
 | 
        
           |  |  | 427 |         } else if (!$definition && $addemptycriterion) {
 | 
        
           |  |  | 428 |             $properties->guide['comments'] = array('addcomment' => 1);
 | 
        
           |  |  | 429 |         }
 | 
        
           |  |  | 430 |         return $properties;
 | 
        
           |  |  | 431 |     }
 | 
        
           |  |  | 432 |   | 
        
           |  |  | 433 |     /**
 | 
        
           |  |  | 434 |      * Returns the form definition suitable for cloning into another area
 | 
        
           |  |  | 435 |      *
 | 
        
           |  |  | 436 |      * @see parent::get_definition_copy()
 | 
        
           |  |  | 437 |      * @param gradingform_controller $target the controller of the new copy
 | 
        
           |  |  | 438 |      * @return stdClass definition structure to pass to the target's {@link update_definition()}
 | 
        
           |  |  | 439 |      */
 | 
        
           |  |  | 440 |     public function get_definition_copy(gradingform_controller $target) {
 | 
        
           |  |  | 441 |   | 
        
           |  |  | 442 |         $new = parent::get_definition_copy($target);
 | 
        
           |  |  | 443 |         $old = $this->get_definition_for_editing();
 | 
        
           |  |  | 444 |         $new->description_editor = $old->description_editor;
 | 
        
           |  |  | 445 |         $new->guide = array('criteria' => array(), 'options' => $old->guide['options'], 'comments' => array());
 | 
        
           |  |  | 446 |         $newcritid = 1;
 | 
        
           |  |  | 447 |         foreach ($old->guide['criteria'] as $oldcritid => $oldcrit) {
 | 
        
           |  |  | 448 |             unset($oldcrit['id']);
 | 
        
           |  |  | 449 |             $new->guide['criteria']['NEWID'.$newcritid] = $oldcrit;
 | 
        
           |  |  | 450 |             $newcritid++;
 | 
        
           |  |  | 451 |         }
 | 
        
           |  |  | 452 |         $newcomid = 1;
 | 
        
           |  |  | 453 |         foreach ($old->guide['comments'] as $oldcritid => $oldcom) {
 | 
        
           |  |  | 454 |             unset($oldcom['id']);
 | 
        
           |  |  | 455 |             $new->guide['comments']['NEWID'.$newcomid] = $oldcom;
 | 
        
           |  |  | 456 |             $newcomid++;
 | 
        
           |  |  | 457 |         }
 | 
        
           |  |  | 458 |         return $new;
 | 
        
           |  |  | 459 |     }
 | 
        
           |  |  | 460 |   | 
        
           |  |  | 461 |     /**
 | 
        
           |  |  | 462 |      * Options for displaying the guide description field in the form
 | 
        
           |  |  | 463 |      *
 | 
        
           |  |  | 464 |      * @param context $context
 | 
        
           |  |  | 465 |      * @return array options for the form description field
 | 
        
           |  |  | 466 |      */
 | 
        
           |  |  | 467 |     public static function description_form_field_options($context) {
 | 
        
           |  |  | 468 |         global $CFG;
 | 
        
           |  |  | 469 |         return array(
 | 
        
           |  |  | 470 |             'maxfiles' => -1,
 | 
        
           |  |  | 471 |             'maxbytes' => get_max_upload_file_size($CFG->maxbytes),
 | 
        
           |  |  | 472 |             'context'  => $context,
 | 
        
           |  |  | 473 |         );
 | 
        
           |  |  | 474 |     }
 | 
        
           |  |  | 475 |   | 
        
           |  |  | 476 |     /**
 | 
        
           |  |  | 477 |      * Formats the definition description for display on page
 | 
        
           |  |  | 478 |      *
 | 
        
           |  |  | 479 |      * @return string
 | 
        
           |  |  | 480 |      */
 | 
        
           |  |  | 481 |     public function get_formatted_description() {
 | 
        
           |  |  | 482 |         if (!isset($this->definition->description)) {
 | 
        
           |  |  | 483 |             return '';
 | 
        
           |  |  | 484 |         }
 | 
        
           |  |  | 485 |         $context = $this->get_context();
 | 
        
           |  |  | 486 |   | 
        
           |  |  | 487 |         $options = self::description_form_field_options($this->get_context());
 | 
        
           |  |  | 488 |         $description = file_rewrite_pluginfile_urls($this->definition->description, 'pluginfile.php', $context->id,
 | 
        
           |  |  | 489 |             'grading', 'description', $this->definition->id, $options);
 | 
        
           |  |  | 490 |   | 
        
           |  |  | 491 |         $formatoptions = array(
 | 
        
           |  |  | 492 |             'noclean' => false,
 | 
        
           |  |  | 493 |             'trusted' => false,
 | 
        
           |  |  | 494 |             'filter' => true,
 | 
        
           |  |  | 495 |             'context' => $context
 | 
        
           |  |  | 496 |         );
 | 
        
           |  |  | 497 |         return format_text($description, $this->definition->descriptionformat, $formatoptions);
 | 
        
           |  |  | 498 |     }
 | 
        
           |  |  | 499 |   | 
        
           |  |  | 500 |     /**
 | 
        
           |  |  | 501 |      * Returns the guide plugin renderer
 | 
        
           |  |  | 502 |      *
 | 
        
           |  |  | 503 |      * @param moodle_page $page the target page
 | 
        
           |  |  | 504 |      * @return gradingform_guide_renderer
 | 
        
           |  |  | 505 |      */
 | 
        
           |  |  | 506 |     public function get_renderer(moodle_page $page) {
 | 
        
           |  |  | 507 |         return $page->get_renderer('gradingform_'. $this->get_method_name());
 | 
        
           |  |  | 508 |     }
 | 
        
           |  |  | 509 |   | 
        
           |  |  | 510 |     /**
 | 
        
           |  |  | 511 |      * Returns the HTML code displaying the preview of the grading form
 | 
        
           |  |  | 512 |      *
 | 
        
           |  |  | 513 |      * @param moodle_page $page the target page
 | 
        
           |  |  | 514 |      * @return string
 | 
        
           |  |  | 515 |      */
 | 
        
           |  |  | 516 |     public function render_preview(moodle_page $page) {
 | 
        
           |  |  | 517 |   | 
        
           |  |  | 518 |         if (!$this->is_form_defined()) {
 | 
        
           |  |  | 519 |             throw new coding_exception('It is the caller\'s responsibility to make sure that the form is actually defined');
 | 
        
           |  |  | 520 |         }
 | 
        
           |  |  | 521 |   | 
        
           |  |  | 522 |         // Check if current user is able to see preview
 | 
        
           |  |  | 523 |         $options = $this->get_options();
 | 
        
           |  |  | 524 |         if (empty($options['alwaysshowdefinition']) && !has_capability('moodle/grade:managegradingforms', $page->context))  {
 | 
        
           |  |  | 525 |             return '';
 | 
        
           |  |  | 526 |         }
 | 
        
           |  |  | 527 |   | 
        
           |  |  | 528 |         $criteria = $this->definition->guide_criteria;
 | 
        
           |  |  | 529 |         $comments = $this->definition->guide_comments;
 | 
        
           |  |  | 530 |         $output = $this->get_renderer($page);
 | 
        
           |  |  | 531 |   | 
        
           |  |  | 532 |         $guide = '';
 | 
        
           |  |  | 533 |         $guide .= $output->box($this->get_formatted_description(), 'gradingform_guide-description');
 | 
        
           |  |  | 534 |         if (has_capability('moodle/grade:managegradingforms', $page->context)) {
 | 
        
           |  |  | 535 |             $guide .= $output->display_guide_mapping_explained($this->get_min_max_score());
 | 
        
           |  |  | 536 |             $guide .= $output->display_guide($criteria, $comments, $options, self::DISPLAY_PREVIEW, 'guide');
 | 
        
           |  |  | 537 |         } else {
 | 
        
           |  |  | 538 |             $guide .= $output->display_guide($criteria, $comments, $options, self::DISPLAY_PREVIEW_GRADED, 'guide');
 | 
        
           |  |  | 539 |         }
 | 
        
           |  |  | 540 |   | 
        
           |  |  | 541 |         return $guide;
 | 
        
           |  |  | 542 |     }
 | 
        
           |  |  | 543 |   | 
        
           |  |  | 544 |     /**
 | 
        
           |  |  | 545 |      * Deletes the guide definition and all the associated information
 | 
        
           |  |  | 546 |      */
 | 
        
           |  |  | 547 |     protected function delete_plugin_definition() {
 | 
        
           |  |  | 548 |         global $DB;
 | 
        
           |  |  | 549 |   | 
        
           |  |  | 550 |         // Get the list of instances.
 | 
        
           |  |  | 551 |         $instances = array_keys($DB->get_records('grading_instances', array('definitionid' => $this->definition->id), '', 'id'));
 | 
        
           |  |  | 552 |         // Delete all fillings.
 | 
        
           |  |  | 553 |         $DB->delete_records_list('gradingform_guide_fillings', 'instanceid', $instances);
 | 
        
           |  |  | 554 |         // Delete instances.
 | 
        
           |  |  | 555 |         $DB->delete_records_list('grading_instances', 'id', $instances);
 | 
        
           |  |  | 556 |         // Get the list of criteria records.
 | 
        
           |  |  | 557 |         $criteria = array_keys($DB->get_records('gradingform_guide_criteria',
 | 
        
           |  |  | 558 |             array('definitionid' => $this->definition->id), '', 'id'));
 | 
        
           |  |  | 559 |         // Delete critera.
 | 
        
           |  |  | 560 |         $DB->delete_records_list('gradingform_guide_criteria', 'id', $criteria);
 | 
        
           |  |  | 561 |         // Delete comments.
 | 
        
           |  |  | 562 |         $DB->delete_records('gradingform_guide_comments', array('definitionid' => $this->definition->id));
 | 
        
           |  |  | 563 |     }
 | 
        
           |  |  | 564 |   | 
        
           |  |  | 565 |     /**
 | 
        
           |  |  | 566 |      * If instanceid is specified and grading instance exists and it is created by this rater for
 | 
        
           |  |  | 567 |      * this item, this instance is returned.
 | 
        
           |  |  | 568 |      * If there exists a draft for this raterid+itemid, take this draft (this is the change from parent)
 | 
        
           |  |  | 569 |      * Otherwise new instance is created for the specified rater and itemid
 | 
        
           |  |  | 570 |      *
 | 
        
           |  |  | 571 |      * @param int $instanceid
 | 
        
           |  |  | 572 |      * @param int $raterid
 | 
        
           |  |  | 573 |      * @param int $itemid
 | 
        
           |  |  | 574 |      * @return gradingform_instance
 | 
        
           |  |  | 575 |      */
 | 
        
           |  |  | 576 |     public function get_or_create_instance($instanceid, $raterid, $itemid) {
 | 
        
           |  |  | 577 |         global $DB;
 | 
        
           |  |  | 578 |         if ($instanceid &&
 | 
        
           |  |  | 579 |                 $instance = $DB->get_record('grading_instances',
 | 
        
           |  |  | 580 |                     array('id'  => $instanceid, 'raterid' => $raterid, 'itemid' => $itemid), '*', IGNORE_MISSING)) {
 | 
        
           |  |  | 581 |             return $this->get_instance($instance);
 | 
        
           |  |  | 582 |         }
 | 
        
           |  |  | 583 |         if ($itemid && $raterid) {
 | 
        
           |  |  | 584 |             $params = array('definitionid' => $this->definition->id, 'raterid' => $raterid, 'itemid' => $itemid);
 | 
        
           |  |  | 585 |             if ($rs = $DB->get_records('grading_instances', $params, 'timemodified DESC', '*', 0, 1)) {
 | 
        
           |  |  | 586 |                 $record = reset($rs);
 | 
        
           |  |  | 587 |                 $currentinstance = $this->get_current_instance($raterid, $itemid);
 | 
        
           |  |  | 588 |                 if ($record->status == gradingform_guide_instance::INSTANCE_STATUS_INCOMPLETE &&
 | 
        
           |  |  | 589 |                         (!$currentinstance || $record->timemodified > $currentinstance->get_data('timemodified'))) {
 | 
        
           |  |  | 590 |                     $record->isrestored = true;
 | 
        
           |  |  | 591 |                     return $this->get_instance($record);
 | 
        
           |  |  | 592 |                 }
 | 
        
           |  |  | 593 |             }
 | 
        
           |  |  | 594 |         }
 | 
        
           |  |  | 595 |         return $this->create_instance($raterid, $itemid);
 | 
        
           |  |  | 596 |     }
 | 
        
           |  |  | 597 |   | 
        
           |  |  | 598 |     /**
 | 
        
           |  |  | 599 |      * Returns html code to be included in student's feedback.
 | 
        
           |  |  | 600 |      *
 | 
        
           |  |  | 601 |      * @param moodle_page $page
 | 
        
           |  |  | 602 |      * @param int $itemid
 | 
        
           |  |  | 603 |      * @param array $gradinginfo result of function grade_get_grades
 | 
        
           |  |  | 604 |      * @param string $defaultcontent default string to be returned if no active grading is found
 | 
        
           |  |  | 605 |      * @param bool $cangrade whether current user has capability to grade in this context
 | 
        
           |  |  | 606 |      * @return string
 | 
        
           |  |  | 607 |      */
 | 
        
           |  |  | 608 |     public function render_grade($page, $itemid, $gradinginfo, $defaultcontent, $cangrade) {
 | 
        
           |  |  | 609 |         return $this->get_renderer($page)->display_instances($this->get_active_instances($itemid), $defaultcontent, $cangrade);
 | 
        
           |  |  | 610 |     }
 | 
        
           |  |  | 611 |   | 
        
           |  |  | 612 |     // Full-text search support.
 | 
        
           |  |  | 613 |   | 
        
           |  |  | 614 |     /**
 | 
        
           |  |  | 615 |      * Prepare the part of the search query to append to the FROM statement
 | 
        
           |  |  | 616 |      *
 | 
        
           |  |  | 617 |      * @param string $gdid the alias of grading_definitions.id column used by the caller
 | 
        
           |  |  | 618 |      * @return string
 | 
        
           |  |  | 619 |      */
 | 
        
           |  |  | 620 |     public static function sql_search_from_tables($gdid) {
 | 
        
           |  |  | 621 |         return " LEFT JOIN {gradingform_guide_criteria} gc ON (gc.definitionid = $gdid)";
 | 
        
           |  |  | 622 |     }
 | 
        
           |  |  | 623 |   | 
        
           |  |  | 624 |     /**
 | 
        
           |  |  | 625 |      * Prepare the parts of the SQL WHERE statement to search for the given token
 | 
        
           |  |  | 626 |      *
 | 
        
           |  |  | 627 |      * The returned array cosists of the list of SQL comparions and the list of
 | 
        
           |  |  | 628 |      * respective parameters for the comparisons. The returned chunks will be joined
 | 
        
           |  |  | 629 |      * with other conditions using the OR operator.
 | 
        
           |  |  | 630 |      *
 | 
        
           |  |  | 631 |      * @param string $token token to search for
 | 
        
           |  |  | 632 |      * @return array An array containing two more arrays
 | 
        
           |  |  | 633 |      *     Array of search SQL fragments
 | 
        
           |  |  | 634 |      *     Array of params for the search fragments
 | 
        
           |  |  | 635 |      */
 | 
        
           |  |  | 636 |     public static function sql_search_where($token) {
 | 
        
           |  |  | 637 |         global $DB;
 | 
        
           |  |  | 638 |   | 
        
           |  |  | 639 |         $subsql = array();
 | 
        
           |  |  | 640 |         $params = array();
 | 
        
           |  |  | 641 |   | 
        
           |  |  | 642 |         // Search in guide criteria description.
 | 
        
           |  |  | 643 |         $subsql[] = $DB->sql_like('gc.description', '?', false, false);
 | 
        
           |  |  | 644 |         $params[] = '%'.$DB->sql_like_escape($token).'%';
 | 
        
           |  |  | 645 |   | 
        
           |  |  | 646 |         return array($subsql, $params);
 | 
        
           |  |  | 647 |     }
 | 
        
           |  |  | 648 |   | 
        
           |  |  | 649 |     /**
 | 
        
           |  |  | 650 |      * Calculates and returns the possible minimum and maximum score (in points) for this guide
 | 
        
           |  |  | 651 |      *
 | 
        
           |  |  | 652 |      * @return array
 | 
        
           |  |  | 653 |      */
 | 
        
           |  |  | 654 |     public function get_min_max_score() {
 | 
        
           |  |  | 655 |         if (!$this->is_form_available()) {
 | 
        
           |  |  | 656 |             return null;
 | 
        
           |  |  | 657 |         }
 | 
        
           |  |  | 658 |         $returnvalue = array('minscore' => 0, 'maxscore' => 0);
 | 
        
           |  |  | 659 |         $maxscore = 0;
 | 
        
           |  |  | 660 |         foreach ($this->get_definition()->guide_criteria as $id => $criterion) {
 | 
        
           |  |  | 661 |             $maxscore += $criterion['maxscore'];
 | 
        
           |  |  | 662 |         }
 | 
        
           |  |  | 663 |         $returnvalue['maxscore'] = $maxscore;
 | 
        
           |  |  | 664 |         $returnvalue['minscore'] = 0;
 | 
        
           |  |  | 665 |         if (!$this->is_shared_template()) {
 | 
        
           |  |  | 666 |             $fieldname = \core_grades\component_gradeitems::get_field_name_for_itemname($this->component, $this->area, 'grade');
 | 
        
           |  |  | 667 |             if (!empty($this->moduleinstance->{$fieldname})) {
 | 
        
           |  |  | 668 |                 $graderange = make_grades_menu($this->moduleinstance->{$fieldname});
 | 
        
           |  |  | 669 |                 $returnvalue['modulegrade'] = count($graderange) - 1;
 | 
        
           |  |  | 670 |             }
 | 
        
           |  |  | 671 |         }
 | 
        
           |  |  | 672 |         return $returnvalue;
 | 
        
           |  |  | 673 |     }
 | 
        
           |  |  | 674 |   | 
        
           |  |  | 675 |     /**
 | 
        
           |  |  | 676 |      * @return array An array containing 2 key/value pairs which hold the external_multiple_structure
 | 
        
           |  |  | 677 |      * for the 'guide_criteria' and the 'guide_comments'.
 | 
        
           |  |  | 678 |      * @see gradingform_controller::get_external_definition_details()
 | 
        
           |  |  | 679 |      * @since Moodle 2.5
 | 
        
           |  |  | 680 |      */
 | 
        
           |  |  | 681 |     public static function get_external_definition_details() {
 | 
        
           |  |  | 682 |         $guide_criteria = new external_multiple_structure(
 | 
        
           |  |  | 683 |                               new external_single_structure(
 | 
        
           |  |  | 684 |                                   array(
 | 
        
           |  |  | 685 |                                       'id'   => new external_value(PARAM_INT, 'criterion id', VALUE_OPTIONAL),
 | 
        
           |  |  | 686 |                                       'sortorder' => new external_value(PARAM_INT, 'sortorder', VALUE_OPTIONAL),
 | 
        
           |  |  | 687 |                                       'description' => new external_value(PARAM_RAW, 'description', VALUE_OPTIONAL),
 | 
        
           |  |  | 688 |                                       'descriptionformat' => new external_format_value('description', VALUE_OPTIONAL),
 | 
        
           |  |  | 689 |                                       'shortname' => new external_value(PARAM_TEXT, 'description'),
 | 
        
           |  |  | 690 |                                       'descriptionmarkers' => new external_value(PARAM_RAW, 'markers description', VALUE_OPTIONAL),
 | 
        
           |  |  | 691 |                                       'descriptionmarkersformat' => new external_format_value('descriptionmarkers', VALUE_OPTIONAL),
 | 
        
           |  |  | 692 |                                       'maxscore' => new external_value(PARAM_FLOAT, 'maximum score')
 | 
        
           |  |  | 693 |                                       )
 | 
        
           |  |  | 694 |                                   )
 | 
        
           |  |  | 695 |         );
 | 
        
           |  |  | 696 |         $guide_comments = new external_multiple_structure(
 | 
        
           |  |  | 697 |                               new external_single_structure(
 | 
        
           |  |  | 698 |                                   array(
 | 
        
           |  |  | 699 |                                       'id'   => new external_value(PARAM_INT, 'criterion id', VALUE_OPTIONAL),
 | 
        
           |  |  | 700 |                                       'sortorder' => new external_value(PARAM_INT, 'sortorder', VALUE_OPTIONAL),
 | 
        
           |  |  | 701 |                                       'description' => new external_value(PARAM_RAW, 'description', VALUE_OPTIONAL),
 | 
        
           |  |  | 702 |                                       'descriptionformat' => new external_format_value('description', VALUE_OPTIONAL)
 | 
        
           |  |  | 703 |                                    )
 | 
        
           |  |  | 704 |                               ), 'comments', VALUE_OPTIONAL
 | 
        
           |  |  | 705 |         );
 | 
        
           |  |  | 706 |         return array('guide_criteria' => $guide_criteria, 'guide_comments' => $guide_comments);
 | 
        
           |  |  | 707 |     }
 | 
        
           |  |  | 708 |   | 
        
           |  |  | 709 |     /**
 | 
        
           |  |  | 710 |      * Returns an array that defines the structure of the guide's filling. This function is used by
 | 
        
           |  |  | 711 |      * the web service function core_grading_external::get_gradingform_instances().
 | 
        
           |  |  | 712 |      *
 | 
        
           |  |  | 713 |      * @return An array containing a single key/value pair with the 'criteria' external_multiple_structure
 | 
        
           |  |  | 714 |      * @see gradingform_controller::get_external_instance_filling_details()
 | 
        
           |  |  | 715 |      * @since Moodle 2.6
 | 
        
           |  |  | 716 |      */
 | 
        
           |  |  | 717 |     public static function get_external_instance_filling_details() {
 | 
        
           |  |  | 718 |         $criteria = new external_multiple_structure(
 | 
        
           |  |  | 719 |             new external_single_structure(
 | 
        
           |  |  | 720 |                 array(
 | 
        
           |  |  | 721 |                     'id' => new external_value(PARAM_INT, 'filling id'),
 | 
        
           |  |  | 722 |                     'criterionid' => new external_value(PARAM_INT, 'criterion id'),
 | 
        
           |  |  | 723 |                     'levelid' => new external_value(PARAM_INT, 'level id', VALUE_OPTIONAL),
 | 
        
           |  |  | 724 |                     'remark' => new external_value(PARAM_RAW, 'remark', VALUE_OPTIONAL),
 | 
        
           |  |  | 725 |                     'remarkformat' => new external_format_value('remark', VALUE_OPTIONAL),
 | 
        
           |  |  | 726 |                     'score' => new external_value(PARAM_FLOAT, 'maximum score')
 | 
        
           |  |  | 727 |                 )
 | 
        
           |  |  | 728 |             ), 'filling', VALUE_OPTIONAL
 | 
        
           |  |  | 729 |         );
 | 
        
           |  |  | 730 |         return array ('criteria' => $criteria);
 | 
        
           |  |  | 731 |     }
 | 
        
           |  |  | 732 |   | 
        
           |  |  | 733 | }
 | 
        
           |  |  | 734 |   | 
        
           |  |  | 735 | /**
 | 
        
           |  |  | 736 |  * Class to manage one guide grading instance. Stores information and performs actions like
 | 
        
           |  |  | 737 |  * update, copy, validate, submit, etc.
 | 
        
           |  |  | 738 |  *
 | 
        
           |  |  | 739 |  * @package    gradingform_guide
 | 
        
           |  |  | 740 |  * @copyright  2012 Dan Marsden <dan@danmarsden.com>
 | 
        
           |  |  | 741 |  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
 | 
        
           |  |  | 742 |  */
 | 
        
           |  |  | 743 | class gradingform_guide_instance extends gradingform_instance {
 | 
        
           |  |  | 744 |   | 
        
           |  |  | 745 |     /** @var array */
 | 
        
           |  |  | 746 |     protected $guide;
 | 
        
           |  |  | 747 |   | 
        
           |  |  | 748 |     /** @var array An array of validation errors */
 | 
        
           |  |  | 749 |     protected $validationerrors = array();
 | 
        
           |  |  | 750 |   | 
        
           |  |  | 751 |     /**
 | 
        
           |  |  | 752 |      * Deletes this (INCOMPLETE) instance from database.
 | 
        
           |  |  | 753 |      */
 | 
        
           |  |  | 754 |     public function cancel() {
 | 
        
           |  |  | 755 |         global $DB;
 | 
        
           |  |  | 756 |         parent::cancel();
 | 
        
           |  |  | 757 |         $DB->delete_records('gradingform_guide_fillings', array('instanceid' => $this->get_id()));
 | 
        
           |  |  | 758 |     }
 | 
        
           |  |  | 759 |   | 
        
           |  |  | 760 |     /**
 | 
        
           |  |  | 761 |      * Duplicates the instance before editing (optionally substitutes raterid and/or itemid with
 | 
        
           |  |  | 762 |      * the specified values)
 | 
        
           |  |  | 763 |      *
 | 
        
           |  |  | 764 |      * @param int $raterid value for raterid in the duplicate
 | 
        
           |  |  | 765 |      * @param int $itemid value for itemid in the duplicate
 | 
        
           |  |  | 766 |      * @return int id of the new instance
 | 
        
           |  |  | 767 |      */
 | 
        
           |  |  | 768 |     public function copy($raterid, $itemid) {
 | 
        
           |  |  | 769 |         global $DB;
 | 
        
           |  |  | 770 |         $instanceid = parent::copy($raterid, $itemid);
 | 
        
           |  |  | 771 |         $currentgrade = $this->get_guide_filling();
 | 
        
           |  |  | 772 |         foreach ($currentgrade['criteria'] as $criterionid => $record) {
 | 
        
           |  |  | 773 |             $params = array('instanceid' => $instanceid, 'criterionid' => $criterionid,
 | 
        
           |  |  | 774 |                 'score' => $record['score'], 'remark' => $record['remark'], 'remarkformat' => $record['remarkformat']);
 | 
        
           |  |  | 775 |             $DB->insert_record('gradingform_guide_fillings', $params);
 | 
        
           |  |  | 776 |         }
 | 
        
           |  |  | 777 |         return $instanceid;
 | 
        
           |  |  | 778 |     }
 | 
        
           |  |  | 779 |   | 
        
           |  |  | 780 |     /**
 | 
        
           |  |  | 781 |      * Determines whether the submitted form was empty.
 | 
        
           |  |  | 782 |      *
 | 
        
           |  |  | 783 |      * @param array $elementvalue value of element submitted from the form
 | 
        
           |  |  | 784 |      * @return boolean true if the form is empty
 | 
        
           |  |  | 785 |      */
 | 
        
           |  |  | 786 |     public function is_empty_form($elementvalue) {
 | 
        
           |  |  | 787 |         $criteria = $this->get_controller()->get_definition()->guide_criteria;
 | 
        
           |  |  | 788 |         foreach ($criteria as $id => $criterion) {
 | 
        
           |  |  | 789 |             $score = $elementvalue['criteria'][$id]['score'];
 | 
        
           |  |  | 790 |             $remark = $elementvalue['criteria'][$id]['remark'];
 | 
        
           |  |  | 791 |   | 
        
           |  |  | 792 |             if ((isset($score) && $score !== '')
 | 
        
           |  |  | 793 |                     || ((isset($remark) && $remark !== ''))) {
 | 
        
           |  |  | 794 |                 return false;
 | 
        
           |  |  | 795 |             }
 | 
        
           |  |  | 796 |         }
 | 
        
           |  |  | 797 |         return true;
 | 
        
           |  |  | 798 |     }
 | 
        
           |  |  | 799 |   | 
        
           |  |  | 800 |     /**
 | 
        
           |  |  | 801 |      * Validates that guide is fully completed and contains valid grade on each criterion
 | 
        
           |  |  | 802 |      *
 | 
        
           |  |  | 803 |      * @param array $elementvalue value of element as came in form submit
 | 
        
           |  |  | 804 |      * @return boolean true if the form data is validated and contains no errors
 | 
        
           |  |  | 805 |      */
 | 
        
           |  |  | 806 |     public function validate_grading_element($elementvalue) {
 | 
        
           |  |  | 807 |         $criteria = $this->get_controller()->get_definition()->guide_criteria;
 | 
        
           |  |  | 808 |         if (!isset($elementvalue['criteria']) || !is_array($elementvalue['criteria']) ||
 | 
        
           |  |  | 809 |             count($elementvalue['criteria']) < count($criteria)) {
 | 
        
           |  |  | 810 |             return false;
 | 
        
           |  |  | 811 |         }
 | 
        
           |  |  | 812 |         // Reset validation errors.
 | 
        
           |  |  | 813 |         $this->validationerrors = null;
 | 
        
           |  |  | 814 |         foreach ($criteria as $id => $criterion) {
 | 
        
           |  |  | 815 |             if (!isset($elementvalue['criteria'][$id]['score'])
 | 
        
           |  |  | 816 |                     || $criterion['maxscore'] < $elementvalue['criteria'][$id]['score']
 | 
        
           |  |  | 817 |                     || !is_numeric($elementvalue['criteria'][$id]['score'])
 | 
        
           |  |  | 818 |                     || $elementvalue['criteria'][$id]['score'] < 0) {
 | 
        
           |  |  | 819 |                 $this->validationerrors[$id]['score'] = $elementvalue['criteria'][$id]['score'];
 | 
        
           |  |  | 820 |             }
 | 
        
           |  |  | 821 |         }
 | 
        
           |  |  | 822 |         if (!empty($this->validationerrors)) {
 | 
        
           |  |  | 823 |             return false;
 | 
        
           |  |  | 824 |         }
 | 
        
           |  |  | 825 |         return true;
 | 
        
           |  |  | 826 |     }
 | 
        
           |  |  | 827 |   | 
        
           |  |  | 828 |     /**
 | 
        
           |  |  | 829 |      * Retrieves from DB and returns the data how this guide was filled
 | 
        
           |  |  | 830 |      *
 | 
        
           |  |  | 831 |      * @param bool $force whether to force DB query even if the data is cached
 | 
        
           |  |  | 832 |      * @return array
 | 
        
           |  |  | 833 |      */
 | 
        
           |  |  | 834 |     public function get_guide_filling($force = false) {
 | 
        
           |  |  | 835 |         global $DB;
 | 
        
           |  |  | 836 |         if ($this->guide === null || $force) {
 | 
        
           |  |  | 837 |             $records = $DB->get_records('gradingform_guide_fillings', array('instanceid' => $this->get_id()));
 | 
        
           |  |  | 838 |             $this->guide = array('criteria' => array());
 | 
        
           |  |  | 839 |             foreach ($records as $record) {
 | 
        
           |  |  | 840 |                 $record->score = (float)$record->score; // Strip trailing 0.
 | 
        
           |  |  | 841 |                 $this->guide['criteria'][$record->criterionid] = (array)$record;
 | 
        
           |  |  | 842 |             }
 | 
        
           |  |  | 843 |         }
 | 
        
           |  |  | 844 |         return $this->guide;
 | 
        
           |  |  | 845 |     }
 | 
        
           |  |  | 846 |   | 
        
           |  |  | 847 |     /**
 | 
        
           |  |  | 848 |      * Updates the instance with the data received from grading form. This function may be
 | 
        
           |  |  | 849 |      * called via AJAX when grading is not yet completed, so it does not change the
 | 
        
           |  |  | 850 |      * status of the instance.
 | 
        
           |  |  | 851 |      *
 | 
        
           |  |  | 852 |      * @param array $data
 | 
        
           |  |  | 853 |      */
 | 
        
           |  |  | 854 |     public function update($data) {
 | 
        
           |  |  | 855 |         global $DB;
 | 
        
           |  |  | 856 |         $currentgrade = $this->get_guide_filling();
 | 
        
           |  |  | 857 |         parent::update($data);
 | 
        
           |  |  | 858 |   | 
        
           |  |  | 859 |         foreach ($data['criteria'] as $criterionid => $record) {
 | 
        
           | 1441 | ariadna | 860 |             // Hardcoding/defaulting to html format for new/existing record
 | 
        
           |  |  | 861 |             $record['remarkformat'] = FORMAT_HTML;
 | 
        
           |  |  | 862 |   | 
        
           | 1 | efrain | 863 |             if (!array_key_exists($criterionid, $currentgrade['criteria'])) {
 | 
        
           |  |  | 864 |                 $newrecord = array('instanceid' => $this->get_id(), 'criterionid' => $criterionid,
 | 
        
           | 1441 | ariadna | 865 |                     'score' => $record['score'], 'remarkformat' => $record['remarkformat']);
 | 
        
           | 1 | efrain | 866 |                 if (isset($record['remark'])) {
 | 
        
           |  |  | 867 |                     $newrecord['remark'] = $record['remark'];
 | 
        
           |  |  | 868 |                 }
 | 
        
           |  |  | 869 |                 $DB->insert_record('gradingform_guide_fillings', $newrecord);
 | 
        
           |  |  | 870 |             } else {
 | 
        
           |  |  | 871 |                 $newrecord = array('id' => $currentgrade['criteria'][$criterionid]['id']);
 | 
        
           | 1441 | ariadna | 872 |                 foreach (array('score', 'remark', 'remarkformat') as $key) {
 | 
        
           | 1 | efrain | 873 |                     if (isset($record[$key]) && $currentgrade['criteria'][$criterionid][$key] != $record[$key]) {
 | 
        
           |  |  | 874 |                         $newrecord[$key] = $record[$key];
 | 
        
           |  |  | 875 |                     }
 | 
        
           |  |  | 876 |                 }
 | 
        
           |  |  | 877 |                 if (count($newrecord) > 1) {
 | 
        
           |  |  | 878 |                     $DB->update_record('gradingform_guide_fillings', $newrecord);
 | 
        
           |  |  | 879 |                 }
 | 
        
           |  |  | 880 |             }
 | 
        
           |  |  | 881 |         }
 | 
        
           |  |  | 882 |         foreach ($currentgrade['criteria'] as $criterionid => $record) {
 | 
        
           |  |  | 883 |             if (!array_key_exists($criterionid, $data['criteria'])) {
 | 
        
           |  |  | 884 |                 $DB->delete_records('gradingform_guide_fillings', array('id' => $record['id']));
 | 
        
           |  |  | 885 |             }
 | 
        
           |  |  | 886 |         }
 | 
        
           |  |  | 887 |         $this->get_guide_filling(true);
 | 
        
           |  |  | 888 |     }
 | 
        
           |  |  | 889 |   | 
        
           |  |  | 890 |     /**
 | 
        
           |  |  | 891 |      * Removes the attempt from the gradingform_guide_fillings table
 | 
        
           |  |  | 892 |      * @param array $data the attempt data
 | 
        
           |  |  | 893 |      */
 | 
        
           |  |  | 894 |     public function clear_attempt($data) {
 | 
        
           |  |  | 895 |         global $DB;
 | 
        
           |  |  | 896 |   | 
        
           |  |  | 897 |         foreach ($data['criteria'] as $criterionid => $record) {
 | 
        
           |  |  | 898 |             $DB->delete_records('gradingform_guide_fillings',
 | 
        
           |  |  | 899 |                 array('criterionid' => $criterionid, 'instanceid' => $this->get_id()));
 | 
        
           |  |  | 900 |         }
 | 
        
           |  |  | 901 |     }
 | 
        
           |  |  | 902 |   | 
        
           |  |  | 903 |     /**
 | 
        
           |  |  | 904 |      * Calculates the grade to be pushed to the gradebook
 | 
        
           |  |  | 905 |      *
 | 
        
           |  |  | 906 |      * @return float|int the valid grade from $this->get_controller()->get_grade_range()
 | 
        
           |  |  | 907 |      */
 | 
        
           |  |  | 908 |     public function get_grade() {
 | 
        
           |  |  | 909 |         $grade = $this->get_guide_filling();
 | 
        
           |  |  | 910 |   | 
        
           |  |  | 911 |         if (!($scores = $this->get_controller()->get_min_max_score()) || $scores['maxscore'] <= $scores['minscore']) {
 | 
        
           |  |  | 912 |             return -1;
 | 
        
           |  |  | 913 |         }
 | 
        
           |  |  | 914 |   | 
        
           |  |  | 915 |         $graderange = array_keys($this->get_controller()->get_grade_range());
 | 
        
           |  |  | 916 |         if (empty($graderange)) {
 | 
        
           |  |  | 917 |             return -1;
 | 
        
           |  |  | 918 |         }
 | 
        
           |  |  | 919 |         sort($graderange);
 | 
        
           |  |  | 920 |         $mingrade = $graderange[0];
 | 
        
           |  |  | 921 |         $maxgrade = $graderange[count($graderange) - 1];
 | 
        
           |  |  | 922 |   | 
        
           |  |  | 923 |         $curscore = 0;
 | 
        
           |  |  | 924 |         foreach ($grade['criteria'] as $record) {
 | 
        
           |  |  | 925 |             $curscore += $record['score'];
 | 
        
           |  |  | 926 |         }
 | 
        
           |  |  | 927 |         $gradeoffset = ($curscore-$scores['minscore'])/($scores['maxscore']-$scores['minscore'])*
 | 
        
           |  |  | 928 |             ($maxgrade-$mingrade);
 | 
        
           |  |  | 929 |         if ($this->get_controller()->get_allow_grade_decimals()) {
 | 
        
           |  |  | 930 |             return $gradeoffset + $mingrade;
 | 
        
           |  |  | 931 |         }
 | 
        
           |  |  | 932 |         return round($gradeoffset, 0) + $mingrade;
 | 
        
           |  |  | 933 |     }
 | 
        
           |  |  | 934 |   | 
        
           |  |  | 935 |     /**
 | 
        
           |  |  | 936 |      * Returns html for form element of type 'grading'.
 | 
        
           |  |  | 937 |      *
 | 
        
           |  |  | 938 |      * @param moodle_page $page
 | 
        
           |  |  | 939 |      * @param MoodleQuickForm_grading $gradingformelement
 | 
        
           |  |  | 940 |      * @return string
 | 
        
           |  |  | 941 |      */
 | 
        
           |  |  | 942 |     public function render_grading_element($page, $gradingformelement) {
 | 
        
           |  |  | 943 |         if (!$gradingformelement->_flagFrozen) {
 | 
        
           |  |  | 944 |             $module = array('name'=>'gradingform_guide', 'fullpath'=>'/grade/grading/form/guide/js/guide.js');
 | 
        
           |  |  | 945 |             $page->requires->js_init_call('M.gradingform_guide.init', array(
 | 
        
           |  |  | 946 |                 array('name' => $gradingformelement->getName())), true, $module);
 | 
        
           |  |  | 947 |             $mode = gradingform_guide_controller::DISPLAY_EVAL;
 | 
        
           |  |  | 948 |         } else {
 | 
        
           |  |  | 949 |             if ($gradingformelement->_persistantFreeze) {
 | 
        
           |  |  | 950 |                 $mode = gradingform_guide_controller::DISPLAY_EVAL_FROZEN;
 | 
        
           |  |  | 951 |             } else {
 | 
        
           |  |  | 952 |                 $mode = gradingform_guide_controller::DISPLAY_REVIEW;
 | 
        
           |  |  | 953 |             }
 | 
        
           |  |  | 954 |         }
 | 
        
           |  |  | 955 |         $criteria = $this->get_controller()->get_definition()->guide_criteria;
 | 
        
           |  |  | 956 |         $comments = $this->get_controller()->get_definition()->guide_comments;
 | 
        
           |  |  | 957 |         $options = $this->get_controller()->get_options();
 | 
        
           |  |  | 958 |         $value = $gradingformelement->getValue();
 | 
        
           |  |  | 959 |         $html = '';
 | 
        
           |  |  | 960 |         if ($value === null) {
 | 
        
           |  |  | 961 |             $value = $this->get_guide_filling();
 | 
        
           |  |  | 962 |         } else if (!$this->validate_grading_element($value)) {
 | 
        
           |  |  | 963 |             $html .= html_writer::tag('div', get_string('guidenotcompleted', 'gradingform_guide'),
 | 
        
           |  |  | 964 |                 array('class' => 'gradingform_guide-error'));
 | 
        
           |  |  | 965 |             if (!empty($this->validationerrors)) {
 | 
        
           |  |  | 966 |                 foreach ($this->validationerrors as $id => $err) {
 | 
        
           |  |  | 967 |                     $a = new stdClass();
 | 
        
           |  |  | 968 |                     $a->criterianame = format_text($criteria[$id]['shortname'], FORMAT_HTML);
 | 
        
           |  |  | 969 |                     $a->maxscore = $criteria[$id]['maxscore'];
 | 
        
           |  |  | 970 |                     if ($this->validationerrors[$id]['score'] < 0) {
 | 
        
           |  |  | 971 |                         $html .= html_writer::tag('div', get_string('err_scoreisnegative', 'gradingform_guide', $a),
 | 
        
           |  |  | 972 |                         array('class' => 'gradingform_guide-error'));
 | 
        
           |  |  | 973 |                     } else {
 | 
        
           |  |  | 974 |                         $html .= html_writer::tag('div', get_string('err_scoreinvalid', 'gradingform_guide', $a),
 | 
        
           |  |  | 975 |                         array('class' => 'gradingform_guide-error'));
 | 
        
           |  |  | 976 |                     }
 | 
        
           |  |  | 977 |                 }
 | 
        
           |  |  | 978 |             }
 | 
        
           |  |  | 979 |         }
 | 
        
           |  |  | 980 |         $currentinstance = $this->get_current_instance();
 | 
        
           |  |  | 981 |         if ($currentinstance && $currentinstance->get_status() == gradingform_instance::INSTANCE_STATUS_NEEDUPDATE) {
 | 
        
           |  |  | 982 |             $html .= html_writer::tag('div', get_string('needregrademessage', 'gradingform_guide'),
 | 
        
           |  |  | 983 |                 array('class' => 'gradingform_guide-regrade', 'role' => 'alert'));
 | 
        
           |  |  | 984 |         }
 | 
        
           |  |  | 985 |         $haschanges = false;
 | 
        
           |  |  | 986 |         if ($currentinstance) {
 | 
        
           |  |  | 987 |             $curfilling = $currentinstance->get_guide_filling();
 | 
        
           |  |  | 988 |             foreach ($curfilling['criteria'] as $criterionid => $curvalues) {
 | 
        
           |  |  | 989 |                 $value['criteria'][$criterionid]['score'] = $curvalues['score'];
 | 
        
           |  |  | 990 |                 $newremark = null;
 | 
        
           |  |  | 991 |                 $newscore = null;
 | 
        
           |  |  | 992 |                 if (isset($value['criteria'][$criterionid]['remark'])) {
 | 
        
           |  |  | 993 |                     $newremark = $value['criteria'][$criterionid]['remark'];
 | 
        
           |  |  | 994 |                 }
 | 
        
           |  |  | 995 |                 if (isset($value['criteria'][$criterionid]['score'])) {
 | 
        
           |  |  | 996 |                     $newscore = $value['criteria'][$criterionid]['score'];
 | 
        
           |  |  | 997 |                 }
 | 
        
           |  |  | 998 |                 if ($newscore != $curvalues['score'] || $newremark != $curvalues['remark']) {
 | 
        
           |  |  | 999 |                     $haschanges = true;
 | 
        
           |  |  | 1000 |                 }
 | 
        
           |  |  | 1001 |             }
 | 
        
           |  |  | 1002 |         }
 | 
        
           |  |  | 1003 |         if ($this->get_data('isrestored') && $haschanges) {
 | 
        
           |  |  | 1004 |             $html .= html_writer::tag('div', get_string('restoredfromdraft', 'gradingform_guide'),
 | 
        
           |  |  | 1005 |                 array('class' => 'gradingform_guide-restored'));
 | 
        
           |  |  | 1006 |         }
 | 
        
           |  |  | 1007 |         $html .= html_writer::tag('div', $this->get_controller()->get_formatted_description(),
 | 
        
           |  |  | 1008 |             array('class' => 'gradingform_guide-description'));
 | 
        
           |  |  | 1009 |         $html .= $this->get_controller()->get_renderer($page)->display_guide($criteria, $comments, $options, $mode,
 | 
        
           |  |  | 1010 |             $gradingformelement->getName(), $value, $this->validationerrors);
 | 
        
           |  |  | 1011 |         return $html;
 | 
        
           |  |  | 1012 |     }
 | 
        
           |  |  | 1013 | }
 | 
        
           |  |  | 1014 |   | 
        
           |  |  | 1015 | /**
 | 
        
           |  |  | 1016 |  * Get the icon mapping for font-awesome.
 | 
        
           |  |  | 1017 |  *
 | 
        
           |  |  | 1018 |  * @return array
 | 
        
           |  |  | 1019 |  */
 | 
        
           |  |  | 1020 | function gradingform_guide_get_fontawesome_icon_map(): array {
 | 
        
           |  |  | 1021 |     return [
 | 
        
           | 1441 | ariadna | 1022 |         'gradingform_guide:info' => 'fa-circle-info',
 | 
        
           |  |  | 1023 |         'gradingform_guide:plus' => 'fa-circle-plus',
 | 
        
           | 1 | efrain | 1024 |     ];
 | 
        
           |  |  | 1025 | }
 |