[ Index ]

PHP Cross Reference of moodle-2.8

title

Body

[close]

/completion/ -> data_object.php (source)

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


Generated: Fri Nov 28 20:29:05 2014 Cross-referenced by PHPXref 0.7.1