AutorÃa | Ultima modificación | Ver Log |
<?php// This file is part of Moodle - http://moodle.org///// Moodle is free software: you can redistribute it and/or modify// it under the terms of the GNU General Public License as published by// the Free Software Foundation, either version 3 of the License, or// (at your option) any later version.//// Moodle is distributed in the hope that it will be useful,// but WITHOUT ANY WARRANTY; without even the implied warranty of// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the// GNU General Public License for more details.//// You should have received a copy of the GNU General Public License// along with Moodle. If not, see <http://www.gnu.org/licenses/>./*** Course completion critieria aggregation** @package core_completion* @category completion* @copyright 2009 Catalyst IT Ltd* @author Aaron Barnes <aaronb@catalyst.net.nz>* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later*/defined('MOODLE_INTERNAL') || die();/*** Trigger for the new data_object api.** See data_object::__constructor*/define('DATA_OBJECT_FETCH_BY_KEY', 2);/*** A data abstraction object that holds methods and attributes** @package core_completion* @category completion* @copyright 2009 Catalyst IT Ltd* @author Aaron Barnes <aaronb@catalyst.net.nz>* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later*/abstract class data_object {/* @var string Table that the class maps to in the database */public $table;/* @var array Array of required table fields, must start with 'id'. */public $required_fields = array('id');/*** Array of optional fields with default values - usually long text information that is not always needed.* If you want to create an instance without optional fields use: new data_object($only_required_fields, false);* @var array*/public $optional_fields = array();/* @var Array of unique fields, used in where clauses and constructor */public $unique_fields = array();/* @var int The primary key */public $id;/** @var int completed status. */public $completedself;/*** Constructor. Optionally (and by default) attempts to fetch corresponding row from DB.** If $fetch is not false, there are a few different things that can happen:* - true:* load corresponding row from the database, using $params as the WHERE clause** - DATA_OBJECT_FETCH_BY_KEY:* load corresponding row from the database, using only the $id in the WHERE clause (if set),* otherwise using the columns listed in $this->unique_fields.** - array():* load corresponding row from the database, using the columns listed in this array* in the WHERE clause** @param array $params required parameters and their values for this data object* @param mixed $fetch if false, do not attempt to fetch from the database, otherwise see notes*/public function __construct($params = null, $fetch = true) {if (is_object($params)) {throw new coding_exception('data_object params should be in the form of an array, not an object');}// If no params given, apply defaults for optional fieldsif (empty($params) || !is_array($params)) {self::set_properties($this, $this->optional_fields);return;}// If fetch is false, do not load from databaseif ($fetch === false) {self::set_properties($this, $params);return;}// Compose where clause only from fields in unique_fieldsif ($fetch === DATA_OBJECT_FETCH_BY_KEY && !empty($this->unique_fields)) {if (empty($params['id'])) {$where = array_intersect_key($params, array_flip($this->unique_fields));}else {$where = array('id' => $params['id']);}// Compose where clause from given field names} else if (is_array($fetch) && !empty($fetch)) {$where = array_intersect_key($params, array_flip($fetch));// Use entire params array for where clause} else {$where = $params;}// Attempt to load from databaseif ($data = $this->fetch($where)) {// Apply data from database, then data sent to constructorself::set_properties($this, $data);self::set_properties($this, $params);} else {// Apply defaults for optional fields, then data from constructorself::set_properties($this, $this->optional_fields);self::set_properties($this, $params);}}/*** Makes sure all the optional fields are loaded.** If id present (==instance exists in db) fetches data from db.* Defaults are used for new instances.*/public function load_optional_fields() {global $DB;foreach ($this->optional_fields as $field=>$default) {if (property_exists($this, $field)) {continue;}if (empty($this->id)) {$this->$field = $default;} else {$this->$field = $DB->get_field($this->table, $field, array('id', $this->id));}}}/*** Finds and returns a data_object instance based on params.** This function MUST be overridden by all deriving classes.** @param array $params associative arrays varname => value* @throws coding_exception This function MUST be overridden* @return data_object instance of data_object or false if none found.*/public static function fetch($params) {throw new coding_exception('fetch() method needs to be overridden in each subclass of data_object');}/*** Finds and returns all data_object instances based on params.** This function MUST be overridden by all deriving classes.** @param array $params associative arrays varname => value* @throws coding_exception This function MUST be overridden* @return array array of data_object instances or false if none found.*/public static function fetch_all($params) {throw new coding_exception('fetch_all() method needs to be overridden in each subclass of data_object');}/*** Factory method - uses the parameters to retrieve matching instance from the DB.** @final* @param string $table The table name to fetch from* @param string $classname The class that you want the result instantiated as* @param array $params Any params required to select the desired row* @return object Instance of $classname or false.*/protected static function fetch_helper($table, $classname, $params) {if ($instances = self::fetch_all_helper($table, $classname, $params)) {if (count($instances) > 1) {// we should not tolerate any errors here - problems might appear laterthrow new \moodle_exception('morethanonerecordinfetch', 'debug');}return reset($instances);} else {return false;}}/*** Factory method - uses the parameters to retrieve all matching instances from the DB.** @final* @param string $table The table name to fetch from* @param string $classname The class that you want the result instantiated as* @param array $params Any params required to select the desired row* @return mixed array of object instances or false if not found*/public static function fetch_all_helper($table, $classname, $params) {$instance = new $classname();$classvars = (array)$instance;$params = (array)$params;$wheresql = array();$dbparams = array();foreach ($params as $var=>$value) {if (!in_array($var, $instance->required_fields) and !array_key_exists($var, $instance->optional_fields)) {continue;}if (is_null($value)) {$wheresql[] = " $var IS NULL ";} else {$wheresql[] = " $var = ? ";$dbparams[] = $value;}}if (empty($wheresql)) {$wheresql = '';} else {$wheresql = implode("AND", $wheresql);}global $DB;if ($datas = $DB->get_records_select($table, $wheresql, $dbparams)) {$result = array();foreach($datas as $data) {$instance = new $classname();self::set_properties($instance, $data);$result[$instance->id] = $instance;}return $result;} else {return false;}}/*** Updates this object in the Database, based on its object variables. ID must be set.** @return bool success*/public function update() {global $DB;if (empty($this->id)) {debugging('Can not update data object, no id!');return false;}$data = $this->get_record_data();$DB->update_record($this->table, $data);$this->notify_changed(false);return true;}/*** Deletes this object from the database.** @return bool success*/public function delete() {global $DB;if (empty($this->id)) {debugging('Can not delete data object, no id!');return false;}$data = $this->get_record_data();if ($DB->delete_records($this->table, array('id'=>$this->id))) {$this->notify_changed(true);return true;} else {return false;}}/*** Returns object with fields and values that are defined in database** @return stdClass*/public function get_record_data() {$data = new stdClass();foreach ($this as $var=>$value) {if (in_array($var, $this->required_fields) or array_key_exists($var, $this->optional_fields)) {if (is_object($value) or is_array($value)) {debugging("Incorrect property '$var' found when inserting data object");} else {$data->$var = $value;}}}return $data;}/*** Records this object in the Database, sets its id to the returned value, and returns that value.* If successful this function also fetches the new object data from database and stores it* in object properties.** @return int PK ID if successful, false otherwise*/public function insert() {global $DB;if (!empty($this->id)) {debugging("Data object already exists!");return false;}$data = $this->get_record_data();$this->id = $DB->insert_record($this->table, $data);// set all object properties from real db data$this->update_from_db();$this->notify_changed(false);return $this->id;}/*** Using this object's id field, fetches the matching record in the DB, and looks at* each variable in turn. If the DB has different data, the db's data is used to update* the object. This is different from the update() function, which acts on the DB record* based on the object.** @return bool True for success, false otherwise.*/public function update_from_db() {if (empty($this->id)) {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.");return false;}global $DB;if (!$params = $DB->get_record($this->table, array('id' => $this->id))) {debugging("Object with this id:{$this->id} does not exist in table:{$this->table}, can not update from db!");return false;}self::set_properties($this, $params);return true;}/*** Given an associated array or object, cycles through each key/variable* and assigns the value to the corresponding variable in this object.** @final* @param data_object $instance* @param array $params*/public static function set_properties(&$instance, $params) {$params = (array) $params;foreach ($params as $var => $value) {if (in_array($var, $instance->required_fields) or array_key_exists($var, $instance->optional_fields)) {$instance->$var = $value;}}}/*** Called immediately after the object data has been inserted, updated, or* deleted in the database. Default does nothing, can be overridden to* hook in special behaviour.** @param bool $deleted Set this to true if it has been deleted.*/public function notify_changed($deleted) {}}