fixed unterminated JS statements
[moodle.git] / lib / completion / data_object.php
CommitLineData
2be4d090
MD
1<?php
2
3///////////////////////////////////////////////////////////////////////////
4// //
5// NOTICE OF COPYRIGHT //
6// //
7// Moodle - Modular Object-Oriented Dynamic Learning Environment //
8// http://moodle.com //
9// //
10// Copyright (C) 1999 onwards Martin Dougiamas http://dougiamas.com //
11// //
12// This program is free software; you can redistribute it and/or modify //
13// it under the terms of the GNU General Public License as published by //
14// the Free Software Foundation; either version 2 of the License, or //
15// (at your option) any later version. //
16// //
17// This program is distributed in the hope that it will be useful, //
18// but WITHOUT ANY WARRANTY; without even the implied warranty of //
19// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
20// GNU General Public License for more details: //
21// //
22// http://www.gnu.org/copyleft/gpl.html //
23// //
24///////////////////////////////////////////////////////////////////////////
25
26/**
27 * A data abstraction object that holds methods and attributes
28 * @abstract
29 */
30abstract class data_object {
31 /**
32 * Table that the class maps to in the database
33 * @var string $table
34 */
35 public $table;
36
37 /**
38 * Array of required table fields, must start with 'id'.
39 * @var array $required_fields
40 */
41 public $required_fields = array('id');
42
43 /**
44 * Array of optional fields with default values - usually long text information that is not always needed.
45 * If you want to create an instance without optional fields use: new data_object($only_required_fields, false);
46 * @var array $optional_fields
47 */
48 public $optional_fields = array();
49
50 /**
51 * The PK.
52 * @var int $id
53 */
54 public $id;
55
56 /**
57 * Constructor. Optionally (and by default) attempts to fetch corresponding row from DB.
58 * @param array $params an array with required parameters for this data object.
59 * @param boolean $fetch Whether to fetch corresponding row from DB or not,
60 * optional fields might not be defined if false used
61 */
62 public function __construct($params=NULL, $fetch=true) {
63 if (!empty($params) and (is_array($params) or is_object($params))) {
64 if ($fetch) {
65 if ($data = $this->fetch($params)) {
66 self::set_properties($this, $data);
67 } else {
68 self::set_properties($this, $this->optional_fields);//apply defaults for optional fields
69 self::set_properties($this, $params);
70 }
71
72 } else {
73 self::set_properties($this, $params);
74 }
75
76 } else {
77 self::set_properties($this, $this->optional_fields);//apply defaults for optional fields
78 }
79 }
80
81 /**
82 * Makes sure all the optional fields are loaded.
83 * If id present (==instance exists in db) fetches data from db.
84 * Defaults are used for new instances.
85 */
86 public function load_optional_fields() {
87 global $DB;
88 foreach ($this->optional_fields as $field=>$default) {
89 if (array_key_exists($field, $this)) {
90 continue;
91 }
92 if (empty($this->id)) {
93 $this->$field = $default;
94 } else {
95 $this->$field = $DB->get_field($this->table, $field, array('id', $this->id));
96 }
97 }
98 }
99
100 /**
101 * Finds and returns a data_object instance based on params.
102 * @static abstract
103 *
104 * @param array $params associative arrays varname=>value
105 * @return object data_object instance or false if none found.
106 */
107 public static abstract function fetch($params);
108
109 /**
110 * Finds and returns all data_object instances based on params.
111 *
112 * @param array $params associative arrays varname=>value
113 * @return array array of data_object insatnces or false if none found.
114 */
115 public static function fetch_all($params) {}
116
117 /**
118 * Factory method - uses the parameters to retrieve matching instance from the DB.
119 * @static final protected
120 * @return mixed object instance or false if not found
121 */
122 protected static function fetch_helper($table, $classname, $params) {
123 if ($instances = self::fetch_all_helper($table, $classname, $params)) {
124 if (count($instances) > 1) {
125 // we should not tolerate any errors here - problems might appear later
126 print_error('morethanonerecordinfetch','debug');
127 }
128 return reset($instances);
129 } else {
130 return false;
131 }
132 }
133
134 /**
135 * Factory method - uses the parameters to retrieve all matching instances from the DB.
136 * @static final protected
137 * @return mixed array of object instances or false if not found
138 */
139 public static function fetch_all_helper($table, $classname, $params) {
140 $instance = new $classname();
141
142 $classvars = (array)$instance;
143 $params = (array)$params;
144
145 $wheresql = array();
146
147 foreach ($params as $var=>$value) {
148 if (!in_array($var, $instance->required_fields) and !array_key_exists($var, $instance->optional_fields)) {
149 continue;
150 }
151 if (is_null($value)) {
152 $wheresql[] = " $var IS NULL ";
153 } else {
154 $wheresql[] = " $var = ? ";
155 $params[] = $value;
156 }
157 }
158
159 if (empty($wheresql)) {
160 $wheresql = '';
161 } else {
162 $wheresql = implode("AND", $wheresql);
163 }
164
165 global $DB;
166 if ($datas = $DB->get_records_select($table, $wheresql, $params)) {
167
168 $result = array();
169 foreach($datas as $data) {
170 $instance = new $classname();
171 self::set_properties($instance, $data);
172 $result[$instance->id] = $instance;
173 }
174 return $result;
175
176 } else {
177
178 return false;
179 }
180 }
181
182 /**
183 * Updates this object in the Database, based on its object variables. ID must be set.
184 * @return boolean success
185 */
186 public function update() {
187 global $DB;
188
189 if (empty($this->id)) {
190 debugging('Can not update data object, no id!');
191 return false;
192 }
193
194 $data = $this->get_record_data();
195
196 $DB->update_record($this->table, $data);
197
198 $this->notify_changed(false);
199 return true;
200 }
201
202 /**
203 * Deletes this object from the database.
204 * @return boolean success
205 */
206 public function delete() {
207 global $DB;
208
209 if (empty($this->id)) {
210 debugging('Can not delete data object, no id!');
211 return false;
212 }
213
214 $data = $this->get_record_data();
215
216 if ($DB->delete_records($this->table, array('id'=>$this->id))) {
217 $this->notify_changed(true);
218 return true;
219
220 } else {
221 return false;
222 }
223 }
224
225 /**
226 * Returns object with fields and values that are defined in database
227 */
228 public function get_record_data() {
229 $data = new object();
230
231 foreach ($this as $var=>$value) {
232 if (in_array($var, $this->required_fields) or array_key_exists($var, $this->optional_fields)) {
233 if (is_object($value) or is_array($value)) {
234 debugging("Incorrect property '$var' found when inserting data object");
235 } else {
236 $data->$var = $value;
237 }
238 }
239 }
240 return $data;
241 }
242
243 /**
244 * Records this object in the Database, sets its id to the returned value, and returns that value.
245 * If successful this function also fetches the new object data from database and stores it
246 * in object properties.
247 * @return int PK ID if successful, false otherwise
248 */
249 public function insert() {
250 global $DB;
251
252 if (!empty($this->id)) {
253 debugging("Data object already exists!");
254 return false;
255 }
256
257 $data = $this->get_record_data();
258
259 $this->id = $DB->insert_record($this->table, $data);
260
261 // set all object properties from real db data
262 $this->update_from_db();
263
264 $this->notify_changed(false);
265 return $this->id;
266 }
267
268 /**
269 * Using this object's id field, fetches the matching record in the DB, and looks at
270 * each variable in turn. If the DB has different data, the db's data is used to update
271 * the object. This is different from the update() function, which acts on the DB record
272 * based on the object.
273 */
274 public function update_from_db() {
275 if (empty($this->id)) {
276 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.");
277 return false;
278 }
279 global $DB;
280 if (!$params = $DB->get_record($this->table, array('id' => $this->id))) {
281 debugging("Object with this id:{$this->id} does not exist in table:{$this->table}, can not update from db!");
282 return false;
283 }
284
285 self::set_properties($this, $params);
286
287 return true;
288 }
289
290 /**
291 * Given an associated array or object, cycles through each key/variable
292 * and assigns the value to the corresponding variable in this object.
293 * @static final
294 */
295 public static function set_properties(&$instance, $params) {
296 $params = (array) $params;
297 foreach ($params as $var => $value) {
298 if (in_array($var, $instance->required_fields) or array_key_exists($var, $instance->optional_fields)) {
299 $instance->$var = $value;
300 }
301 }
302 }
303
304 /**
305 * Called immediately after the object data has been inserted, updated, or
306 * deleted in the database. Default does nothing, can be overridden to
307 * hook in special behaviour.
308 *
309 * @param bool $deleted
310 */
311 function notify_changed($deleted) {
312 }
313}