Proyectos de Subversion Moodle

Rev

| Ultima modificación | Ver Log |

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