Differences Between: [Versions 310 and 403] [Versions 311 and 403] [Versions 39 and 403] [Versions 400 and 403] [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 * Course completion critieria aggregation 19 * 20 * @package core_completion 21 * @category completion 22 * @copyright 2009 Catalyst IT Ltd 23 * @author Aaron Barnes <aaronb@catalyst.net.nz> 24 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 25 */ 26 27 defined('MOODLE_INTERNAL') || die(); 28 29 30 /** 31 * Trigger for the new data_object api. 32 * 33 * See data_object::__constructor 34 */ 35 define('DATA_OBJECT_FETCH_BY_KEY', 2); 36 37 /** 38 * A data abstraction object that holds methods and attributes 39 * 40 * @package core_completion 41 * @category completion 42 * @copyright 2009 Catalyst IT Ltd 43 * @author Aaron Barnes <aaronb@catalyst.net.nz> 44 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 45 */ 46 abstract class data_object { 47 48 /* @var string Table that the class maps to in the database */ 49 public $table; 50 51 /* @var array Array of required table fields, must start with 'id'. */ 52 public $required_fields = array('id'); 53 54 /** 55 * Array of optional fields with default values - usually long text information that is not always needed. 56 * If you want to create an instance without optional fields use: new data_object($only_required_fields, false); 57 * @var array 58 */ 59 public $optional_fields = array(); 60 61 /* @var Array of unique fields, used in where clauses and constructor */ 62 public $unique_fields = array(); 63 64 /* @var int The primary key */ 65 public $id; 66 67 /** @var int completed status. */ 68 public $completedself; 69 70 71 /** 72 * Constructor. Optionally (and by default) attempts to fetch corresponding row from DB. 73 * 74 * If $fetch is not false, there are a few different things that can happen: 75 * - true: 76 * load corresponding row from the database, using $params as the WHERE clause 77 * 78 * - DATA_OBJECT_FETCH_BY_KEY: 79 * load corresponding row from the database, using only the $id in the WHERE clause (if set), 80 * otherwise using the columns listed in $this->unique_fields. 81 * 82 * - array(): 83 * load corresponding row from the database, using the columns listed in this array 84 * in the WHERE clause 85 * 86 * @param array $params required parameters and their values for this data object 87 * @param mixed $fetch if false, do not attempt to fetch from the database, otherwise see notes 88 */ 89 public function __construct($params = null, $fetch = true) { 90 91 if (is_object($params)) { 92 throw new coding_exception('data_object params should be in the form of an array, not an object'); 93 } 94 95 // If no params given, apply defaults for optional fields 96 if (empty($params) || !is_array($params)) { 97 self::set_properties($this, $this->optional_fields); 98 return; 99 } 100 101 // If fetch is false, do not load from database 102 if ($fetch === false) { 103 self::set_properties($this, $params); 104 return; 105 } 106 107 // Compose where clause only from fields in unique_fields 108 if ($fetch === DATA_OBJECT_FETCH_BY_KEY && !empty($this->unique_fields)) { 109 if (empty($params['id'])) { 110 $where = array_intersect_key($params, array_flip($this->unique_fields)); 111 } 112 else { 113 $where = array('id' => $params['id']); 114 } 115 // Compose where clause from given field names 116 } else if (is_array($fetch) && !empty($fetch)) { 117 $where = array_intersect_key($params, array_flip($fetch)); 118 // Use entire params array for where clause 119 } else { 120 $where = $params; 121 } 122 123 // Attempt to load from database 124 if ($data = $this->fetch($where)) { 125 // Apply data from database, then data sent to constructor 126 self::set_properties($this, $data); 127 self::set_properties($this, $params); 128 } else { 129 // Apply defaults for optional fields, then data from constructor 130 self::set_properties($this, $this->optional_fields); 131 self::set_properties($this, $params); 132 } 133 } 134 135 /** 136 * Makes sure all the optional fields are loaded. 137 * 138 * If id present (==instance exists in db) fetches data from db. 139 * Defaults are used for new instances. 140 */ 141 public function load_optional_fields() { 142 global $DB; 143 foreach ($this->optional_fields as $field=>$default) { 144 if (property_exists($this, $field)) { 145 continue; 146 } 147 if (empty($this->id)) { 148 $this->$field = $default; 149 } else { 150 $this->$field = $DB->get_field($this->table, $field, array('id', $this->id)); 151 } 152 } 153 } 154 155 /** 156 * Finds and returns a data_object instance based on params. 157 * 158 * This function MUST be overridden by all deriving classes. 159 * 160 * @param array $params associative arrays varname => value 161 * @throws coding_exception This function MUST be overridden 162 * @return data_object instance of data_object or false if none found. 163 */ 164 public static function fetch($params) { 165 throw new coding_exception('fetch() method needs to be overridden in each subclass of data_object'); 166 } 167 168 /** 169 * Finds and returns all data_object instances based on params. 170 * 171 * This function MUST be overridden by all deriving classes. 172 * 173 * @param array $params associative arrays varname => value 174 * @throws coding_exception This function MUST be overridden 175 * @return array array of data_object instances or false if none found. 176 */ 177 public static function fetch_all($params) { 178 throw new coding_exception('fetch_all() method needs to be overridden in each subclass of data_object'); 179 } 180 181 /** 182 * Factory method - uses the parameters to retrieve matching instance from the DB. 183 * 184 * @final 185 * @param string $table The table name to fetch from 186 * @param string $classname The class that you want the result instantiated as 187 * @param array $params Any params required to select the desired row 188 * @return object Instance of $classname or false. 189 */ 190 protected static function fetch_helper($table, $classname, $params) { 191 if ($instances = self::fetch_all_helper($table, $classname, $params)) { 192 if (count($instances) > 1) { 193 // we should not tolerate any errors here - problems might appear later 194 throw new \moodle_exception('morethanonerecordinfetch', 'debug'); 195 } 196 return reset($instances); 197 } else { 198 return false; 199 } 200 } 201 202 /** 203 * Factory method - uses the parameters to retrieve all matching instances from the DB. 204 * 205 * @final 206 * @param string $table The table name to fetch from 207 * @param string $classname The class that you want the result instantiated as 208 * @param array $params Any params required to select the desired row 209 * @return mixed array of object instances or false if not found 210 */ 211 public static function fetch_all_helper($table, $classname, $params) { 212 $instance = new $classname(); 213 214 $classvars = (array)$instance; 215 $params = (array)$params; 216 217 $wheresql = array(); 218 219 $dbparams = array(); 220 foreach ($params as $var=>$value) { 221 if (!in_array($var, $instance->required_fields) and !array_key_exists($var, $instance->optional_fields)) { 222 continue; 223 } 224 if (is_null($value)) { 225 $wheresql[] = " $var IS NULL "; 226 } else { 227 $wheresql[] = " $var = ? "; 228 $dbparams[] = $value; 229 } 230 } 231 232 if (empty($wheresql)) { 233 $wheresql = ''; 234 } else { 235 $wheresql = implode("AND", $wheresql); 236 } 237 238 global $DB; 239 if ($datas = $DB->get_records_select($table, $wheresql, $dbparams)) { 240 241 $result = array(); 242 foreach($datas as $data) { 243 $instance = new $classname(); 244 self::set_properties($instance, $data); 245 $result[$instance->id] = $instance; 246 } 247 return $result; 248 249 } else { 250 251 return false; 252 } 253 } 254 255 /** 256 * Updates this object in the Database, based on its object variables. ID must be set. 257 * 258 * @return bool success 259 */ 260 public function update() { 261 global $DB; 262 263 if (empty($this->id)) { 264 debugging('Can not update data object, no id!'); 265 return false; 266 } 267 268 $data = $this->get_record_data(); 269 270 $DB->update_record($this->table, $data); 271 272 $this->notify_changed(false); 273 return true; 274 } 275 276 /** 277 * Deletes this object from the database. 278 * 279 * @return bool success 280 */ 281 public function delete() { 282 global $DB; 283 284 if (empty($this->id)) { 285 debugging('Can not delete data object, no id!'); 286 return false; 287 } 288 289 $data = $this->get_record_data(); 290 291 if ($DB->delete_records($this->table, array('id'=>$this->id))) { 292 $this->notify_changed(true); 293 return true; 294 295 } else { 296 return false; 297 } 298 } 299 300 /** 301 * Returns object with fields and values that are defined in database 302 * 303 * @return stdClass 304 */ 305 public function get_record_data() { 306 $data = new stdClass(); 307 308 foreach ($this as $var=>$value) { 309 if (in_array($var, $this->required_fields) or array_key_exists($var, $this->optional_fields)) { 310 if (is_object($value) or is_array($value)) { 311 debugging("Incorrect property '$var' found when inserting data object"); 312 } else { 313 $data->$var = $value; 314 } 315 } 316 } 317 return $data; 318 } 319 320 /** 321 * Records this object in the Database, sets its id to the returned value, and returns that value. 322 * If successful this function also fetches the new object data from database and stores it 323 * in object properties. 324 * 325 * @return int PK ID if successful, false otherwise 326 */ 327 public function insert() { 328 global $DB; 329 330 if (!empty($this->id)) { 331 debugging("Data object already exists!"); 332 return false; 333 } 334 335 $data = $this->get_record_data(); 336 337 $this->id = $DB->insert_record($this->table, $data); 338 339 // set all object properties from real db data 340 $this->update_from_db(); 341 342 $this->notify_changed(false); 343 return $this->id; 344 } 345 346 /** 347 * Using this object's id field, fetches the matching record in the DB, and looks at 348 * each variable in turn. If the DB has different data, the db's data is used to update 349 * the object. This is different from the update() function, which acts on the DB record 350 * based on the object. 351 * 352 * @return bool True for success, false otherwise. 353 */ 354 public function update_from_db() { 355 if (empty($this->id)) { 356 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."); 357 return false; 358 } 359 global $DB; 360 if (!$params = $DB->get_record($this->table, array('id' => $this->id))) { 361 debugging("Object with this id:{$this->id} does not exist in table:{$this->table}, can not update from db!"); 362 return false; 363 } 364 365 self::set_properties($this, $params); 366 367 return true; 368 } 369 370 /** 371 * Given an associated array or object, cycles through each key/variable 372 * and assigns the value to the corresponding variable in this object. 373 * 374 * @final 375 * @param data_object $instance 376 * @param array $params 377 */ 378 public static function set_properties(&$instance, $params) { 379 $params = (array) $params; 380 foreach ($params as $var => $value) { 381 if (in_array($var, $instance->required_fields) or array_key_exists($var, $instance->optional_fields)) { 382 $instance->$var = $value; 383 } 384 } 385 } 386 387 /** 388 * Called immediately after the object data has been inserted, updated, or 389 * deleted in the database. Default does nothing, can be overridden to 390 * hook in special behaviour. 391 * 392 * @param bool $deleted Set this to true if it has been deleted. 393 */ 394 public function notify_changed($deleted) { 395 } 396 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body