MDL-16408 Improve counting of questions of a missing type.
[moodle.git] / lib / portfoliolib.php
CommitLineData
67a87e7d 1<?php
67a87e7d 2/**
87fcac8d 3 * Moodle - Modular Object-Oriented Dynamic Learning Environment
4 * http://moodle.org
5 * Copyright (C) 1999 onwards Martin Dougiamas http://dougiamas.com
6 *
7 * This program is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation, either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program. If not, see <http://www.gnu.org/licenses/>.
19 *
20 * @package moodle
21 * @subpackage portfolio
22 * @author Penny Leach <penny@catalyst.net.nz>
23 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL
24 * @copyright (C) 1999 onwards Martin Dougiamas http://dougiamas.com
25 *
26 * This file contains all global functions to do with manipulating portfolios
27 * everything else that is logically namespaced by class is in its own file
28 * in lib/portfolio/ directory.
29 */
30
31// require all the sublibraries first.
32require_once($CFG->libdir . '/portfolio/constants.php'); // all the constants for time, export format etc.
33require_once($CFG->libdir . '/portfolio/exceptions.php'); // exception classes used by portfolio code
34require_once($CFG->libdir . '/portfolio/formats.php'); // the export format hierarchy
35require_once($CFG->libdir . '/portfolio/forms.php'); // the form classes that subclass moodleform
36require_once($CFG->libdir . '/portfolio/exporter.php'); // the exporter class
37require_once($CFG->libdir . '/portfolio/plugin.php'); // the base classes for plugins
38require_once($CFG->libdir . '/portfolio/caller.php'); // the base classes for calling code
39
40/**
41* Entry point to add an 'add to portfolio' button to a page somewhere in moodle
67a87e7d 42*
87fcac8d 43* This function does not check permissions. the caller must check permissions first.
44* Later, during the export process, the caller class is instantiated and the check_permissions method is called
45* This does <b>not</b> happen in this function - you are responsible for it.
67a87e7d 46*
47* @param string $callbackclass name of the class containing the callback functions
48* activity modules should ALWAYS use their name_portfolio_caller
49* other locations must use something unique
50* @param mixed $callbackargs this can be an array or hash of arguments to pass
51* back to the callback functions (passed by reference)
52* these MUST be primatives to be added as hidden form fields.
53* and the values get cleaned to PARAM_ALPHAEXT or PARAM_NUMBER or PARAM_PATH
ed1fcf79 54* @param string $callbackfile this can be autodetected if it's in the same file as your caller,
55* but more often, the caller is a script.php and the class in a lib.php
56* so you can pass it here if necessary.
87fcac8d 57* this path should be relative (ie, not include) dirroot, eg '/mod/forum/lib.php'
866d543f 58* @param int $format format to display the button or form or icon or link.
59* See constants PORTFOLIO_ADD_XXX for more info.
60* optional, defaults to PORTFOLI_ADD_FULL_FORM
61* @param str $addstr string to use for the button or icon alt text or link text.
62* this is whole string, not key. optional, defaults to 'Add to portfolio';
67a87e7d 63* @param boolean $return whether to echo or return content (optional defaults to false (echo)
349242a3 64* @param array $callersupports if the calling code knows better than the static method on the calling class (supported_formats)
65* eg, if there's a file that might be an image, you can pass it here instead
87fcac8d 66* {@see portfolio_format_from_file} for how to get the appropriate formats to pass here.
67a87e7d 67*/
349242a3 68function portfolio_add_button($callbackclass, $callbackargs, $callbackfile=null, $format=PORTFOLIO_ADD_FULL_FORM, $addstr=null, $return=false, $callersupports=null) {
67a87e7d 69
70 global $SESSION, $CFG, $COURSE, $USER;
71
90658eef 72 if (empty($CFG->enableportfolios)) {
a239f01e 73 return;
74 }
75
67a87e7d 76 if (!$instances = portfolio_instances()) {
77 return;
78 }
79
84a44985 80 if (defined('PORTFOLIO_INTERNAL')) {
6fdd8fa7 81 // something somewhere has detected a risk of this being called during inside the preparation
82 // eg forum_print_attachments
83 return;
84 }
85
84a44985 86 if (isset($SESSION->portfolioexport)) {
ac6a5492 87 $a = new StdClass;
88 $a->cancel = $CFG->wwwroot . '/portfolio/add.php?cancel=1';
89 $a->finish = $CFG->wwwroot . '/portfolio/add.php?id=' . $SESSION->portfolioexport;
3bb8a2c7 90 throw new portfolio_exception('alreadyexporting', 'portfolio', null, $a);
84a44985 91 }
92
ed1fcf79 93 if (empty($callbackfile)) {
94 $backtrace = debug_backtrace();
95 if (!array_key_exists(0, $backtrace) || !array_key_exists('file', $backtrace[0]) || !is_readable($backtrace[0]['file'])) {
96 debugging(get_string('nocallbackfile', 'portfolio'));
97 return;
98 }
99
100 $callbackfile = substr($backtrace[0]['file'], strlen($CFG->dirroot));
101 } else {
102 if (!is_readable($CFG->dirroot . $callbackfile)) {
103 debugging(get_string('nocallbackfile', 'portfolio'));
104 return;
105 }
67a87e7d 106 }
107
67a87e7d 108 require_once($CFG->dirroot . $callbackfile);
109
349242a3 110 if (empty($callersupports)) {
111 $callersupports = call_user_func(array($callbackclass, 'supported_formats'));
112 }
67a87e7d 113
866d543f 114 $formoutput = '<form method="post" action="' . $CFG->wwwroot . '/portfolio/add.php" id="portfolio-add-button">' . "\n";
115 $linkoutput = '<a href="' . $CFG->wwwroot . '/portfolio/add.php?';
67a87e7d 116 foreach ($callbackargs as $key => $value) {
117 if (!empty($value) && !is_string($value) && !is_numeric($value)) {
118 $a->key = $key;
119 $a->value = print_r($value, true);
120 debugging(get_string('nonprimative', 'portfolio', $a));
121 return;
122 }
866d543f 123 $linkoutput .= 'ca_' . $key . '=' . $value . '&amp;';
124 $formoutput .= "\n" . '<input type="hidden" name="ca_' . $key . '" value="' . $value . '" />';
67a87e7d 125 }
866d543f 126 $formoutput .= "\n" . '<input type="hidden" name="callbackfile" value="' . $callbackfile . '" />';
127 $formoutput .= "\n" . '<input type="hidden" name="callbackclass" value="' . $callbackclass . '" />';
128 $formoutput .= "\n" . '<input type="hidden" name="course" value="' . (!empty($COURSE) ? $COURSE->id : 0) . '" />';
129 $linkoutput .= 'callbackfile=' . $callbackfile . '&amp;callbackclass='
130 . $callbackclass . '&amp;course=' . (!empty($COURSE) ? $COURSE->id : 0);
67a87e7d 131 $selectoutput = '';
132 if (count($instances) == 1) {
133 $instance = array_shift($instances);
349242a3 134 $formats = portfolio_supported_formats_intersect($callersupports, $instance->supported_formats());
135 if (count($formats) == 0) {
67a87e7d 136 // bail. no common formats.
137 debugging(get_string('nocommonformats', 'portfolio', $callbackclass));
138 return;
139 }
140 if ($error = portfolio_instance_sanity_check($instance)) {
141 // bail, plugin is misconfigured
142 debugging(get_string('instancemisconfigured', 'portfolio', get_string($error[$instance->get('id')], 'portfolio_' . $instance->get('plugin'))));
143 return;
144 }
866d543f 145 $formoutput .= "\n" . '<input type="hidden" name="instance" value="' . $instance->get('id') . '" />';
146 $linkoutput .= '&amp;instance=' . $instance->get('id');
67a87e7d 147 }
148 else {
7c61a8f0 149 $selectoutput = portfolio_instance_select($instances, $callersupports, $callbackclass, 'instance', true);
67a87e7d 150 }
151
866d543f 152 if (empty($addstr)) {
153 $addstr = get_string('addtoportfolio', 'portfolio');
67a87e7d 154 }
866d543f 155 if (empty($format)) {
156 $format = PORTFOLIO_ADD_FULL_FORM;
157 }
158 switch ($format) {
159 case PORTFOLIO_ADD_FULL_FORM:
160 $formoutput .= $selectoutput;
161 $formoutput .= "\n" . '<input type="submit" value="' . $addstr .'" />';
162 $formoutput .= "\n" . '</form>';
163 break;
164 case PORTFOLIO_ADD_ICON_FORM:
165 $formoutput .= $selectoutput;
166 $formoutput .= "\n" . '<input type="image" src="' . $CFG->pixpath . '/t/portfolio.gif" alt=' . $addstr .'" />';
167 $formoutput .= "\n" . '</form>';
168 break;
169 case PORTFOLIO_ADD_ICON_LINK:
170 $linkoutput .= '"><img src="' . $CFG->pixpath . '/t/portfolio.gif" alt=' . $addstr .'" /></a>';
171 break;
172 case PORTFOLIO_ADD_TEXT_LINK:
173 $linkoutput .= '">' . $addstr .'</a>';
174 break;
175 default:
3bb8a2c7 176 debugging(get_string('invalidaddformat', 'portfolio', $format));
866d543f 177 }
178 $output = (in_array($format, array(PORTFOLIO_ADD_FULL_FORM, PORTFOLIO_ADD_ICON_FORM)) ? $formoutput : $linkoutput);
67a87e7d 179 if ($return) {
180 return $output;
181 } else {
182 echo $output;
183 }
184 return true;
185}
186
187/**
188* returns a drop menu with a list of available instances.
189*
87fcac8d 190* @param array $instances array of portfolio plugin instance objects - the instances to put in the menu
191* @param array $callerformats array of PORTFOLIO_FORMAT_XXX constants - the formats the caller supports (this is used to filter plugins)
192* @param array $callbackclass the callback class name - used for debugging only for when there are no common formats
193* @param string $selectname the name of the select element. Optional, defaults to instance.
194* @param boolean $return whether to print or return the output. Optional, defaults to print.
195* @param booealn $returnarray if returning, whether to return the HTML or the array of options. Optional, defaults to HTML.
67a87e7d 196*
197* @return string the html, from <select> to </select> inclusive.
198*/
9eb0a772 199function portfolio_instance_select($instances, $callerformats, $callbackclass, $selectname='instance', $return=false, $returnarray=false) {
200 global $CFG;
201
90658eef 202 if (empty($CFG->enableportfolios)) {
9eb0a772 203 return;
204 }
205
67a87e7d 206 $insane = portfolio_instance_sanity_check();
207 $count = 0;
9eb0a772 208 $selectoutput = "\n" . '<select name="' . $selectname . '">' . "\n";
67a87e7d 209 foreach ($instances as $instance) {
349242a3 210 $formats = portfolio_supported_formats_intersect($callerformats, $instance->supported_formats());
211 if (count($formats) == 0) {
67a87e7d 212 // bail. no common formats.
213 continue;
214 }
215 if (array_key_exists($instance->get('id'), $insane)) {
216 // bail, plugin is misconfigured
217 debugging(get_string('instancemisconfigured', 'portfolio', get_string($insane[$instance->get('id')], 'portfolio_' . $instance->get('plugin'))));
218 continue;
219 }
220 $count++;
9eb0a772 221 $selectoutput .= "\n" . '<option value="' . $instance->get('id') . '">' . $instance->get('name') . '</option>' . "\n";
222 $options[$instance->get('id')] = $instance->get('name');
67a87e7d 223 }
224 if (empty($count)) {
225 // bail. no common formats.
226 debugging(get_string('nocommonformats', 'portfolio', $callbackclass));
227 return;
228 }
229 $selectoutput .= "\n" . "</select>\n";
9eb0a772 230 if (!empty($returnarray)) {
231 return $options;
232 }
233 if (!empty($return)) {
234 return $selectoutput;
235 }
236 echo $selectoutput;
67a87e7d 237}
238
239/**
240* return all portfolio instances
241*
87fcac8d 242* @todo check capabilities here - see MDL-15768
243*
244* @param boolean visibleonly Don't include hidden instances. Defaults to true and will be overridden to true if the next parameter is true
245* @param boolean useronly Check the visibility preferences and permissions of the logged in user. Defaults to true.
246*
67a87e7d 247* @return array of portfolio instances (full objects, not just database records)
248*/
249function portfolio_instances($visibleonly=true, $useronly=true) {
250
251 global $DB, $USER;
252
253 $values = array();
254 $sql = 'SELECT * FROM {portfolio_instance}';
255
256 if ($visibleonly || $useronly) {
257 $values[] = 1;
258 $sql .= ' WHERE visible = ?';
259 }
260 if ($useronly) {
261 $sql .= ' AND id NOT IN (
262 SELECT instance FROM {portfolio_instance_user}
263 WHERE userid = ? AND name = ? AND value = ?
264 )';
265 $values = array_merge($values, array($USER->id, 'visible', 0));
266 }
267 $sql .= ' ORDER BY name';
268
269 $instances = array();
270 foreach ($DB->get_records_sql($sql, $values) as $instance) {
a50ef3d3 271 $instances[$instance->id] = portfolio_instance($instance->id, $instance);
67a87e7d 272 }
67a87e7d 273 return $instances;
274}
275
276/**
87fcac8d 277* Supported formats currently in use.
278*
279* Canonical place for a list of all formats
280* that portfolio plugins and callers
67a87e7d 281* can use for exporting content
282*
87fcac8d 283* @return keyed array of all the available export formats (constant => classname)
67a87e7d 284*/
285function portfolio_supported_formats() {
286 return array(
349242a3 287 PORTFOLIO_FORMAT_FILE => 'portfolio_format_file',
288 PORTFOLIO_FORMAT_IMAGE => 'portfolio_format_image',
289 PORTFOLIO_FORMAT_HTML => 'portfolio_format_html',
ea0de12f 290 PORTFOLIO_FORMAT_TEXT => 'portfolio_format_text',
291 PORTFOLIO_FORMAT_VIDEO => 'portfolio_format_video',
5071079c 292 /*PORTFOLIO_FORMAT_MBKP, */ // later
293 /*PORTFOLIO_FORMAT_PIOP, */ // also later
67a87e7d 294 );
295}
296
ea0de12f 297/**
87fcac8d 298* Deduce export format from file mimetype
299*
300* This function returns the revelant portfolio export format
ea0de12f 301* which is used to determine which portfolio plugins can be used
302* for exporting this content
303* according to the mime type of the given file
304* this only works when exporting exactly <b>one</b> file
305*
306* @param stored_file $file file to check mime type for
87fcac8d 307*
ea0de12f 308* @return string the format constant (see PORTFOLIO_FORMAT_XXX constants)
309*/
87fcac8d 310function portfolio_format_from_file(stored_file $file) {
ea0de12f 311 static $alreadymatched;
312 if (empty($alreadymatched)) {
313 $alreadymatched = array();
314 }
315 if (!($file instanceof stored_file)) {
316 throw new portfolio_exception('invalidfileargument', 'portfolio');
317 }
318 $mimetype = $file->get_mimetype();
319 if (array_key_exists($mimetype, $alreadymatched)) {
320 return $alreadymatched[$mimetype];
321 }
322 $allformats = portfolio_supported_formats();
323 foreach ($allformats as $format => $classname) {
324 $supportedmimetypes = call_user_func(array($classname, 'mimetypes'));
325 if (!is_array($supportedmimetypes)) {
326 debugging("one of the portfolio format classes, $classname, said it supported something funny for mimetypes, should have been array...");
327 debugging(print_r($supportedmimetypes, true));
328 continue;
329 }
330 if (in_array($mimetype, $supportedmimetypes)) {
331 $alreadymatched[$mimetype] = $format;
332 return $format;
333 }
334 }
335 return PORTFOLIO_FORMAT_FILE; // base case for files...
336}
337
338/**
87fcac8d 339* Intersection of plugin formats and caller formats
340*
341* Walks both the caller formats and portfolio plugin formats
ea0de12f 342* and looks for matches (walking the hierarchy as well)
343* and returns the intersection
344*
345* @param array $callerformats formats the caller supports
346* @param array $pluginformats formats the portfolio plugin supports
347*/
7812e882 348function portfolio_supported_formats_intersect($callerformats, $pluginformats) {
349 $allformats = portfolio_supported_formats();
350 $intersection = array();
351 foreach ($callerformats as $cf) {
352 if (!array_key_exists($cf, $allformats)) {
353 debugging(get_string('invalidformat', 'portfolio', $cf));
354 continue;
355 }
34035201 356 $cfobj = new $allformats[$cf]();
7812e882 357 foreach ($pluginformats as $p => $pf) {
358 if (!array_key_exists($pf, $allformats)) {
359 debugging(get_string('invalidformat', 'portfolio', $pf));
360 unset($pluginformats[$p]); // to avoid the same warning over and over
361 continue;
362 }
34035201 363 if ($cfobj instanceof $allformats[$pf]) {
7812e882 364 $intersection[] = $cf;
365 }
366 }
367 }
368 return $intersection;
369}
370
67a87e7d 371/**
372* helper function to return an instance of a plugin (with config loaded)
373*
87fcac8d 374* @param int $instance id of instance
375* @param array $record database row that corresponds to this instance
376* this is passed to avoid unnecessary lookups
377* Optional, and the record will be retrieved if null.
67a87e7d 378*
379* @return subclass of portfolio_plugin_base
380*/
381function portfolio_instance($instanceid, $record=null) {
382 global $DB, $CFG;
383
384 if ($record) {
385 $instance = $record;
386 } else {
387 if (!$instance = $DB->get_record('portfolio_instance', array('id' => $instanceid))) {
34035201 388 throw new portfolio_exception('invalidinstance', 'portfolio');
67a87e7d 389 }
390 }
391 require_once($CFG->dirroot . '/portfolio/type/'. $instance->plugin . '/lib.php');
392 $classname = 'portfolio_plugin_' . $instance->plugin;
393 return new $classname($instanceid, $instance);
394}
395
396/**
87fcac8d 397* Helper function to call a static function on a portfolio plugin class
398*
399* This will figure out the classname and require the right file and call the function.
67a87e7d 400* you can send a variable number of arguments to this function after the first two
401* and they will be passed on to the function you wish to call.
402*
87fcac8d 403* @param string $plugin name of plugin
67a87e7d 404* @param string $function function to call
405*/
406function portfolio_static_function($plugin, $function) {
407 global $CFG;
408
409 $pname = null;
410 if (is_object($plugin) || is_array($plugin)) {
411 $plugin = (object)$plugin;
412 $pname = $plugin->name;
413 } else {
414 $pname = $plugin;
415 }
416
417 $args = func_get_args();
418 if (count($args) <= 2) {
419 $args = array();
420 }
421 else {
422 array_shift($args);
423 array_shift($args);
424 }
425
426 require_once($CFG->dirroot . '/portfolio/type/' . $plugin . '/lib.php');
427 return call_user_func_array(array('portfolio_plugin_' . $plugin, $function), $args);
428}
429
430/**
431* helper function to check all the plugins for sanity and set any insane ones to invisible.
432*
433* @param array $plugins to check (if null, defaults to all)
434* one string will work too for a single plugin.
435*
436* @return array array of insane instances (keys= id, values = reasons (keys for plugin lang)
437*/
438function portfolio_plugin_sanity_check($plugins=null) {
439 global $DB;
440 if (is_string($plugins)) {
441 $plugins = array($plugins);
442 } else if (empty($plugins)) {
443 $plugins = get_list_of_plugins('portfolio/type');
444 }
445
446 $insane = array();
447 foreach ($plugins as $plugin) {
448 if ($result = portfolio_static_function($plugin, 'plugin_sanity_check')) {
449 $insane[$plugin] = $result;
450 }
451 }
452 if (empty($insane)) {
453 return array();
454 }
455 list($where, $params) = $DB->get_in_or_equal(array_keys($insane));
456 $where = ' plugin ' . $where;
457 $DB->set_field_select('portfolio_instance', 'visible', 0, $where, $params);
458 return $insane;
459}
460
461/**
462* helper function to check all the instances for sanity and set any insane ones to invisible.
463*
464* @param array $instances to check (if null, defaults to all)
465* one instance or id will work too
466*
467* @return array array of insane instances (keys= id, values = reasons (keys for plugin lang)
468*/
469function portfolio_instance_sanity_check($instances=null) {
470 global $DB;
471 if (empty($instances)) {
472 $instances = portfolio_instances(false);
473 } else if (!is_array($instances)) {
474 $instances = array($instances);
475 }
476
477 $insane = array();
478 foreach ($instances as $instance) {
479 if (is_object($instance) && !($instance instanceof portfolio_plugin_base)) {
480 $instance = portfolio_instance($instance->id, $instance);
481 } else if (is_numeric($instance)) {
482 $instance = portfolio_instance($instance);
483 }
484 if (!($instance instanceof portfolio_plugin_base)) {
485 debugging('something weird passed to portfolio_instance_sanity_check, not subclass or id');
486 continue;
487 }
488 if ($result = $instance->instance_sanity_check()) {
489 $insane[$instance->get('id')] = $result;
490 }
491 }
492 if (empty($insane)) {
493 return array();
494 }
495 list ($where, $params) = $DB->get_in_or_equal(array_keys($insane));
496 $where = ' id ' . $where;
497 $DB->set_field_select('portfolio_instance', 'visible', 0, $where, $params);
498 return $insane;
499}
500
501/**
502* helper function to display a table of plugins (or instances) and reasons for disabling
503*
504* @param array $insane array of insane plugins (key = plugin (or instance id), value = reason)
505* @param array $instances if reporting instances rather than whole plugins, pass the array (key = id, value = object) here
506*
507*/
a50ef3d3 508function portfolio_report_insane($insane, $instances=false, $return=false) {
67a87e7d 509 if (empty($insane)) {
510 return;
511 }
512
513 static $pluginstr;
514 if (empty($pluginstr)) {
515 $pluginstr = get_string('plugin', 'portfolio');
516 }
517 if ($instances) {
518 $headerstr = get_string('someinstancesdisabled', 'portfolio');
519 } else {
520 $headerstr = get_string('somepluginsdisabled', 'portfolio');
521 }
522
a50ef3d3 523 $output = notify($headerstr, 'notifyproblem', 'center', true);
67a87e7d 524 $table = new StdClass;
525 $table->head = array($pluginstr, '');
526 $table->data = array();
527 foreach ($insane as $plugin => $reason) {
528 if ($instances) {
67a87e7d 529 $instance = $instances[$plugin];
530 $plugin = $instance->get('plugin');
531 $name = $instance->get('name');
532 } else {
533 $name = $plugin;
534 }
535 $table->data[] = array($name, get_string($reason, 'portfolio_' . $plugin));
536 }
a50ef3d3 537 $output .= print_table($table, true);
538 $output .= '<br /><br /><br />';
539
540 if ($return) {
541 return $output;
542 }
543 echo $output;
67a87e7d 544}
545
9eb0a772 546/**
547* fake the url to portfolio/add.php from data from somewhere else
548* you should use portfolio_add_button instead 99% of the time
549*
87fcac8d 550* @param int $instanceid instanceid (optional, will force a new screen if not specified)
551* @param string $classname callback classname
552* @param string $classfile file containing the callback class definition
553* @param array $callbackargs arguments to pass to the callback class
9eb0a772 554*/
555function portfolio_fake_add_url($instanceid, $classname, $classfile, $callbackargs) {
556 global $CFG;
557 $url = $CFG->wwwroot . '/portfolio/add.php?instance=' . $instanceid . '&amp;callbackclass=' . $classname . '&amp;callbackfile=' . $classfile;
558
559 if (is_object($callbackargs)) {
560 $callbackargs = (array)$callbackargs;
561 }
562 if (!is_array($callbackargs) || empty($callbackargs)) {
563 return $url;
564 }
565 foreach ($callbackargs as $key => $value) {
566 $url .= '&amp;ca_' . $key . '=' . urlencode($value);
567 }
568 return $url;
569}
67a87e7d 570
67a87e7d 571
67a87e7d 572
87fcac8d 573/**
574* event handler for the portfolio_send event
575*/
576function portfolio_handle_event($eventdata) {
577 global $CFG;
578 $exporter = portfolio_exporter::rewaken_object($eventdata);
579 $exporter->process_stage_package();
580 $exporter->process_stage_send();
581 $exporter->save();
582 $exporter->process_stage_cleanup();
583 return true;
67a87e7d 584}
585
87fcac8d 586/**
587* main portfolio cronjob
588* currently just cleans up expired transfer records.
589*
590* @todo add hooks in the plugins - either per instance or per plugin
591*/
592function portfolio_cron() {
593 global $DB;
9eb0a772 594
87fcac8d 595 if ($expired = $DB->get_records_select('portfolio_tempdata', 'expirytime < ?', array(time()), '', 'id')) {
596 foreach ($expired as $d) {
597 $e = portfolio_exporter::rewaken_object($d);
598 $e->process_stage_cleanup(true);
9eb0a772 599 }
192ce92b 600 }
5071079c 601}
602
67a87e7d 603/**
87fcac8d 604* helper function to rethrow a caught portfolio_exception as an export exception
605*
606* used because when a portfolio_export exception is thrown the export is cancelled
607*
608* @param portfolio_exporter $exporter current exporter object
609* @param exception $exception exception to rethrow
610*
611* @return void
612* @throws portfolio_export_exceptiog
67a87e7d 613*/
87fcac8d 614function portfolio_export_rethrow_exception($exporter, $exception) {
615 throw new portfolio_export_exception($exporter, $exception->errorcode, $exception->module, $exception->link, $exception->a);
616}
67a87e7d 617
67a87e7d 618
67a87e7d 619?>