Differences Between: [Versions 311 and 400] [Versions 311 and 401] [Versions 311 and 402] [Versions 311 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 print_error('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 * @return bool success 242 */ 243 public function update($source=null) { 244 global $USER, $CFG, $DB; 245 246 if (empty($this->id)) { 247 debugging('Can not update grade object, no id!'); 248 return false; 249 } 250 251 $data = $this->get_record_data(); 252 253 $DB->update_record($this->table, $data); 254 255 $historyid = null; 256 if (empty($CFG->disablegradehistory)) { 257 unset($data->timecreated); 258 $data->action = GRADE_HISTORY_UPDATE; 259 $data->oldid = $this->id; 260 $data->source = $source; 261 $data->timemodified = time(); 262 $data->loggeduser = $USER->id; 263 $historyid = $DB->insert_record($this->table.'_history', $data); 264 } 265 266 $this->notify_changed(false); 267 268 $this->update_feedback_files($historyid); 269 270 return true; 271 } 272 273 /** 274 * Deletes this object from the database. 275 * 276 * @param string $source From where was the object deleted (mod/forum, manual, etc.) 277 * @return bool success 278 */ 279 public function delete($source=null) { 280 global $USER, $CFG, $DB; 281 282 if (empty($this->id)) { 283 debugging('Can not delete grade object, no id!'); 284 return false; 285 } 286 287 $data = $this->get_record_data(); 288 289 if ($DB->delete_records($this->table, array('id'=>$this->id))) { 290 if (empty($CFG->disablegradehistory)) { 291 unset($data->id); 292 unset($data->timecreated); 293 $data->action = GRADE_HISTORY_DELETE; 294 $data->oldid = $this->id; 295 $data->source = $source; 296 $data->timemodified = time(); 297 $data->loggeduser = $USER->id; 298 $DB->insert_record($this->table.'_history', $data); 299 } 300 301 $this->notify_changed(true); 302 303 $this->delete_feedback_files(); 304 305 return true; 306 } else { 307 return false; 308 } 309 } 310 311 /** 312 * Returns object with fields and values that are defined in database 313 * 314 * @return stdClass 315 */ 316 public function get_record_data() { 317 $data = new stdClass(); 318 319 foreach ($this as $var=>$value) { 320 if (in_array($var, $this->required_fields) or array_key_exists($var, $this->optional_fields)) { 321 if (is_object($value) or is_array($value)) { 322 debugging("Incorrect property '$var' found when inserting grade object"); 323 } else { 324 $data->$var = $value; 325 } 326 } 327 } 328 return $data; 329 } 330 331 /** 332 * Records this object in the Database, sets its id to the returned value, and returns that value. 333 * If successful this function also fetches the new object data from database and stores it 334 * in object properties. 335 * 336 * @param string $source From where was the object inserted (mod/forum, manual, etc.) 337 * @return int The new grade object ID if successful, false otherwise 338 */ 339 public function insert($source=null) { 340 global $USER, $CFG, $DB; 341 342 if (!empty($this->id)) { 343 debugging("Grade object already exists!"); 344 return false; 345 } 346 347 $data = $this->get_record_data(); 348 349 $this->id = $DB->insert_record($this->table, $data); 350 351 // set all object properties from real db data 352 $this->update_from_db(); 353 354 $data = $this->get_record_data(); 355 356 $historyid = null; 357 if (empty($CFG->disablegradehistory)) { 358 unset($data->timecreated); 359 $data->action = GRADE_HISTORY_INSERT; 360 $data->oldid = $this->id; 361 $data->source = $source; 362 $data->timemodified = time(); 363 $data->loggeduser = $USER->id; 364 $historyid = $DB->insert_record($this->table.'_history', $data); 365 } 366 367 $this->notify_changed(false); 368 369 $this->add_feedback_files($historyid); 370 371 return $this->id; 372 } 373 374 /** 375 * Using this object's id field, fetches the matching record in the DB, and looks at 376 * each variable in turn. If the DB has different data, the db's data is used to update 377 * the object. This is different from the update() function, which acts on the DB record 378 * based on the object. 379 * 380 * @return bool True if successful 381 */ 382 public function update_from_db() { 383 if (empty($this->id)) { 384 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."); 385 return false; 386 } 387 global $DB; 388 if (!$params = $DB->get_record($this->table, array('id' => $this->id))) { 389 debugging("Object with this id:{$this->id} does not exist in table:{$this->table}, can not update from db!"); 390 return false; 391 } 392 393 grade_object::set_properties($this, $params); 394 395 return true; 396 } 397 398 /** 399 * Given an associated array or object, cycles through each key/variable 400 * and assigns the value to the corresponding variable in this object. 401 * 402 * @param stdClass $instance The object to set the properties on 403 * @param array $params An array of properties to set like $propertyname => $propertyvalue 404 * @return array|stdClass Either an associative array or an object containing property name, property value pairs 405 */ 406 public static function set_properties(&$instance, $params) { 407 $params = (array) $params; 408 foreach ($params as $var => $value) { 409 if (in_array($var, $instance->required_fields) or array_key_exists($var, $instance->optional_fields)) { 410 $instance->$var = $value; 411 } 412 } 413 } 414 415 /** 416 * Called immediately after the object data has been inserted, updated, or 417 * deleted in the database. Default does nothing, can be overridden to 418 * hook in special behaviour. 419 * 420 * @param bool $deleted 421 */ 422 protected function notify_changed($deleted) { 423 } 424 425 /** 426 * Handles adding feedback files in the gradebook. 427 * 428 * @param int|null $historyid 429 */ 430 protected function add_feedback_files(int $historyid = null) { 431 } 432 433 /** 434 * Handles updating feedback files in the gradebook. 435 * 436 * @param int|null $historyid 437 */ 438 protected function update_feedback_files(int $historyid = null) { 439 } 440 441 /** 442 * Handles deleting feedback files in the gradebook. 443 */ 444 protected function delete_feedback_files() { 445 } 446 447 /** 448 * Returns the current hidden state of this grade_item 449 * 450 * This depends on the grade object hidden setting and the current time if hidden is set to a "hidden until" timestamp 451 * 452 * @return bool Current hidden state 453 */ 454 function is_hidden() { 455 return ($this->hidden == 1 or ($this->hidden != 0 and $this->hidden > time())); 456 } 457 458 /** 459 * Check grade object hidden status 460 * 461 * @return bool True if a "hidden until" timestamp is set, false if grade object is set to always visible or always hidden. 462 */ 463 function is_hiddenuntil() { 464 return $this->hidden > 1; 465 } 466 467 /** 468 * Check a grade item hidden status. 469 * 470 * @return int 0 means visible, 1 hidden always, a timestamp means "hidden until" 471 */ 472 function get_hidden() { 473 return $this->hidden; 474 } 475 476 /** 477 * Set a grade object hidden status 478 * 479 * @param int $hidden 0 means visiable, 1 means hidden always, a timestamp means "hidden until" 480 * @param bool $cascade Ignored 481 */ 482 function set_hidden($hidden, $cascade=false) { 483 $this->hidden = $hidden; 484 $this->update(); 485 } 486 487 /** 488 * Returns whether the grade object can control the visibility of the grades. 489 * 490 * @return bool 491 */ 492 public function can_control_visibility() { 493 return true; 494 } 495 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body