lib.php 12.5 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<?php
/**
 * This program is part of Mahara
 *
 *  This program 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 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program 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 this program; if not, write to the Free Software
 *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
 *
 * @package    mahara
Penny Leach's avatar
Penny Leach committed
20
 * @subpackage artefact
Penny Leach's avatar
Penny Leach committed
21
 * @author     Penny Leach <penny@catalyst.net.nz>
22
23
24
25
26
27
 * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL
 * @copyright  (C) 2006,2007 Catalyst IT Ltd http://catalyst.net.nz
 *
 */

defined('INTERNAL') || die();
28
define('ARTEFACT_FORMAT_LISTITEM', 1);
29
30
31
32
33
34
35
36
37
38

/** 
 * Exception - artefact not found 
 */
class ArtefactNotFoundException extends Exception {}

/**
 * Base artefact plugin class
 * @abstract
 */
39
abstract class PluginArtefact extends Plugin {
40
41
42
43

    /** 
     * This function returns a list of classnames 
     * of artefact types this plugin provides.
Penny Leach's avatar
Penny Leach committed
44
     * @abstract
45
46
47
48
     * @return array
     */
    public static abstract function get_artefact_types();

49
50
    /**
     * This function returns the name of the plugin.
Penny Leach's avatar
Penny Leach committed
51
     * @abstract
52
53
54
55
56
     * @return string
     */
    public static abstract function get_plugin_name();


57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
    /**
     * This function returns an array of menu items
     * to be displayed
     * Each item should be a StdClass object containing -
     * - name language pack key
     * - url relative to wwwroot
     * @return array
     */
    public static function menu_items() {
        return array();
    }

    /**
     * This function returns an array of crons it wants to have run
     * Each item should be a StdtClass object containing - 
     * - name (will have artefact.$pluginname added for uniqueness)
     * - script to hit relative to the documentroot
     * NOTE THAT each plugin that implements this should ship with a 
     * .htaccess that denies access to all cron scripts 
     */
    public static function get_cron_options() { 
        return array();
    }

    /** 
     * This function returns an array of events to subscribe to
     * by unique name. 
     * If an event the plugin is trying to subscribe to is unknown by the
     * core, an exception will be thrown.
     * @return array
     */
    public static function get_event_subscriptions() {
        return array();
    }
}

/** 
 * Base artefact type class
 * @abstract
 */
abstract class ArtefactType {
    
99
100
    protected $dirty;
    protected $parentdirty;
101
    protected $id;
102
103
    protected $artefacttype;
    protected $owner;
104
    protected $container;
105
    protected $parent;
106
107
    protected $ctime;
    protected $mtime;
108
    protected $atime;
109
110
111
112
113
    protected $locked;
    protected $title;
    protected $description;
    protected $note;

Penny Leach's avatar
Penny Leach committed
114
115
116
117
118
119
120
    protected $viewsinstances;
    protected $viewsmetadata;
    protected $childreninstances;
    protected $childrenmetadata;
    protected $parentinstance;
    protected $parentmetadata;

121
122
123
124
125
126
127
128
    /** 
     * Constructer. 
     * If an id is supplied, will query the database
     * to build up the basic information about the object.
     * If an id is not supplied, we just create an empty
     * artefact, ready to be filled up
     * @param int $id artefact.id
     */
Penny Leach's avatar
Penny Leach committed
129
    public function __construct($id=0, $data=null) {
130
        if (!empty($id)) {
Penny Leach's avatar
Penny Leach committed
131
132
133
134
            if (empty($data)) {
                if (!$data = get_record('artefact','id',$id)) {
                    throw new ArtefactNotFoundException("Artefact with id $id not found");
                }
135
136
137
138
139
            }
        }
        else {
            $this->ctime = time();
        }
140
141
142
143
144
145
146
147
148
        if (empty($data)) {
            $data = array();
        }
        foreach ((array)$data as $field => $value) {
            if (property_exists($this, $field)) {
                $this->{$field} = $value;
            }
        }

149
150
        $this->atime = time();
        $this->artefacttype = $this->get_artefact_type();
151
152
153
154
155
156
157
158
159
160
    }

    public function get_views_instances() {
        // @todo
    }
    
    public function get_views_metadata() {
        // @todo
    }

Penny Leach's avatar
Penny Leach committed
161
162
163
164
165
166
167
168
169
    /** 
     * This function returns the instances 
     * of all children of this artefact
     * If you just want the basic info, 
     * use {@link get_children_metadata} instead.
     * 
     * @return array of instances.
     */

170
    public function get_children_instances() {
Penny Leach's avatar
Penny Leach committed
171
172
173
174
175
        if (!isset($this->childreninstances)) {
            $this->childreninstances = false;
            if ($children = $this->get_children_metadata()) {
                $this->childreninstances = array();
                foreach ($children as $child) {
176
                    $classname = generate_artefact_class_name($child->artefacttype);
Penny Leach's avatar
Penny Leach committed
177
178
179
180
181
182
                    $instance = new $classname($child->id, $child);
                    $this->childreninstances[] = $instance;
                }
            }
        }
        return $this->childreninstances;
183
184
    }

185
186
187
188
189
190
191
192
193
    /**
     * This function returns the db rows 
     * from the artefact table that have this 
     * artefact as the parent.
     * If you want instances, use {@link get_children_instances}
     * but bear in mind this will have a performance impact.
     * 
     * @return array
     */
194
    public function get_children_metadata() {
Penny Leach's avatar
Penny Leach committed
195
196
197
198
        if (!isset($this->childrenmetadata)) {
            $this->childrenmetadata = get_records('artefact', 'parentid', $this->id);
        }
        return $this->childrenmetadata;
199
    }
Penny Leach's avatar
Penny Leach committed
200
201
202
203
204
205
206
207
208

    /**
     * This function returns the instance relating to the parent
     * of this object, or false if there isn't one.
     * If you just want basic information about it,
     * use {@link get_parent_metadata} instead.
     *
     * @return ArtefactType
     */
209
    public function get_parent_instance() {
Penny Leach's avatar
Penny Leach committed
210
211
212
        if (!isset($this->parentinstance)) {
            $this->parentinstance = false;
            if ($parent = $this->get_parent_metadata()) {
213
214
                $classname = generate_artefact_class_name($parent->artefacttype);
                // @todo this won't work.
Penny Leach's avatar
Penny Leach committed
215
216
217
218
                $this->parentinstance = new $classname($parent->id, $parent);
            }
        }
        return $this->parentinstance;
219
    }
220
221
222
223
224
225
226
227

    /** 
     * This function returns the db row 
     * (if there is one) of the parent
     * artefact for this instance.
     * If you want the instance, use 
     * {@link get_parent_instance} instead.
     * 
228
     * @return object - db row
229
     */
230
    public function get_parent_metadata() {
231
        return get_record('artefact','id',$this->parentid);
232
233
234
    }

    public function get($field) {
235
        if (!property_exists($this, $field)) {
236
            throw new InvalidArgumentException("Field $field wasn't found in class " . get_class($this));
237
238
239
240
241
        }
        return $this->{$field};
    }

    public function set($field, $value) {
242
        if (property_exists($this, $field)) {
243
244
245
246
            if ($this->{$field} != $value) {
                // only set it to dirty if it's changed
                $this->dirty = true;
            }
247
            $this->{$field} = $value;
248
249
250
            if ($field == 'parent') {
                $this->parentdirty = true;
            }
251
            $this->mtime = time();
252
253
            return true;
        }
254
        throw new InvalidArgumentException("Field $field wasn't found in class " . get_class($this));
255
256
    }
    
257
258
259
260
    /**
     * Artefact destructor. Calls commit and marks the
     * artefact cache as dirty if necessary.
     */
261
    public function __destruct() {
262
263
264
265
        if (!empty($this->dirty)) {
            $this->commit();
        }
        if (!empty($this->parentdirty)) {
266
            if (!empty($this->parent) && !record_exists('artefact_parent_cache', 'artefact', $this->id)) {
267
268
269
270
271
272
                $apc = new StdClass;
                $apc->artefact = $this->id;
                $apc->parent = $this->parent;
                $apc->dirty  = 1; // set this so the cronjob will pick it up and go set all the other parents.
                insert_record('artefact_parent_cache', $apc);
            }
273
274
275
            set_field_select('artefact_parent_cache', 'dirty', 1,
                             'artefact = ? OR parent = ?', array($this->id, $this->id));
        }
276
277
278
279
280
281
    }
    
    public function is_container() {
        return false;
    }

282
283
284
285
286
287
288
    /** 
     * As commit is abstract, subclasses
     * can use this as a helper to update
     * the contents of the artefact table
     */
    
    protected function commit_basic() {
289
290
291
        if (empty($this->dirty)) {
            return;
        }
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
        $fordb = new StdClass;
        foreach (get_object_vars($this) as $k => $v) {
            $fordb->{$k} = $v;
            if (in_array($k, array('mtime', 'ctime', 'atime')) && !empty($v)) {
                $fordb->{$k} = db_format_timestamp($v);
            }
        }
        if (empty($this->id)) {
            $this->id = insert_record('artefact', $fordb, 'id', true);
        }
        else {
            update_record('artefact', $fordb, 'id');
        }
        $this->dirty = false;
    }


Penny Leach's avatar
Penny Leach committed
309
310
    /**
     * Saves any changes to the database
311
     * for basic commits, use {@link commit_basic}
Penny Leach's avatar
Penny Leach committed
312
313
     * @abstract
     */
314
315
    public abstract function commit();
    
316
317
318
319
320
321
322
323
324
325
326
327
328

    /** 
     * As delete is abstract, subclasses
     * can use this to clear out the artefact
     * table and set the parentdirty flag
     */

    protected function delete_basic() {
        delete_records('artefact', 'id', $this->id);
        $this->dirty = false;
        $this->parentdirty = true;
    }

Penny Leach's avatar
Penny Leach committed
329
330
    /**
     * Deletes current instance
331
332
     * you MUST set $this->parentdirty to true
     * when delete is called.
333
     * for basic delete, use {@link delete_basic}
Penny Leach's avatar
Penny Leach committed
334
335
     * @abstract
     */
336
337
    public abstract function delete();

Penny Leach's avatar
Penny Leach committed
338
339
340
341
342
    /**
     * render instance to given format
     * @param int $format format type (constant)
     * @param array $options options for format
     */
343
344
    public abstract function render($format, $options);

Penny Leach's avatar
Penny Leach committed
345
346
347
348
349
350
351
    /**
     * returns path to icon
     * can be called statically but not defined so
     * so that can be either from instance or static.
     * @abstract 
     * @return string path to icon (relative to docroot)
     */
352
353
354
355
356
357
358
359
360
361
362
363
364
    public abstract function get_icon();
    

    // ******************** STATIC FUNCTIONS ******************** //

    public static function get_instances_by_userid($userid, $order, $offset, $limit) {
        // @todo
    }

    public static function get_metadata_by_userid($userid, $order, $offset, $limit) {
        // @todo
    }

Penny Leach's avatar
Penny Leach committed
365
366
367
368
    /**
     * returns array of formats can render to (constants)
     * @abstract
     */
369
    public static abstract function get_render_list();
370

Penny Leach's avatar
Penny Leach committed
371
372
373
374
    /**
     * returns boolean for can render to given format
     * @abstract
     */
375
    public static abstract function can_render_to($format);
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390


    // ******************** HELPER FUNCTIONS ******************** //

    protected function get_artefact_type() {
        $classname = get_class($this);
        
        $type = strtolower(substr($classname, strlen('ArtefactType')));

        if (!record_exists('artefact_installed_type', 'name', $type)) {
            throw new InvalidArgumentException("Classname $classname not a valid artefact type");
        }

        return $type;
    }
391
392
393
394
395
396
397
398
399
400
401
402

    public static function has_config() {
        return false;
    }

    public static function get_config_options() {
        return array();
    }

    public static function collapse_config() {
        return false;
    }
403
404
}

405
// helper functions for artefacts in general
406

407
408
409
410
411
412
function artefact_check_plugin_sanity($pluginname) {
    $classname = generate_class_name('artefact', $pluginname);
    safe_require('artefact', $pluginname);
    $types = call_static_method($classname, 'get_artefact_types');
    foreach ($types as $type) {
        $typeclassname = generate_artefact_class_name($type);
413
        if (get_config('installed')) {
414
415
416
417
418
            if ($taken = get_record_select('artefact_installed_type', 'name = ? AND plugin != ?', 
                                           array($type, $pluginname))) {
                throw new InstallationException("type $type is already taken by another plugin (" . $taken->plugin . ")");
            }
        }
419
        if (!class_exists($typeclassname)) {
420
            throw new InstallationException("class $typeclassname for type $type in plugin $pluginname was missing");
421
422
423
        }
    }
}
424
425
426

        
?>