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
 * This file contains the base classes for portfolio plugins to inherit from:
19
 *
20
 * portfolio_plugin_pull_base and portfolio_plugin_push_base
21
 * which both in turn inherit from portfolio_plugin_base.
22
 *
23
 * @package    core_portfolio
24
 * @copyright  2008 Penny Leach <penny@catalyst.net.nz>,
25
 *             Martin Dougiamas <http://dougiamas.com>
26
 * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
27
 */
28
 
29
defined('MOODLE_INTERNAL') || die();
30
 
31
/**
32
 * The base class for portfolio plugins.
33
 *
34
 * All plugins must subclass this
35
 * either via portfolio_plugin_pull_base or portfolio_plugin_push_base
36
 * @see portfolio_plugin_pull_base
37
 * @see portfolio_plugin_push_base
38
 *
39
 * @package core_portfolio
40
 * @category portfolio
41
 * @copyright 2008 Penny Leach <penny@catalyst.net.nz>
42
 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
43
 */
44
abstract class portfolio_plugin_base {
45
 
46
    /** @var bool whether this object needs writing out to the database */
47
    protected $dirty;
48
 
49
    /** @var integer id of instance */
50
    protected $id;
51
 
52
    /** @var string name of instance */
53
    protected $name;
54
 
55
    /** @var string plugin this instance belongs to */
56
    protected $plugin;
57
 
58
    /** @var bool whether this instance is visible or not */
59
    protected $visible;
60
 
61
    /** @var stdClass admin configured config use {@see set_config} and {@see get_config} to access */
62
    protected $config;
63
 
64
    /** @var array user config cache. keyed on userid and then on config field => value use {@link get_user_config} and {@link set_user_config} to access. */
65
    protected $userconfig;
66
 
67
    /** @var array export config during export use {@link get_export_config} and {@link set export_config} to access. */
68
    protected $exportconfig;
69
 
70
    /** @var stdClass user currently exporting data */
71
    protected $user;
72
 
73
    /** @var stdClass a reference to the exporter object */
74
    protected $exporter;
75
 
76
    /**
77
     * Array of formats this portfolio supports
78
     * the intersection of what this function returns
79
     * and what the caller supports will be used.
80
     * Use the constants PORTFOLIO_FORMAT_*
81
     *
82
     * @return array list of formats
83
     */
84
    public function supported_formats() {
85
        return array(PORTFOLIO_FORMAT_FILE, PORTFOLIO_FORMAT_RICH);
86
    }
87
 
88
    /**
89
     * Override this if you are supporting the 'file' type (or a subformat)
90
     * but have restrictions on mimetypes
91
     *
92
     * @param string $mimetype file type or subformat
93
     * @return bool
94
     */
95
    public static function file_mime_check($mimetype) {
96
        return true;
97
    }
98
 
99
 
100
    /**
101
     * How long does this reasonably expect to take..
102
     * Should we offer the user the option to wait..
103
     * This is deliberately nonstatic so it can take filesize into account
104
     *
105
     * @param string $callertime - what the caller thinks
106
     *                             the portfolio plugin instance
107
     *                             is given the final say
108
     *                             because it might be (for example) download.
109
     */
110
    abstract public function expected_time($callertime);
111
 
112
    /**
113
     * Is this plugin push or pull.
114
     * If push, cleanup will be called directly after send_package
115
     * If not, cleanup will be called after portfolio/file.php is requested
116
     */
117
    abstract public function is_push();
118
 
119
    /**
120
     * Returns the user-friendly name for this plugin.
121
     * Usually just get_string('pluginname', 'portfolio_something')
122
     */
123
    public static function get_name() {
124
        throw new coding_exception('get_name() method needs to be overridden in each subclass of portfolio_plugin_base');
125
    }
126
 
127
    /**
128
     * Check sanity of plugin.
129
     * If this function returns something non empty, ALL instances of your plugin
130
     * will be set to invisble and not be able to be set back until it's fixed
131
     *
132
     * @return string|int|bool - string = error string KEY (must be inside portfolio_$yourplugin) or 0/false if you're ok
133
     */
134
    public static function plugin_sanity_check() {
135
        return 0;
136
    }
137
 
138
    /**
139
     * Check sanity of instances.
140
     * If this function returns something non empty, the instance will be
141
     * set to invislbe and not be able to be set back until it's fixed.
142
     *
143
     * @return int|string|bool - string = error string KEY (must be inside portfolio_$yourplugin) or 0/false if you're ok
144
     */
145
    public function instance_sanity_check() {
146
        return 0;
147
    }
148
 
149
    /**
150
     * Does this plugin need any configuration by the administrator?
151
     * If you override this to return true,
152
     * you <b>must</b> implement admin_config_form.
153
     * @see admin_config_form
154
     *
155
     * @return bool
156
     */
157
    public static function has_admin_config() {
158
        return false;
159
    }
160
 
161
    /**
162
     * Can this plugin be configured by the user in their profile?
163
     * If you override this to return true,
164
     * you <b>must</b> implement user_config_form
165
     * @see user_config_form
166
     *
167
     * @return bool
168
     */
169
    public function has_user_config() {
170
        return false;
171
    }
172
 
173
    /**
174
     * Does this plugin need configuration during export time?
175
     * If you override this to return true,
176
     * you <b>must</b> implement export_config_form.
177
     * @see export_config_form
178
     *
179
     * @return bool
180
     */
181
    public function has_export_config() {
182
        return false;
183
    }
184
 
185
    /**
186
     * Just like the moodle form validation function.
187
     * This is passed in the data array from the form
188
     * and if a non empty array is returned, form processing will stop.
189
     *
190
     * @param array $data data from form.
191
     */
192
    public function export_config_validation(array $data) {}
193
 
194
    /**
195
     * Just like the moodle form validation function.
196
     * This is passed in the data array from the form
197
     * and if a non empty array is returned, form processing will stop.
198
     *
199
     * @param array $data data from form.
200
     */
201
    public function user_config_validation(array $data) {}
202
 
203
    /**
204
     * Sets the export time config from the moodle form.
205
     * You can also use this to set export config that
206
     * isn't actually controlled by the user.
207
     * Eg: things that your subclasses want to keep in state
208
     * across the export.
209
     * Keys must be in get_allowed_export_config
210
     * This is deliberately not final (see googledocs plugin)
211
     * @see get_allowed_export_config
212
     *
213
     * @param array $config named array of config items to set.
214
     */
215
    public function set_export_config($config) {
216
        $allowed = array_merge(
217
            array('wait', 'hidewait', 'format', 'hideformat'),
218
            $this->get_allowed_export_config()
219
        );
220
        foreach ($config as $key => $value) {
221
            if (!in_array($key, $allowed)) {
222
                $a = (object)array('property' => $key, 'class' => get_class($this));
223
                throw new portfolio_export_exception($this->get('exporter'), 'invalidexportproperty', 'portfolio', null, $a);
224
            }
225
            $this->exportconfig[$key] = $value;
226
        }
227
    }
228
 
229
    /**
230
     * Gets an export time config value.
231
     * Subclasses should not override this.
232
     *
233
     * @param string $key field to fetch
234
     * @return null|string config value
235
     */
236
    final public function get_export_config($key) {
237
        $allowed = array_merge(
238
            array('hidewait', 'wait', 'format', 'hideformat'),
239
            $this->get_allowed_export_config()
240
        );
241
        if (!in_array($key, $allowed)) {
242
            $a = (object)array('property' => $key, 'class' => get_class($this));
243
            throw new portfolio_export_exception($this->get('exporter'), 'invalidexportproperty', 'portfolio', null, $a);
244
        }
245
        if (!array_key_exists($key, $this->exportconfig)) {
246
            return null;
247
        }
248
        return $this->exportconfig[$key];
249
    }
250
 
251
    /**
252
     * After the user submits their config,
253
     * they're given a confirm screen
254
     * summarising what they've chosen.
255
     * This function should return a table of nice strings => values
256
     * of what they've chosen
257
     * to be displayed in a table.
258
     *
259
     * @return bool
260
     */
261
    public function get_export_summary() {
262
        return false;
263
    }
264
 
265
    /**
266
     * Called after the caller has finished having control
267
     * of its prepare_package function.
268
     * This function should read all the files from the portfolio
269
     * working file area and zip them and send them or whatever it wants.
270
     * get_tempfiles to get the list of files.
271
     * @see get_tempfiles
272
     *
273
     */
274
    abstract public function prepare_package();
275
 
276
    /**
277
     * This is the function that is responsible for sending
278
     * the package to the remote system,
279
     * or whatever request is necessary to initiate the transfer.
280
     *
281
     * @return bool success
282
     */
283
    abstract public function send_package();
284
 
285
 
286
    /**
287
     * Once everything is done and the user
288
     * has the finish page displayed to them.
289
     * The base class takes care of printing them
290
     * "return to where you are" or "continue to portfolio" links.
291
     * This function allows for exta finish options from the plugin
292
     *
293
     * @return bool
294
     */
295
    public function get_extra_finish_options() {
296
        return false;
297
    }
298
 
299
    /**
300
     * The url for the user to continue to their portfolio
301
     * during the lifecycle of the request
302
     */
303
    abstract public function get_interactive_continue_url();
304
 
305
    /**
306
     * The url to save in the log as the continue url.
307
     * This is passed through resolve_static_continue_url()
308
     * at display time to the user.
309
     *
310
     * @return string
311
     */
312
    public function get_static_continue_url() {
313
        return $this->get_interactive_continue_url();
314
    }
315
 
316
    /**
317
     * Override this function if you need to add something on to the url
318
     * for post-export continues (eg from the log page).
319
     * Mahara does this, for example, to start a jump session.
320
     *
321
     * @param string $url static continue url
322
     * @return string
323
     */
324
    public function resolve_static_continue_url($url) {
325
        return $url;
326
    }
327
 
328
    /**
329
     * mform to display to the user in their profile
330
     * if your plugin can't be configured by the user,
331
     * @see has_user_config.
332
     * Don't bother overriding this function
333
     *
334
     * @param moodleform $mform passed by reference, add elements to it
335
     */
336
    public function user_config_form(&$mform) {}
337
 
338
    /**
339
     * mform to display to the admin configuring the plugin.
340
     * If your plugin can't be configured by the admin,
341
     * @see has_admin_config
342
     * Don't bother overriding this function.
343
     * This function can be called statically or non statically,
344
     * depending on whether it's creating a new instance (statically),
345
     * or editing an existing one (non statically)
346
     *
347
     * @param moodleform $mform passed by reference, add elements to it.
348
     */
349
    public static function admin_config_form(&$mform) {}
350
 
351
    /**
352
     * Just like the moodle form validation function,
353
     * this is passed in the data array from the form
354
     * and if a non empty array is returned, form processing will stop.
355
     *
356
     * @param array $data data from form.
357
     */
358
    public static function admin_config_validation($data) {}
359
 
360
    /**
361
     * mform to display to the user exporting data using this plugin.
362
     * If your plugin doesn't need user input at this time,
363
     * @see has_export_config.
364
     * Don't bother overrideing this function
365
     *
366
     * @param moodleform $mform passed by reference, add elements to it.
367
     */
368
    public function export_config_form(&$mform) {}
369
 
370
    /**
371
     * Override this if your plugin doesn't allow multiple instances
372
     *
373
     * @return bool
374
     */
375
    public static function allows_multiple_instances() {
376
        return true;
377
    }
378
 
379
    /**
380
     * If at any point the caller wants to steal control,
381
     * it can, by returning something that isn't false
382
     * in this function
383
     * The controller will redirect to whatever url
384
     * this function returns.
385
     * Afterwards, you can redirect back to portfolio/add.php?postcontrol=1
386
     * and post_control is called before the rest of the processing
387
     * for the stage is done,
388
     * @see post_control
389
     *
390
     * @param int $stage to steal control *before* (see constants PARAM_STAGE_*}
391
     * @return bool
392
     */
393
    public function steal_control($stage) {
394
        return false;
395
    }
396
 
397
    /**
398
     * After a plugin has elected to steal control,
399
     * and control returns to portfolio/add.php|postcontrol=1,
400
     * this function is called, and passed the stage that was stolen control from
401
     * and the request (get and post but not cookie) parameters.
402
     * This is useful for external systems that need to redirect the user back
403
     * with some extra data in the url (like auth tokens etc)
404
     * for an example implementation, see googledocs portfolio plugin.
405
     *
406
     * @param int $stage the stage before control was stolen
407
     * @param array $params a merge of $_GET and $_POST
408
     */
409
    public function post_control($stage, $params) { }
410
 
411
    /**
412
     * This function creates a new instance of a plugin
413
     * saves it in the database, saves the config
414
     * and returns it.
415
     * You shouldn't need to override it
416
     * unless you're doing something really funky
417
     *
418
     * @param string $plugin portfolio plugin to create
419
     * @param string $name name of new instance
420
     * @param array $config what the admin config form returned
421
     * @return object subclass of portfolio_plugin_base
422
     */
423
    public static function create_instance($plugin, $name, $config) {
424
        global $DB, $CFG;
425
        $new = (object)array(
426
            'plugin' => $plugin,
427
            'name'   => $name,
428
        );
429
        if (!portfolio_static_function($plugin, 'allows_multiple_instances')) {
430
            // check we don't have one already
431
            if ($DB->record_exists('portfolio_instance', array('plugin' => $plugin))) {
432
                throw new portfolio_exception('multipleinstancesdisallowed', 'portfolio', '', $plugin);
433
            }
434
        }
435
        $newid = $DB->insert_record('portfolio_instance', $new);
436
        require_once($CFG->dirroot . '/portfolio/' . $plugin . '/lib.php');
437
        $classname = 'portfolio_plugin_'  . $plugin;
438
        $obj = new $classname($newid);
439
        $obj->set_config($config);
440
        $obj->save();
441
        return $obj;
442
    }
443
 
444
    /**
445
     * Construct a plugin instance.
446
     * Subclasses should not need to override this unless they're doing something special
447
     * and should call parent::__construct afterwards.
448
     *
449
     * @param int $instanceid id of plugin instance to construct
450
     * @param mixed $record stdclass object or named array - use this if you already have the record to avoid another query
451
     * @return portfolio_plugin_base
452
     */
453
    public function __construct($instanceid, $record=null) {
454
        global $DB;
455
        if (!$record) {
456
            if (!$record = $DB->get_record('portfolio_instance', array('id' => $instanceid))) {
457
                throw new portfolio_exception('invalidinstance', 'portfolio');
458
            }
459
        }
460
        foreach ((array)$record as $key =>$value) {
461
            if (property_exists($this, $key)) {
462
                $this->{$key} = $value;
463
            }
464
        }
465
        $this->config = new StdClass;
466
        $this->userconfig = array();
467
        $this->exportconfig = array();
468
        foreach ($DB->get_records('portfolio_instance_config', array('instance' => $instanceid)) as $config) {
469
            $this->config->{$config->name} = $config->value;
470
        }
471
        $this->init();
472
        return $this;
473
    }
474
 
475
    /**
476
     * Called after __construct - allows plugins to perform initialisation tasks
477
     * without having to override the constructor.
478
     */
479
    protected function init() { }
480
 
481
    /**
482
     * A list of fields that can be configured per instance.
483
     * This is used for the save handlers of the config form
484
     * and as checks in set_config and get_config.
485
     *
486
     * @return array array of strings (config item names)
487
     */
488
    public static function get_allowed_config() {
489
        return array();
490
    }
491
 
492
    /**
493
     * A list of fields that can be configured by the user.
494
     * This is used for the save handlers in the config form
495
     * and as checks in set_user_config and get_user_config.
496
     *
497
     * @return array array of strings (config field names)
498
     */
499
    public function get_allowed_user_config() {
500
        return array();
501
    }
502
 
503
    /**
504
     * A list of fields that can be configured by the user.
505
     * This is used for the save handlers in the config form
506
     * and as checks in set_export_config and get_export_config.
507
     *
508
     * @return array array of strings (config field names)
509
     */
510
    public function get_allowed_export_config() {
511
        return array();
512
    }
513
 
514
    /**
515
     * Saves (or updates) the config stored in portfolio_instance_config.
516
     * You shouldn't need to override this unless you're doing something funky.
517
     *
518
     * @param array $config array of config items.
519
     */
520
    final public function set_config($config) {
521
        global $DB;
522
        foreach ($config as $key => $value) {
523
            // try set it in $this first
524
            try {
525
                $this->set($key, $value);
526
                continue;
527
            } catch (portfolio_exception $e) { }
528
            if (!in_array($key, $this->get_allowed_config())) {
529
                $a = (object)array('property' => $key, 'class' => get_class($this));
530
                throw new portfolio_export_exception($this->get('exporter'), 'invalidconfigproperty', 'portfolio', null, $a);
531
            }
532
            if (!isset($this->config->{$key})) {
533
                $DB->insert_record('portfolio_instance_config', (object)array(
534
                    'instance' => $this->id,
535
                    'name' => $key,
536
                    'value' => $value,
537
                ));
538
            } else if ($this->config->{$key} != $value) {
539
                $DB->set_field('portfolio_instance_config', 'value', $value, array('name' => $key, 'instance' => $this->id));
540
            }
541
            $this->config->{$key} = $value;
542
        }
543
    }
544
 
545
    /**
546
     * Gets the value of a particular config item
547
     *
548
     * @param string $key key to fetch
549
     * @return null|mixed the corresponding value
550
     */
551
    final public function get_config($key) {
552
        if (!in_array($key, $this->get_allowed_config())) {
553
            $a = (object)array('property' => $key, 'class' => get_class($this));
554
            throw new portfolio_export_exception($this->get('exporter'), 'invalidconfigproperty', 'portfolio', null, $a);
555
        }
556
        if (isset($this->config->{$key})) {
557
            return $this->config->{$key};
558
        }
559
        return null;
560
    }
561
 
562
    /**
563
     * Get the value of a config item for a particular user.
564
     *
565
     * @param string $key key to fetch
566
     * @param int $userid id of user (defaults to current)
567
     * @return string the corresponding value
568
     *
569
     */
570
    final public function get_user_config($key, $userid=0) {
571
        global $DB;
572
 
573
        if (empty($userid)) {
574
            $userid = $this->user->id;
575
        }
576
 
577
        if ($key != 'visible') { // handled by the parent class
578
            if (!in_array($key, $this->get_allowed_user_config())) {
579
                $a = (object)array('property' => $key, 'class' => get_class($this));
580
                throw new portfolio_export_exception($this->get('exporter'), 'invaliduserproperty', 'portfolio', null, $a);
581
            }
582
        }
583
        if (!array_key_exists($userid, $this->userconfig)) {
584
            $this->userconfig[$userid] = (object)array_fill_keys(array_merge(array('visible'), $this->get_allowed_user_config()), null);
585
            foreach ($DB->get_records('portfolio_instance_user', array('instance' => $this->id, 'userid' => $userid)) as $config) {
586
                $this->userconfig[$userid]->{$config->name} = $config->value;
587
            }
588
        }
589
        if ($this->userconfig[$userid]->visible === null) {
590
            $this->set_user_config(array('visible' => 1), $userid);
591
        }
592
        return $this->userconfig[$userid]->{$key};
593
 
594
    }
595
 
596
    /**
597
     * Sets config options for a given user.
598
     *
599
     * @param array $config array containing key/value pairs to set
600
     * @param int $userid userid to set config for (defaults to current)
601
     *
602
     */
603
    final public function set_user_config($config, $userid=0) {
604
        global $DB;
605
 
606
        if (empty($userid)) {
607
            $userid = $this->user->id;
608
        }
609
 
610
        foreach ($config as $key => $value) {
611
            if ($key != 'visible' && !in_array($key, $this->get_allowed_user_config())) {
612
                $a = (object)array('property' => $key, 'class' => get_class($this));
613
                throw new portfolio_export_exception($this->get('exporter'), 'invaliduserproperty', 'portfolio', null, $a);
614
            }
615
            if (!$existing = $DB->get_record('portfolio_instance_user', array('instance'=> $this->id, 'userid' => $userid, 'name' => $key))) {
616
                $DB->insert_record('portfolio_instance_user', (object)array(
617
                    'instance' => $this->id,
618
                    'name' => $key,
619
                    'value' => $value,
620
                    'userid' => $userid,
621
                ));
622
            } else if ($existing->value != $value) {
623
                $DB->set_field('portfolio_instance_user', 'value', $value, array('name' => $key, 'instance' => $this->id, 'userid' => $userid));
624
            }
625
            $this->userconfig[$userid]->{$key} = $value;
626
        }
627
 
628
    }
629
 
630
    /**
631
     * Generic getter for properties belonging to this instance
632
     * <b>outside</b> the subclasses
633
     * like name, visible etc.
634
     *
635
     * @param string $field property name
636
     * @return mixed value of the field
637
     */
638
    final public function get($field) {
639
        // This is a legacy change to the way files are get/set.
640
        // We now only set $this->file to the id of the \stored_file. So, we need to convert that id back to a \stored_file here.
641
        if ($field === 'file') {
642
            return $this->get_file();
643
        }
644
        if (property_exists($this, $field)) {
645
            return $this->{$field};
646
        }
647
        $a = (object)array('property' => $field, 'class' => get_class($this));
648
        throw new portfolio_export_exception($this->get('exporter'), 'invalidproperty', 'portfolio', null, $a);
649
    }
650
 
651
    /**
652
     * Generic setter for properties belonging to this instance
653
     * <b>outside</b> the subclass
654
     * like name, visible, etc.
655
     *
656
     * @param string $field property's name
657
     * @param string $value property's value
658
     * @return bool
659
     */
660
    final public function set($field, $value) {
661
        // This is a legacy change to the way files are get/set.
662
        // Make sure we never save the \stored_file object. Instead, use the id from $file->get_id() - set_file() does this for us.
663
        if ($field === 'file') {
664
            $this->set_file($value);
665
            return true;
666
        }
667
        if (property_exists($this, $field)) {
668
            $this->{$field} =& $value;
669
            $this->dirty = true;
670
            return true;
671
        }
672
        $a = (object)array('property' => $field, 'class' => get_class($this));
673
        if ($this->get('exporter')) {
674
            throw new portfolio_export_exception($this->get('exporter'), 'invalidproperty', 'portfolio', null, $a);
675
        }
676
        throw new portfolio_exception('invalidproperty', 'portfolio', null, $a); // this happens outside export (eg admin settings)
677
 
678
    }
679
 
680
    /**
681
     * Saves stuff that's been stored in the object to the database.
682
     * You shouldn't need to override this
683
     * unless you're doing something really funky.
684
     * and if so, call parent::save when you're done.
685
     *
686
     * @return bool
687
     */
688
    public function save() {
689
        global $DB;
690
        if (!$this->dirty) {
691
            return true;
692
        }
693
        $fordb = new StdClass();
694
        foreach (array('id', 'name', 'plugin', 'visible') as $field) {
695
            $fordb->{$field} = $this->{$field};
696
        }
697
        $DB->update_record('portfolio_instance', $fordb);
698
        $this->dirty = false;
699
        return true;
700
    }
701
 
702
    /**
703
     * Deletes everything from the database about this plugin instance.
704
     * You shouldn't need to override this unless you're storing stuff
705
     * in your own tables.  and if so, call parent::delete when you're done.
706
     *
707
     * @return bool
708
     */
709
    public function delete() {
710
        global $DB;
711
        $DB->delete_records('portfolio_instance_config', array('instance' => $this->get('id')));
712
        $DB->delete_records('portfolio_instance_user', array('instance' => $this->get('id')));
713
        $DB->delete_records('portfolio_tempdata', array('instance' => $this->get('id')));
714
        $DB->delete_records('portfolio_instance', array('id' => $this->get('id')));
715
        $this->dirty = false;
716
        return true;
717
    }
718
 
719
    /**
720
     * Perform any required cleanup functions
721
     *
722
     * @return bool
723
     */
724
    public function cleanup() {
725
        return true;
726
    }
727
 
728
    /**
729
     * Whether this plugin supports multiple exports in the same session
730
     * most plugins should handle this, but some that require a redirect for authentication
731
     * and then don't support dynamically constructed urls to return to (eg box.net)
732
     * need to override this to return false.
733
     * This means that moodle will prevent multiple exports of this *type* of plugin
734
     * occurring in the same session.
735
     *
736
     * @return bool
737
     */
738
    public static function allows_multiple_exports() {
739
        return true;
740
    }
741
 
742
    /**
743
     * Return a string to put at the header summarising this export
744
     * by default, just the plugin instance name
745
     *
746
     * @return string
747
     */
748
    public function heading_summary() {
749
        return get_string('exportingcontentto', 'portfolio', $this->name);
750
    }
751
}
752
 
753
/**
754
 * Class to inherit from for 'push' type plugins
755
 *
756
 * Eg: those that send the file via a HTTP post or whatever
757
 *
758
 * @package core_portfolio
759
 * @category portfolio
760
 * @copyright 2008 Penny Leach <penny@catalyst.net.nz>
761
 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
762
 */
763
abstract class portfolio_plugin_push_base extends portfolio_plugin_base {
764
 
765
    /**
766
     * Get the capability to push
767
     *
768
     * @return bool
769
     */
770
    public function is_push() {
771
        return true;
772
    }
773
}
774
 
775
/**
776
 * Class to inherit from for 'pull' type plugins.
777
 *
778
 * Eg: those that write a file and wait for the remote system to request it
779
 * from portfolio/file.php.
780
 * If you're using this you must do $this->set('file', $file) so that it can be served.
781
 *
782
 * @package core_portfolio
783
 * @category portfolio
784
 * @copyright 2008 Penny Leach <penny@catalyst.net.nz>
785
 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
786
 */
787
abstract class portfolio_plugin_pull_base extends portfolio_plugin_base {
788
 
789
    /** @var int $file the id of a single file */
790
    protected $file;
791
 
792
    /**
793
     * return the enablelity to push
794
     *
795
     * @return bool
796
     */
797
    public function is_push() {
798
        return false;
799
    }
800
 
801
    /**
802
     * The base part of the download file url to pull files from
803
     * your plugin might need to add &foo=bar on the end
804
     * @see verify_file_request_params
805
     *
806
     * @return string the url
807
     */
808
    public function get_base_file_url() {
809
        global $CFG;
810
        return $CFG->wwwroot . '/portfolio/file.php?id=' . $this->exporter->get('id');
811
    }
812
 
813
    /**
814
     * Before sending the file when the pull is requested, verify the request parameters.
815
     * These might include a token of some sort of whatever
816
     *
817
     * @param array $params request parameters (POST wins over GET)
818
     */
819
    abstract public function verify_file_request_params($params);
820
 
821
    /**
822
     * Called from portfolio/file.php.
823
     * This function sends the stored file out to the browser.
824
     * The default is to just use send_stored_file,
825
     * but other implementations might do something different,
826
     * for example, send back the file base64 encoded and encrypted
827
     * mahara does this but in the response to an xmlrpc request
828
     * rather than through file.php
829
     */
830
    public function send_file() {
831
        $file = $this->get('file');
832
        if (!($file instanceof stored_file)) {
833
            throw new portfolio_export_exception($this->get('exporter'), 'filenotfound', 'portfolio');
834
        }
835
        // don't die(); afterwards, so we can clean up.
836
        send_stored_file($file, 0, 0, true, array('dontdie' => true));
837
        $this->get('exporter')->log_transfer();
838
    }
839
 
840
    /**
841
     * Sets the $file instance var to the id of the supplied \stored_file.
842
 
843
     * This helper allows the $this->get('file') call to return a \stored_file, but means that we only ever record an id reference
844
     * in the $file instance var.
845
     *
846
     * @param \stored_file $file The stored_file instance.
847
     * @return void
848
     */
849
    protected function set_file(\stored_file $file) {
850
        $fileid = $file->get_id();
851
        if (empty($fileid)) {
852
            debugging('stored_file->id should not be empty');
853
            $this->file = null;
854
        } else {
855
            $this->file = $fileid;
856
        }
857
    }
858
 
859
    /**
860
     * Gets the \stored_file object from the file id in the $file instance var.
861
     *
862
     * @return stored_file|null the \stored_file object if it exists, null otherwise.
863
     */
864
    protected function get_file() {
865
        if (!$this->file) {
866
            return null;
867
        }
868
        // The get_file_by_id call can return false, so normalise to null.
869
        $file = get_file_storage()->get_file_by_id($this->file);
870
        return ($file) ? $file : null;
871
    }
872
}