See Release Notes
Long Term Support Release
Differences Between: [Versions 310 and 401] [Versions 311 and 401] [Versions 39 and 401] [Versions 400 and 401] [Versions 401 and 402] [Versions 401 and 403]
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 * Definition of a grade object class for grade item, grade category etc to inherit from 19 * 20 * @package core_grades 21 * @category grade 22 * @copyright 2006 Nicolas Connault 23 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 24 */ 25 26 defined('MOODLE_INTERNAL') || die(); 27 28 /** 29 * An abstract object that holds methods and attributes common to all grade_* objects defined here. 30 * 31 * @package core_grades 32 * @category grade 33 * @copyright 2006 Nicolas Connault 34 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 35 */ 36 abstract class grade_object { 37 /** 38 * The database table this grade object is stored in 39 * @var string $table 40 */ 41 public $table; 42 43 /** 44 * Array of required table fields, must start with 'id'. 45 * @var array $required_fields 46 */ 47 public $required_fields = array('id', 'timecreated', 'timemodified', 'hidden'); 48 49 /** 50 * Array of optional fields with default values - usually long text information that is not always needed. 51 * If you want to create an instance without optional fields use: new grade_object($only_required_fields, false); 52 * @var array $optional_fields 53 */ 54 public $optional_fields = array(); 55 56 /** 57 * The PK. 58 * @var int $id 59 */ 60 public $id; 61 62 /** 63 * The first time this grade_object was created. 64 * @var int $timecreated 65 */ 66 public $timecreated; 67 68 /** 69 * The last time this grade_object was modified. 70 * @var int $timemodified 71 */ 72 public $timemodified; 73 74 /** 75 * 0 if visible, 1 always hidden or date not visible until 76 * @var int $hidden 77 */ 78 var $hidden = 0; 79 80 /** 81 * Constructor. Optionally (and by default) attempts to fetch corresponding row from the database 82 * 83 * @param array $params An array with required parameters for this grade object. 84 * @param bool $fetch Whether to fetch corresponding row from the database or not, 85 * optional fields might not be defined if false used 86 */ 87 public function __construct($params=NULL, $fetch=true) { 88 if (!empty($params) and (is_array($params) or is_object($params))) { 89 if ($fetch) { 90 if ($data = $this->fetch($params)) { 91 grade_object::set_properties($this, $data); 92 } else { 93 grade_object::set_properties($this, $this->optional_fields);//apply defaults for optional fields 94 grade_object::set_properties($this, $params); 95 } 96 97 } else { 98 grade_object::set_properties($this, $params); 99 } 100 101 } else { 102 grade_object::set_properties($this, $this->optional_fields);//apply defaults for optional fields 103 } 104 } 105 106 /** 107 * Makes sure all the optional fields are loaded. 108 * 109 * If id present, meaning the instance exists in the database, then data will be fetched from the database. 110 * Defaults are used for new instances. 111 */ 112 public function load_optional_fields() { 113 global $DB; 114 foreach ($this->optional_fields as $field=>$default) { 115 if (property_exists($this, $field)) { 116 continue; 117 } 118 if (empty($this->id)) { 119 $this->$field = $default; 120 } else { 121 $this->$field = $DB->get_field($this->table, $field, array('id', $this->id)); 122 } 123 } 124 } 125 126 /** 127 * Finds and returns a grade_object instance based on params. 128 * 129 * @static 130 * @abstract 131 * @param array $params associative arrays varname=>value 132 * @return object grade_object instance or false if none found. 133 */ 134 public static function fetch($params) { 135 throw new coding_exception('fetch() method needs to be overridden in each subclass of grade_object'); 136 } 137 138 /** 139 * Finds and returns all grade_object instances based on $params. 140 * 141 * @static 142 * @abstract 143 * @throws coding_exception Throws a coding exception if fetch_all() has not been overriden by the grade object subclass 144 * @param array $params Associative arrays varname=>value 145 * @return array|bool Array of grade_object instances or false if none found. 146 */ 147 public static function fetch_all($params) { 148 throw new coding_exception('fetch_all() method needs to be overridden in each subclass of grade_object'); 149 } 150 151 /** 152 * Factory method which uses the parameters to retrieve matching instances from the database 153 * 154 * @param string $table The table to retrieve from 155 * @param string $classname The name of the class to instantiate 156 * @param array $params An array of conditions like $fieldname => $fieldvalue 157 * @return mixed An object instance or false if not found 158 */ 159 protected static function fetch_helper($table, $classname, $params) { 160 if ($instances = grade_object::fetch_all_helper($table, $classname, $params)) { 161 if (count($instances) > 1) { 162 // we should not tolerate any errors here - problems might appear later 163 throw new \moodle_exception('morethanonerecordinfetch', 'debug'); 164 } 165 return reset($instances); 166 } else { 167 return false; 168 } 169 } 170 171 /** 172 * Factory method which uses the parameters to retrieve all matching instances from the database 173 * 174 * @param string $table The table to retrieve from 175 * @param string $classname The name of the class to instantiate 176 * @param array $params An array of conditions like $fieldname => $fieldvalue 177 * @return array|bool Array of object instances or false if not found 178 */ 179 public static function fetch_all_helper($table, $classname, $params) { 180 global $DB; // Need to introspect DB here. 181 182 $instance = new $classname(); 183 184 $classvars = (array)$instance; 185 $params = (array)$params; 186 187 $wheresql = array(); 188 $newparams = array(); 189 190 $columns = $DB->get_columns($table); // Cached, no worries. 191 192 foreach ($params as $var=>$value) { 193 if (!in_array($var, $instance->required_fields) and !array_key_exists($var, $instance->optional_fields)) { 194 continue; 195 } 196 if (!array_key_exists($var, $columns)) { 197 continue; 198 } 199 if (is_null($value)) { 200 $wheresql[] = " $var IS NULL "; 201 } else { 202 if ($columns[$var]->meta_type === 'X') { 203 // We have a text/clob column, use the cross-db method for its comparison. 204 $wheresql[] = ' ' . $DB->sql_compare_text($var) . ' = ' . $DB->sql_compare_text('?') . ' '; 205 } else { 206 // Other columns (varchar, integers...). 207 $wheresql[] = " $var = ? "; 208 } 209 $newparams[] = $value; 210 } 211 } 212 213 if (empty($wheresql)) { 214 $wheresql = ''; 215 } else { 216 $wheresql = implode("AND", $wheresql); 217 } 218 219 global $DB; 220 $rs = $DB->get_recordset_select($table, $wheresql, $newparams); 221 //returning false rather than empty array if nothing found 222 if (!$rs->valid()) { 223 $rs->close(); 224 return false; 225 } 226 227 $result = array(); 228 foreach($rs as $data) { 229 $instance = new $classname(); 230 grade_object::set_properties($instance, $data); 231 $result[$instance->id] = $instance; 232 } 233 $rs->close(); 234 return $result; 235 } 236 237 /** 238 * Updates this object in the Database, based on its object variables. ID must be set. 239 * 240 * @param string $source from where was the object updated (mod/forum, manual, etc.) 241 * @param bool $isbulkupdate If bulk grade update is happening. 242 * @return bool success 243 */ 244 public function update($source = null, $isbulkupdate = false) { 245 global $USER, $CFG, $DB; 246 247 if (empty($this->id)) { 248 debugging('Can not update grade object, no id!'); 249 return false; 250 } 251 252 $data = $this->get_record_data(); 253 254 $DB->update_record($this->table, $data); 255 256 $historyid = null; 257 if (empty($CFG->disablegradehistory)) { 258 unset($data->timecreated); 259 $data->action = GRADE_HISTORY_UPDATE; 260 $data->oldid = $this->id; 261 $data->source = $source; 262 $data->timemodified = time(); 263 $data->loggeduser = $USER->id; 264 $historyid = $DB->insert_record($this->table.'_history', $data); 265 } 266 267 $this->notify_changed(false, $isbulkupdate); 268 269 $this->update_feedback_files($historyid); 270 271 return true; 272 } 273 274 /** 275 * Deletes this object from the database. 276 * 277 * @param string $source From where was the object deleted (mod/forum, manual, etc.) 278 * @return bool success 279 */ 280 public function delete($source=null) { 281 global $USER, $CFG, $DB; 282 283 if (empty($this->id)) { 284 debugging('Can not delete grade object, no id!'); 285 return false; 286 } 287 288 $data = $this->get_record_data(); 289 290 if ($DB->delete_records($this->table, array('id'=>$this->id))) { 291 if (empty($CFG->disablegradehistory)) { 292 unset($data->id); 293 unset($data->timecreated); 294 $data->action = GRADE_HISTORY_DELETE; 295 $data->oldid = $this->id; 296 $data->source = $source; 297 $data->timemodified = time(); 298 $data->loggeduser = $USER->id; 299 $DB->insert_record($this->table.'_history', $data); 300 } 301 302 $this->notify_changed(true); 303 304 $this->delete_feedback_files(); 305 306 return true; 307 } else { 308 return false; 309 } 310 } 311 312 /** 313 * Returns object with fields and values that are defined in database 314 * 315 * @return stdClass 316 */ 317 public function get_record_data() { 318 $data = new stdClass(); 319 320 foreach ($this as $var=>$value) { 321 if (in_array($var, $this->required_fields) or array_key_exists($var, $this->optional_fields)) { 322 if (is_object($value) or is_array($value)) { 323 debugging("Incorrect property '$var' found when inserting grade object"); 324 } else { 325 $data->$var = $value; 326 } 327 } 328 } 329 return $data; 330 } 331 332 /** 333 * Records this object in the Database, sets its id to the returned value, and returns that value. 334 * If successful this function also fetches the new object data from database and stores it 335 * in object properties. 336 * 337 * @param string $source From where was the object inserted (mod/forum, manual, etc.) 338 * @param string $isbulkupdate If bulk grade update is happening. 339 * @return int The new grade object ID if successful, false otherwise 340 */ 341 public function insert($source = null, $isbulkupdate = false) { 342 global $USER, $CFG, $DB; 343 344 if (!empty($this->id)) { 345 debugging("Grade object already exists!"); 346 return false; 347 } 348 349 $data = $this->get_record_data(); 350 351 $this->id = $DB->insert_record($this->table, $data); 352 353 // set all object properties from real db data 354 $this->update_from_db(); 355 356 $data = $this->get_record_data(); 357 358 $historyid = null; 359 if (empty($CFG->disablegradehistory)) { 360 unset($data->timecreated); 361 $data->action = GRADE_HISTORY_INSERT; 362 $data->oldid = $this->id; 363 $data->source = $source; 364 $data->timemodified = time(); 365 $data->loggeduser = $USER->id; 366 $historyid = $DB->insert_record($this->table.'_history', $data); 367 } 368 369 $this->notify_changed(false, $isbulkupdate); 370 371 $this->add_feedback_files($historyid); 372 373 return $this->id; 374 } 375 376 /** 377 * Using this object's id field, fetches the matching record in the DB, and looks at 378 * each variable in turn. If the DB has different data, the db's data is used to update 379 * the object. This is different from the update() function, which acts on the DB record 380 * based on the object. 381 * 382 * @return bool True if successful 383 */ 384 public function update_from_db() { 385 if (empty($this->id)) { 386 debugging("The object could not be used in its state to retrieve a matching record from the DB, because its id field is not set."); 387 return false; 388 } 389 global $DB; 390 if (!$params = $DB->get_record($this->table, array('id' => $this->id))) { 391 debugging("Object with this id:{$this->id} does not exist in table:{$this->table}, can not update from db!"); 392 return false; 393 } 394 395 grade_object::set_properties($this, $params); 396 397 return true; 398 } 399 400 /** 401 * Given an associated array or object, cycles through each key/variable 402 * and assigns the value to the corresponding variable in this object. 403 * 404 * @param stdClass $instance The object to set the properties on 405 * @param array $params An array of properties to set like $propertyname => $propertyvalue 406 * @return array|stdClass Either an associative array or an object containing property name, property value pairs 407 */ 408 public static function set_properties(&$instance, $params) { 409 $params = (array) $params; 410 foreach ($params as $var => $value) { 411 if (in_array($var, $instance->required_fields) or array_key_exists($var, $instance->optional_fields)) { 412 $instance->$var = $value; 413 } 414 } 415 } 416 417 /** 418 * Called immediately after the object data has been inserted, updated, or 419 * deleted in the database. Default does nothing, can be overridden to 420 * hook in special behaviour. 421 * 422 * @param bool $deleted 423 */ 424 protected function notify_changed($deleted) { 425 } 426 427 /** 428 * Handles adding feedback files in the gradebook. 429 * 430 * @param int|null $historyid 431 */ 432 protected function add_feedback_files(int $historyid = null) { 433 } 434 435 /** 436 * Handles updating feedback files in the gradebook. 437 * 438 * @param int|null $historyid 439 */ 440 protected function update_feedback_files(int $historyid = null) { 441 } 442 443 /** 444 * Handles deleting feedback files in the gradebook. 445 */ 446 protected function delete_feedback_files() { 447 } 448 449 /** 450 * Returns the current hidden state of this grade_item 451 * 452 * This depends on the grade object hidden setting and the current time if hidden is set to a "hidden until" timestamp 453 * 454 * @return bool Current hidden state 455 */ 456 function is_hidden() { 457 return ($this->hidden == 1 or ($this->hidden != 0 and $this->hidden > time())); 458 } 459 460 /** 461 * Check grade object hidden status 462 * 463 * @return bool True if a "hidden until" timestamp is set, false if grade object is set to always visible or always hidden. 464 */ 465 function is_hiddenuntil() { 466 return $this->hidden > 1; 467 } 468 469 /** 470 * Check a grade item hidden status. 471 * 472 * @return int 0 means visible, 1 hidden always, a timestamp means "hidden until" 473 */ 474 function get_hidden() { 475 return $this->hidden; 476 } 477 478 /** 479 * Set a grade object hidden status 480 * 481 * @param int $hidden 0 means visiable, 1 means hidden always, a timestamp means "hidden until" 482 * @param bool $cascade Ignored 483 */ 484 function set_hidden($hidden, $cascade=false) { 485 $this->hidden = $hidden; 486 $this->update(); 487 } 488 489 /** 490 * Returns whether the grade object can control the visibility of the grades. 491 * 492 * @return bool 493 */ 494 public function can_control_visibility() { 495 return true; 496 } 497 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body