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 * Evidence persistent file. 19 * 20 * @package core_competency 21 * @copyright 2015 Frédéric Massart - FMCorz.net 22 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 23 */ 24 25 namespace core_competency; 26 defined('MOODLE_INTERNAL') || die(); 27 28 use coding_exception; 29 use context; 30 use context_user; 31 use lang_string; 32 use moodle_exception; 33 use stdClass; 34 35 /** 36 * Evidence persistent class. 37 * 38 * @package core_competency 39 * @copyright 2015 Frédéric Massart - FMCorz.net 40 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 41 */ 42 class evidence extends persistent { 43 44 const TABLE = 'competency_evidence'; 45 46 /** Action logging. */ 47 const ACTION_LOG = 0; 48 /** Action rating a competency when no rating is set. */ 49 const ACTION_COMPLETE = 2; 50 /** Action rating a competency. */ 51 const ACTION_OVERRIDE = 3; 52 53 /** 54 * Return the definition of the properties of this model. 55 * 56 * @return array 57 */ 58 protected static function define_properties() { 59 return array( 60 'usercompetencyid' => array( 61 'type' => PARAM_INT 62 ), 63 'contextid' => array( 64 'type' => PARAM_INT 65 ), 66 'action' => array( 67 'type' => PARAM_INT, 68 'choices' => array(self::ACTION_LOG, self::ACTION_COMPLETE, self::ACTION_OVERRIDE) 69 ), 70 'actionuserid' => array( 71 'type' => PARAM_INT, 72 'default' => null, 73 'null' => NULL_ALLOWED 74 ), 75 'descidentifier' => array( 76 'type' => PARAM_STRINGID 77 ), 78 'desccomponent' => array( 79 'type' => PARAM_COMPONENT 80 ), 81 'desca' => array( 82 'type' => PARAM_RAW, 83 'default' => null, 84 'null' => NULL_ALLOWED 85 ), 86 'url' => array( 87 'type' => PARAM_URL, 88 'default' => null, 89 'null' => NULL_ALLOWED 90 ), 91 'grade' => array( 92 'type' => PARAM_INT, 93 'default' => null, 94 'null' => NULL_ALLOWED 95 ), 96 'note' => array( 97 'type' => PARAM_NOTAGS, 98 'default' => null, 99 'null' => NULL_ALLOWED 100 ) 101 ); 102 } 103 104 /** 105 * Return the competency linked to this. 106 * 107 * @return competency 108 */ 109 public function get_competency() { 110 return user_competency::get_competency_by_usercompetencyid($this->get('usercompetencyid')); 111 } 112 113 /** 114 * Return the evidence's context. 115 * 116 * @return context 117 */ 118 public function get_context() { 119 return context::instance_by_id($this->get('contextid')); 120 } 121 122 /** 123 * Convenience method to get the description $a. 124 * 125 * @return mixed 126 */ 127 protected function get_desca() { 128 $value = $this->raw_get('desca'); 129 if ($value !== null) { 130 $value = json_decode($value); 131 } 132 return $value; 133 } 134 135 /** 136 * Convenience method to get the description. 137 * 138 * @return lang_string 139 */ 140 public function get_description() { 141 return new lang_string($this->get('descidentifier'), $this->get('desccomponent'), $this->get_desca()); 142 } 143 144 /** 145 * Convenience method to set the description $a. 146 * 147 * @param mixed $value 148 * @return mixed 149 */ 150 protected function set_desca($value) { 151 if ($value !== null) { 152 if (!is_scalar($value) && !is_array($value) && !($value instanceof stdClass)) { 153 throw new coding_exception('$a format not supported.'); 154 } 155 $value = json_encode($value); 156 } 157 $this->raw_set('desca', $value); 158 } 159 160 /** 161 * Convenience method handling moodle_urls. 162 * 163 * @param null|string|moodle_url $url The URL. 164 */ 165 protected function set_url($url) { 166 if ($url instanceof \moodle_url) { 167 $url = $url->out(false); 168 } 169 $this->raw_set('url', $url); 170 } 171 172 /** 173 * Validate the action user ID. 174 * 175 * @param int $value A user ID. 176 * @return true|lang_string 177 */ 178 protected function validate_actionuserid($value) { 179 if ($value !== null && !\core_user::is_real_user($value)) { 180 return new lang_string('invaliddata', 'error'); 181 } 182 return true; 183 } 184 185 /** 186 * Validate the context ID. 187 * 188 * @param int $value 189 * @return true|lang_string 190 */ 191 protected function validate_contextid($value) { 192 try { 193 context::instance_by_id($value); 194 } catch (moodle_exception $e) { 195 // That does not look good... 196 return new lang_string('invaliddata', 'error'); 197 } 198 return true; 199 } 200 201 /** 202 * Validate the description $a. 203 * 204 * @param string $value 205 * @return true|lang_string 206 */ 207 protected function validate_desca($value) { 208 if ($value === null) { 209 return true; 210 } 211 212 $desc = json_decode($value); 213 if ($desc === null && json_last_error() !== JSON_ERROR_NONE) { 214 return new lang_string('invaliddata', 'error'); 215 } 216 217 return true; 218 } 219 220 /** 221 * Validate the description identifier. 222 * 223 * Only validate string existence during create. If the string is removed later on we should 224 * not prevent this model from being updated. Alternatively we could check if the string has 225 * changed before performing the check but this overhead is not required for now. 226 * An evidence should usually never be updated anyway. 227 * 228 * @param string $value 229 * @return true|lang_string 230 */ 231 protected function validate_descidentifier($value) { 232 if (!$this->get('id') && !get_string_manager()->string_exists($value, $this->get('desccomponent'))) { 233 return new lang_string('invalidevidencedesc', 'core_competency'); 234 } 235 236 return true; 237 } 238 239 /** 240 * Validate the grade. 241 * 242 * For performance reason we do not validate that the grade is a valid item of the 243 * scale associated with the competency or framework. 244 * 245 * @param int $value The value. 246 * @return true|lang_string 247 */ 248 protected function validate_grade($value) { 249 if ($value !== null && $value <= 0) { 250 return new lang_string('invalidgrade', 'core_competency'); 251 } 252 253 $action = $this->get('action'); 254 if ($value === null && $action == self::ACTION_COMPLETE) { 255 return new lang_string('invalidgrade', 'core_competency'); 256 257 } else if ($value !== null && $action == self::ACTION_LOG) { 258 return new lang_string('invalidgrade', 'core_competency'); 259 } 260 261 if ($value !== null) { 262 // TODO MDL-52243 Use a core method to validate the grade_scale item. 263 // Check if grade exist in the scale item values. 264 $competency = $this->get_competency(); 265 if (!array_key_exists($value - 1, $competency->get_scale()->scale_items)) { 266 return new lang_string('invalidgrade', 'core_competency'); 267 } 268 } 269 270 return true; 271 } 272 273 /** 274 * Validate the user competency. 275 * 276 * @param int $value 277 * @return true|lang_string 278 */ 279 protected function validate_usercompetencyid($value) { 280 if (!user_competency::record_exists($value)) { 281 return new lang_string('invaliddata', 'error'); 282 } 283 return true; 284 } 285 286 /** 287 * Whether the current user can delete an evidence in the context of a user. 288 * 289 * @param int $userid The user ID the evidence belongs to. 290 * @return bool 291 */ 292 public static function can_delete_user($userid) { 293 return has_capability('moodle/competency:evidencedelete', context_user::instance($userid)); 294 } 295 296 /** 297 * Load a list of records in a context for a user competency. 298 * 299 * @param int $usercompetencyid The id of the user competency. 300 * @param context $context Context to filter the evidence list. 301 * @param string $sort The field from the evidence table to sort on. 302 * @param string $order The sort direction 303 * @param int $skip Limitstart. 304 * @param int $limit Number of rows to return. 305 * 306 * @return \core_competency\persistent[] 307 */ 308 public static function get_records_for_usercompetency($usercompetencyid, 309 \context $context, 310 $sort = '', 311 $order = 'ASC', 312 $skip = 0, 313 $limit = 0) { 314 global $DB; 315 316 $params = array( 317 'usercompid' => $usercompetencyid, 318 'path' => $context->path . '/%', 319 'contextid' => $context->id 320 ); 321 322 if (!empty($sort)) { 323 $sort = ' ORDER BY e.' . $sort . ' ' . $order . ', e.id ASC'; 324 } else { 325 $sort = ' ORDER BY e.id ASC'; 326 } 327 328 $sql = 'SELECT e.* 329 FROM {' . static::TABLE . '} e 330 JOIN {context} c ON c.id = e.contextid 331 WHERE (c.path LIKE :path OR c.id = :contextid) 332 AND e.usercompetencyid = :usercompid 333 ' . $sort; 334 $records = $DB->get_records_sql($sql, $params, $skip, $limit); 335 $instances = array(); 336 337 foreach ($records as $record) { 338 $newrecord = new static(0, $record); 339 array_push($instances, $newrecord); 340 } 341 return $instances; 342 } 343 344 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body