Commit | Line | Data |
---|---|---|
67a87e7d | 1 | <?php |
50fcb1d8 | 2 | |
3 | // This file is part of Moodle - http://moodle.org/ | |
4 | // | |
5 | // Moodle is free software: you can redistribute it and/or modify | |
6 | // it under the terms of the GNU General Public License as published by | |
7 | // the Free Software Foundation, either version 3 of the License, or | |
8 | // (at your option) any later version. | |
9 | // | |
10 | // Moodle is distributed in the hope that it will be useful, | |
11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of | |
12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
13 | // GNU General Public License for more details. | |
14 | // | |
15 | // You should have received a copy of the GNU General Public License | |
16 | // along with Moodle. If not, see <http://www.gnu.org/licenses/>. | |
17 | ||
67a87e7d | 18 | /** |
87fcac8d | 19 | * This file contains all global functions to do with manipulating portfolios |
20 | * everything else that is logically namespaced by class is in its own file | |
21 | * in lib/portfolio/ directory. | |
50fcb1d8 | 22 | * |
23 | * Major Contributors | |
24 | * - Penny Leach <penny@catalyst.net.nz> | |
25 | * | |
26 | * @package moodlecore | |
27 | * @subpackage portfolio | |
28 | * @copyright 1999 onwards Martin Dougiamas {@link http://moodle.com} | |
29 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later | |
87fcac8d | 30 | */ |
31 | ||
24ba58ee PL |
32 | // require some of the sublibraries first. |
33 | // this is not an exhaustive list, the others are pulled in as they're needed | |
34 | // so we don't have to always include everything unnecessarily for performance | |
35 | ||
36 | // very lightweight list of constants. always needed and no further dependencies | |
37 | require_once($CFG->libdir . '/portfolio/constants.php'); | |
38 | // a couple of exception deinitions. always needed and no further dependencies | |
87fcac8d | 39 | require_once($CFG->libdir . '/portfolio/exceptions.php'); // exception classes used by portfolio code |
24ba58ee PL |
40 | // The base class for the caller classes. We always need this because we're either drawing a button, |
41 | // in which case the button needs to know the calling class definition, which requires the base class, | |
42 | // or we're exporting, in which case we need the caller class anyway. | |
43 | require_once($CFG->libdir . '/portfolio/caller.php'); | |
44 | ||
45 | // the other dependencies are included on demand: | |
46 | // libdir/portfolio/formats.php - the classes for the export formats | |
47 | // libdir/portfolio/forms.php - all portfolio form classes (requires formslib) | |
48 | // libdir/portfolio/plugin.php - the base class for the export plugins | |
49 | // libdir/portfolio/exporter.php - the exporter class | |
50 | ||
87fcac8d | 51 | |
52 | /** | |
50fcb1d8 | 53 | * use this to add a portfolio button or icon or form to a page |
54 | * | |
55 | * These class methods do not check permissions. the caller must check permissions first. | |
56 | * Later, during the export process, the caller class is instantiated and the check_permissions method is called | |
887160c7 | 57 | * If you are exporting a single file, you should always call set_format_by_file($file) |
50fcb1d8 | 58 | * |
59 | * This class can be used like this: | |
60 | * <code> | |
61 | * $button = new portfolio_add_button(); | |
62 | * $button->set_callback_options('name_of_caller_class', array('id' => 6), '/your/mod/lib.php'); | |
63 | * $button->render(PORTFOLIO_ADD_FULL_FORM, get_string('addeverythingtoportfolio', 'yourmodule')); | |
64 | * </code> | |
65 | * | |
66 | * or like this: | |
67 | * <code> | |
68 | * $button = new portfolio_add_button(array('callbackclass' => 'name_of_caller_class', 'callbackargs' => array('id' => 6), 'callbackfile' => '/your/mod/lib.php')); | |
69 | * $somehtml .= $button->to_html(PORTFOLIO_ADD_TEXT_LINK); | |
70 | * </code> | |
71 | * | |
72 | * See {@link http://docs.moodle.org/en/Development:Adding_a_Portfolio_Button_to_a_page} for more information | |
73 | * | |
74 | * @package moodlecore | |
75 | * @subpackage portfolio | |
76 | * @copyright 1999 onwards Martin Dougiamas {@link http://moodle.com} | |
77 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later | |
67a87e7d | 78 | */ |
ce09fecc | 79 | class portfolio_add_button { |
67a87e7d | 80 | |
ce09fecc | 81 | private $callbackclass; |
82 | private $callbackargs; | |
83 | private $callbackfile; | |
84 | private $formats; | |
85 | private $instances; | |
887160c7 | 86 | private $file; // for single-file exports |
67a87e7d | 87 | |
ce09fecc | 88 | /** |
89 | * constructor. either pass the options here or set them using the helper methods. | |
90 | * generally the code will be clearer if you use the helper methods. | |
91 | * | |
92 | * @param array $options keyed array of options: | |
93 | * key 'callbackclass': name of the caller class (eg forum_portfolio_caller') | |
94 | * key 'callbackargs': the array of callback arguments your caller class wants passed to it in the constructor | |
95 | * key 'callbackfile': the file containing the class definition of your caller class. | |
96 | * See set_callback_options for more information on these three. | |
97 | * key 'formats': an array of PORTFOLIO_FORMATS this caller will support | |
887160c7 | 98 | * See set_formats or set_format_by_file for more information on this. |
ce09fecc | 99 | */ |
100 | public function __construct($options=null) { | |
11ae365c | 101 | global $SESSION, $CFG; |
380a251f | 102 | $this->instances = portfolio_instances(); |
ce09fecc | 103 | if (empty($options)) { |
104 | return true; | |
105 | } | |
c95a6095 | 106 | $constructoroptions = array('callbackclass', 'callbackargs', 'callbackfile', 'formats'); |
ce09fecc | 107 | foreach ((array)$options as $key => $value) { |
108 | if (!in_array($key, $constructoroptions)) { | |
109 | throw new portfolio_button_exception('invalidbuttonproperty', 'portfolio', $key); | |
110 | } | |
111 | $this->{$key} = $value; | |
112 | } | |
a239f01e | 113 | } |
114 | ||
ce09fecc | 115 | /* |
116 | * @param string $class name of the class containing the callback functions | |
117 | * activity modules should ALWAYS use their name_portfolio_caller | |
118 | * other locations must use something unique | |
119 | * @param mixed $argarray this can be an array or hash of arguments to pass | |
120 | * back to the callback functions (passed by reference) | |
121 | * these MUST be primatives to be added as hidden form fields. | |
122 | * and the values get cleaned to PARAM_ALPHAEXT or PARAM_NUMBER or PARAM_PATH | |
123 | * @param string $file this can be autodetected if it's in the same file as your caller, | |
124 | * but often, the caller is a script.php and the class in a lib.php | |
125 | * so you can pass it here if necessary. | |
126 | * this path should be relative (ie, not include) dirroot, eg '/mod/forum/lib.php' | |
127 | */ | |
128 | public function set_callback_options($class, array $argarray, $file=null) { | |
129 | global $CFG; | |
130 | if (empty($file)) { | |
131 | $backtrace = debug_backtrace(); | |
132 | if (!array_key_exists(0, $backtrace) || !array_key_exists('file', $backtrace[0]) || !is_readable($backtrace[0]['file'])) { | |
133 | throw new portfolio_button_exception('nocallbackfile', 'portfolio'); | |
134 | } | |
135 | ||
136 | $file = substr($backtrace[0]['file'], strlen($CFG->dirroot)); | |
137 | } else if (!is_readable($CFG->dirroot . $file)) { | |
138 | throw new portfolio_button_exception('nocallbackfile', 'portfolio', $file); | |
139 | } | |
140 | $this->callbackfile = $file; | |
24ba58ee | 141 | require_once($CFG->libdir . '/portfolio/caller.php'); // require the base class first |
ce09fecc | 142 | require_once($CFG->dirroot . $file); |
143 | if (!class_exists($class)) { | |
144 | throw new portfolio_button_exception('nocallbackclass', 'portfolio', $class); | |
145 | } | |
0d06b6fd | 146 | |
147 | // this will throw exceptions | |
148 | // but should not actually do anything other than verify callbackargs | |
149 | $test = new $class($argarray); | |
150 | unset($test); | |
151 | ||
ce09fecc | 152 | $this->callbackclass = $class; |
153 | $this->callbackargs = $argarray; | |
67a87e7d | 154 | } |
155 | ||
ce09fecc | 156 | /* |
9d7432f6 | 157 | * sets the available export formats for this content |
158 | * this function will also poll the static function in the caller class | |
159 | * and make sure we're not overriding a format that has nothing to do with mimetypes | |
59dd457e | 160 | * eg if you pass IMAGE here but the caller can export LEAP2A it will keep LEAP2A as well. |
9d7432f6 | 161 | * see portfolio_most_specific_formats for more information |
162 | * | |
59dd457e | 163 | * @param array $formats if the calling code knows better than the static method on the calling class (base_supported_formats) |
ce09fecc | 164 | * eg, if it's going to be a single file, or if you know it's HTML, you can pass it here instead |
165 | * this is almost always the case so you should always use this. | |
166 | * {@see portfolio_format_from_file} for how to get the appropriate formats to pass here for uploaded files. | |
167 | */ | |
168 | public function set_formats($formats=null) { | |
169 | if (is_string($formats)) { | |
170 | $formats = array($formats); | |
171 | } | |
172 | if (empty($formats)) { | |
9d7432f6 | 173 | $formats = array(); |
ce09fecc | 174 | } |
9d7432f6 | 175 | if (empty($this->callbackclass)) { |
176 | throw new portfolio_button_exception('noclassbeforeformats', 'portfolio'); | |
d1581fc5 | 177 | } |
59dd457e | 178 | $callerformats = call_user_func(array($this->callbackclass, 'base_supported_formats')); |
9d7432f6 | 179 | $this->formats = portfolio_most_specific_formats($formats, $callerformats); |
6fdd8fa7 | 180 | } |
181 | ||
59dd457e PL |
182 | public function reset_formats() { |
183 | $this->set_formats(); | |
184 | } | |
185 | ||
186 | ||
887160c7 PL |
187 | /** |
188 | * if we already know we have exactly one file, | |
189 | * bypass set_formats and just pass the file | |
190 | * so we can detect the formats by mimetype. | |
191 | * | |
59dd457e PL |
192 | * @param stored_file $file file to set the format from |
193 | * @param mixed $extraformats any additional formats other than by mimetype | |
194 | * eg leap2a etc | |
887160c7 | 195 | */ |
59dd457e | 196 | public function set_format_by_file(stored_file $file, $extraformats=null) { |
887160c7 | 197 | $this->file = $file; |
59dd457e PL |
198 | if (is_string($extraformats)) { |
199 | $this->set_formats(array(portfolio_format_from_file($file), $extraformats)); | |
200 | } else if (is_array($extraformats)) { | |
201 | $this->set_formats(array_merge(array(portfolio_format_from_file($file)), $extraformats)); | |
202 | } else { | |
203 | $this->set_formats(portfolio_format_from_file($file)); | |
204 | } | |
887160c7 PL |
205 | } |
206 | ||
ce09fecc | 207 | /* |
208 | * echo the form/button/icon/text link to the page | |
209 | * | |
210 | * @param int $format format to display the button or form or icon or link. | |
211 | * See constants PORTFOLIO_ADD_XXX for more info. | |
212 | * optional, defaults to PORTFOLI_ADD_FULL_FORM | |
213 | * @param str $addstr string to use for the button or icon alt text or link text. | |
214 | * this is whole string, not key. optional, defaults to 'Add to portfolio'; | |
215 | */ | |
216 | public function render($format=null, $addstr=null) { | |
380a251f | 217 | echo $this->to_html($format, $addstr); |
84a44985 | 218 | } |
219 | ||
ce09fecc | 220 | /* |
221 | * returns the form/button/icon/text link as html | |
222 | * | |
223 | * @param int $format format to display the button or form or icon or link. | |
224 | * See constants PORTFOLIO_ADD_XXX for more info. | |
225 | * optional, defaults to PORTFOLI_ADD_FULL_FORM | |
226 | * @param str $addstr string to use for the button or icon alt text or link text. | |
227 | * this is whole string, not key. optional, defaults to 'Add to portfolio'; | |
228 | */ | |
229 | public function to_html($format=null, $addstr=null) { | |
add93b8f | 230 | global $CFG, $COURSE, $OUTPUT, $USER; |
ce09fecc | 231 | if (!$this->is_renderable()) { |
ed1fcf79 | 232 | return; |
233 | } | |
380a251f | 234 | if (empty($this->callbackclass) || empty($this->callbackfile)) { |
235 | throw new portfolio_button_exception('mustsetcallbackoptions', 'portfolio'); | |
ce09fecc | 236 | } |
237 | if (empty($this->formats)) { | |
238 | // use the caller defaults | |
239 | $this->set_formats(); | |
240 | } | |
241 | $formoutput = '<form method="post" action="' . $CFG->wwwroot . '/portfolio/add.php" id="portfolio-add-button">' . "\n"; | |
242 | $linkoutput = '<a href="' . $CFG->wwwroot . '/portfolio/add.php?'; | |
243 | foreach ($this->callbackargs as $key => $value) { | |
244 | if (!empty($value) && !is_string($value) && !is_numeric($value)) { | |
245 | $a->key = $key; | |
246 | $a->value = print_r($value, true); | |
247 | debugging(get_string('nonprimative', 'portfolio', $a)); | |
248 | return; | |
249 | } | |
250 | $linkoutput .= 'ca_' . $key . '=' . $value . '&'; | |
251 | $formoutput .= "\n" . '<input type="hidden" name="ca_' . $key . '" value="' . $value . '" />'; | |
252 | } | |
766d61cb | 253 | $formoutput .= "\n" . '<input type="hidden" name="sesskey" value="' . sesskey() . '" />'; |
254 | $linkoutput .= 'sesskey=' . sesskey() . '&'; | |
ce09fecc | 255 | $formoutput .= "\n" . '<input type="hidden" name="callbackfile" value="' . $this->callbackfile . '" />'; |
256 | $formoutput .= "\n" . '<input type="hidden" name="callbackclass" value="' . $this->callbackclass . '" />'; | |
257 | $formoutput .= "\n" . '<input type="hidden" name="course" value="' . (!empty($COURSE) ? $COURSE->id : 0) . '" />'; | |
59dd457e | 258 | $formoutput .= "\n" . '<input type="hidden" name="callerformats" value="' . implode(',', $this->formats) . '" />'; |
ce09fecc | 259 | $linkoutput .= 'callbackfile=' . $this->callbackfile . '&callbackclass=' |
59dd457e PL |
260 | . $this->callbackclass . '&course=' . (!empty($COURSE) ? $COURSE->id : 0) |
261 | . '&callerformats=' . implode(',', $this->formats); | |
ce09fecc | 262 | $selectoutput = ''; |
263 | if (count($this->instances) == 1) { | |
6be1dcae | 264 | $tmp = array_values($this->instances); |
265 | $instance = $tmp[0]; | |
c95a6095 | 266 | |
ce09fecc | 267 | $formats = portfolio_supported_formats_intersect($this->formats, $instance->supported_formats()); |
268 | if (count($formats) == 0) { | |
269 | // bail. no common formats. | |
add93b8f | 270 | debugging(get_string('nocommonformats', 'portfolio', (object)array('location' => $this->callbackclass, 'formats' => implode(',', $this->formats)))); |
ce09fecc | 271 | return; |
272 | } | |
273 | if ($error = portfolio_instance_sanity_check($instance)) { | |
274 | // bail, plugin is misconfigured | |
275 | debugging(get_string('instancemisconfigured', 'portfolio', get_string($error[$instance->get('id')], 'portfolio_' . $instance->get('plugin')))); | |
276 | return; | |
277 | } | |
24ba58ee | 278 | if (!$instance->allows_multiple_exports() && $already = portfolio_existing_exports($USER->id, $instance->get('plugin'))) { |
c95a6095 PL |
279 | debugging(get_string('singleinstancenomultiallowed', 'portfolio')); |
280 | return; | |
281 | } | |
887160c7 PL |
282 | if ($this->file && $this->file instanceof stored_file && !$instance->file_mime_check($this->file->get_mimetype())) { |
283 | // bail, we have a specific file and this plugin doesn't support it | |
add93b8f | 284 | debugging(get_string('mimecheckfail', 'portfolio', (object)array('plugin' => $instance->get('plugin'), 'mimetype' => $this->file->get_mimetype()))); |
887160c7 PL |
285 | return; |
286 | } | |
ce09fecc | 287 | $formoutput .= "\n" . '<input type="hidden" name="instance" value="' . $instance->get('id') . '" />'; |
288 | $linkoutput .= '&instance=' . $instance->get('id'); | |
289 | } | |
290 | else { | |
887160c7 | 291 | if (!$selectoutput = portfolio_instance_select($this->instances, $this->formats, $this->file, $this->callbackclass, 'instance', true)) { |
3ec8d786 PL |
292 | return; |
293 | } | |
ed1fcf79 | 294 | } |
67a87e7d | 295 | |
ce09fecc | 296 | if (empty($addstr)) { |
297 | $addstr = get_string('addtoportfolio', 'portfolio'); | |
298 | } | |
299 | if (empty($format)) { | |
300 | $format = PORTFOLIO_ADD_FULL_FORM; | |
301 | } | |
302 | switch ($format) { | |
303 | case PORTFOLIO_ADD_FULL_FORM: | |
304 | $formoutput .= $selectoutput; | |
305 | $formoutput .= "\n" . '<input type="submit" value="' . $addstr .'" />'; | |
306 | $formoutput .= "\n" . '</form>'; | |
307 | break; | |
308 | case PORTFOLIO_ADD_ICON_FORM: | |
309 | $formoutput .= $selectoutput; | |
f2a1963c | 310 | $formoutput .= "\n" . '<input type="image" src="' . $OUTPUT->old_icon_url('t/portfolio') . '" alt=' . $addstr .'" />'; |
ce09fecc | 311 | $formoutput .= "\n" . '</form>'; |
312 | break; | |
313 | case PORTFOLIO_ADD_ICON_LINK: | |
f2a1963c | 314 | $linkoutput .= '"><img src="' . $OUTPUT->old_icon_url('t/portfolio') . '" alt=' . $addstr .'" /></a>'; |
ce09fecc | 315 | break; |
316 | case PORTFOLIO_ADD_TEXT_LINK: | |
317 | $linkoutput .= '">' . $addstr .'</a>'; | |
318 | break; | |
319 | default: | |
320 | debugging(get_string('invalidaddformat', 'portfolio', $format)); | |
321 | } | |
322 | $output = (in_array($format, array(PORTFOLIO_ADD_FULL_FORM, PORTFOLIO_ADD_ICON_FORM)) ? $formoutput : $linkoutput); | |
323 | return $output; | |
349242a3 | 324 | } |
67a87e7d | 325 | |
ce09fecc | 326 | /** |
327 | * does some internal checks | |
328 | * these are not errors, just situations | |
329 | * where it's not appropriate to add the button | |
330 | */ | |
331 | private function is_renderable() { | |
332 | global $CFG; | |
333 | if (empty($CFG->enableportfolios)) { | |
334 | return false; | |
67a87e7d | 335 | } |
ce09fecc | 336 | if (defined('PORTFOLIO_INTERNAL')) { |
337 | // something somewhere has detected a risk of this being called during inside the preparation | |
338 | // eg forum_print_attachments | |
339 | return false; | |
67a87e7d | 340 | } |
380a251f | 341 | if (empty($this->instances) || count($this->instances) == 0) { |
ce09fecc | 342 | return false; |
67a87e7d | 343 | } |
ce09fecc | 344 | return true; |
67a87e7d | 345 | } |
ef6f0f60 | 346 | |
347 | /** | |
348 | * Getter for $format property | |
349 | * @return array | |
350 | */ | |
351 | public function get_formats() { | |
352 | return $this->formats; | |
353 | } | |
354 | ||
355 | /** | |
356 | * Getter for $callbackargs property | |
357 | * @return array | |
358 | */ | |
359 | public function get_callbackargs() { | |
360 | return $this->callbackargs; | |
361 | } | |
362 | ||
363 | /** | |
364 | * Getter for $callbackfile property | |
365 | * @return array | |
366 | */ | |
367 | public function get_callbackfile() { | |
368 | return $this->callbackfile; | |
369 | } | |
370 | ||
371 | /** | |
372 | * Getter for $callbackclass property | |
373 | * @return array | |
374 | */ | |
375 | public function get_callbackclass() { | |
376 | return $this->callbackclass; | |
377 | } | |
ce09fecc | 378 | } |
67a87e7d | 379 | |
67a87e7d | 380 | /** |
381 | * returns a drop menu with a list of available instances. | |
382 | * | |
887160c7 PL |
383 | * @param array $instances array of portfolio plugin instance objects - the instances to put in the menu |
384 | * @param array $callerformats array of PORTFOLIO_FORMAT_XXX constants - the formats the caller supports (this is used to filter plugins) | |
385 | * @param array $callbackclass the callback class name - used for debugging only for when there are no common formats | |
386 | * @param stored_file $file if we already know we have exactly one file, pass it here to do mime filtering. | |
387 | * @param string $selectname the name of the select element. Optional, defaults to instance. | |
388 | * @param boolean $return whether to print or return the output. Optional, defaults to print. | |
389 | * @param booealn $returnarray if returning, whether to return the HTML or the array of options. Optional, defaults to HTML. | |
67a87e7d | 390 | * |
391 | * @return string the html, from <select> to </select> inclusive. | |
392 | */ | |
887160c7 | 393 | function portfolio_instance_select($instances, $callerformats, $callbackclass, $file=null, $selectname='instance', $return=false, $returnarray=false) { |
c95a6095 | 394 | global $CFG, $USER; |
9eb0a772 | 395 | |
90658eef | 396 | if (empty($CFG->enableportfolios)) { |
9eb0a772 | 397 | return; |
398 | } | |
399 | ||
67a87e7d | 400 | $insane = portfolio_instance_sanity_check(); |
b816c08a | 401 | $pinsane = portfolio_plugin_sanity_check(); |
402 | ||
67a87e7d | 403 | $count = 0; |
9eb0a772 | 404 | $selectoutput = "\n" . '<select name="' . $selectname . '">' . "\n"; |
24ba58ee | 405 | $existingexports = portfolio_existing_exports_by_plugin($USER->id); |
67a87e7d | 406 | foreach ($instances as $instance) { |
349242a3 | 407 | $formats = portfolio_supported_formats_intersect($callerformats, $instance->supported_formats()); |
408 | if (count($formats) == 0) { | |
67a87e7d | 409 | // bail. no common formats. |
410 | continue; | |
411 | } | |
412 | if (array_key_exists($instance->get('id'), $insane)) { | |
413 | // bail, plugin is misconfigured | |
b816c08a | 414 | debugging(get_string('instanceismisconfigured', 'portfolio', get_string($insane[$instance->get('id')], 'portfolio_' . $instance->get('plugin')))); |
415 | continue; | |
416 | } else if (array_key_exists($instance->get('plugin'), $pinsane)) { | |
417 | // bail, plugin is misconfigured | |
418 | debugging(get_string('pluginismisconfigured', 'portfolio', get_string($pinsane[$instance->get('plugin')], 'portfolio_' . $instance->get('plugin')))); | |
67a87e7d | 419 | continue; |
420 | } | |
c95a6095 PL |
421 | if (!$instance->allows_multiple_exports() && in_array($instance->get('plugin'), $existingexports)) { |
422 | // bail, already exporting something with this plugin and it doesn't support multiple exports | |
423 | continue; | |
424 | } | |
887160c7 | 425 | if ($file && $file instanceof stored_file && !$instance->file_mime_check($file->get_mimetype())) { |
add93b8f | 426 | debugging(get_string('mimecheckfail', 'portfolio', (object)array('plugin' => $instance->get('plugin'), 'mimetype' => $this->file->get_mimetype()))); |
887160c7 PL |
427 | // bail, we have a specific file and this plugin doesn't support it |
428 | continue; | |
429 | } | |
67a87e7d | 430 | $count++; |
9eb0a772 | 431 | $selectoutput .= "\n" . '<option value="' . $instance->get('id') . '">' . $instance->get('name') . '</option>' . "\n"; |
432 | $options[$instance->get('id')] = $instance->get('name'); | |
67a87e7d | 433 | } |
434 | if (empty($count)) { | |
435 | // bail. no common formats. | |
add93b8f | 436 | debugging(get_string('nocommonformats', 'portfolio', (object)array('location' => $callbackclass, 'formats' => implode(',', $callerformats)))); |
67a87e7d | 437 | return; |
438 | } | |
439 | $selectoutput .= "\n" . "</select>\n"; | |
9eb0a772 | 440 | if (!empty($returnarray)) { |
441 | return $options; | |
442 | } | |
443 | if (!empty($return)) { | |
444 | return $selectoutput; | |
445 | } | |
446 | echo $selectoutput; | |
67a87e7d | 447 | } |
448 | ||
449 | /** | |
450 | * return all portfolio instances | |
451 | * | |
87fcac8d | 452 | * @todo check capabilities here - see MDL-15768 |
453 | * | |
454 | * @param boolean visibleonly Don't include hidden instances. Defaults to true and will be overridden to true if the next parameter is true | |
455 | * @param boolean useronly Check the visibility preferences and permissions of the logged in user. Defaults to true. | |
456 | * | |
67a87e7d | 457 | * @return array of portfolio instances (full objects, not just database records) |
458 | */ | |
459 | function portfolio_instances($visibleonly=true, $useronly=true) { | |
460 | ||
461 | global $DB, $USER; | |
462 | ||
463 | $values = array(); | |
464 | $sql = 'SELECT * FROM {portfolio_instance}'; | |
465 | ||
466 | if ($visibleonly || $useronly) { | |
467 | $values[] = 1; | |
468 | $sql .= ' WHERE visible = ?'; | |
469 | } | |
470 | if ($useronly) { | |
471 | $sql .= ' AND id NOT IN ( | |
472 | SELECT instance FROM {portfolio_instance_user} | |
473 | WHERE userid = ? AND name = ? AND value = ? | |
474 | )'; | |
475 | $values = array_merge($values, array($USER->id, 'visible', 0)); | |
476 | } | |
477 | $sql .= ' ORDER BY name'; | |
478 | ||
479 | $instances = array(); | |
480 | foreach ($DB->get_records_sql($sql, $values) as $instance) { | |
a50ef3d3 | 481 | $instances[$instance->id] = portfolio_instance($instance->id, $instance); |
67a87e7d | 482 | } |
67a87e7d | 483 | return $instances; |
484 | } | |
485 | ||
486 | /** | |
87fcac8d | 487 | * Supported formats currently in use. |
488 | * | |
489 | * Canonical place for a list of all formats | |
490 | * that portfolio plugins and callers | |
67a87e7d | 491 | * can use for exporting content |
492 | * | |
87fcac8d | 493 | * @return keyed array of all the available export formats (constant => classname) |
67a87e7d | 494 | */ |
495 | function portfolio_supported_formats() { | |
496 | return array( | |
a9ec9031 DP |
497 | PORTFOLIO_FORMAT_FILE => 'portfolio_format_file', |
498 | PORTFOLIO_FORMAT_IMAGE => 'portfolio_format_image', | |
499 | PORTFOLIO_FORMAT_RICHHTML => 'portfolio_format_richhtml', | |
500 | PORTFOLIO_FORMAT_PLAINHTML => 'portfolio_format_plainhtml', | |
501 | PORTFOLIO_FORMAT_TEXT => 'portfolio_format_text', | |
502 | PORTFOLIO_FORMAT_VIDEO => 'portfolio_format_video', | |
503 | PORTFOLIO_FORMAT_PDF => 'portfolio_format_pdf', | |
504 | PORTFOLIO_FORMAT_DOCUMENT => 'portfolio_format_document', | |
505 | PORTFOLIO_FORMAT_SPREADSHEET => 'portfolio_format_spreadsheet', | |
506 | PORTFOLIO_FORMAT_PRESENTATION => 'portfolio_format_presentation', | |
5071079c | 507 | /*PORTFOLIO_FORMAT_MBKP, */ // later |
59dd457e PL |
508 | PORTFOLIO_FORMAT_LEAP2A => 'portfolio_format_leap2a', |
509 | PORTFOLIO_FORMAT_RICH => 'portfolio_format_rich', | |
67a87e7d | 510 | ); |
511 | } | |
512 | ||
ea0de12f | 513 | /** |
87fcac8d | 514 | * Deduce export format from file mimetype |
515 | * | |
516 | * This function returns the revelant portfolio export format | |
ea0de12f | 517 | * which is used to determine which portfolio plugins can be used |
518 | * for exporting this content | |
519 | * according to the mime type of the given file | |
520 | * this only works when exporting exactly <b>one</b> file | |
521 | * | |
522 | * @param stored_file $file file to check mime type for | |
87fcac8d | 523 | * |
ea0de12f | 524 | * @return string the format constant (see PORTFOLIO_FORMAT_XXX constants) |
525 | */ | |
87fcac8d | 526 | function portfolio_format_from_file(stored_file $file) { |
24ba58ee | 527 | global $CFG; |
ea0de12f | 528 | static $alreadymatched; |
529 | if (empty($alreadymatched)) { | |
530 | $alreadymatched = array(); | |
531 | } | |
532 | if (!($file instanceof stored_file)) { | |
533 | throw new portfolio_exception('invalidfileargument', 'portfolio'); | |
534 | } | |
535 | $mimetype = $file->get_mimetype(); | |
536 | if (array_key_exists($mimetype, $alreadymatched)) { | |
537 | return $alreadymatched[$mimetype]; | |
538 | } | |
539 | $allformats = portfolio_supported_formats(); | |
24ba58ee | 540 | require_once($CFG->libdir . '/portfolio/formats.php'); |
ea0de12f | 541 | foreach ($allformats as $format => $classname) { |
542 | $supportedmimetypes = call_user_func(array($classname, 'mimetypes')); | |
543 | if (!is_array($supportedmimetypes)) { | |
544 | debugging("one of the portfolio format classes, $classname, said it supported something funny for mimetypes, should have been array..."); | |
545 | debugging(print_r($supportedmimetypes, true)); | |
546 | continue; | |
547 | } | |
548 | if (in_array($mimetype, $supportedmimetypes)) { | |
549 | $alreadymatched[$mimetype] = $format; | |
550 | return $format; | |
551 | } | |
552 | } | |
553 | return PORTFOLIO_FORMAT_FILE; // base case for files... | |
554 | } | |
555 | ||
556 | /** | |
87fcac8d | 557 | * Intersection of plugin formats and caller formats |
558 | * | |
559 | * Walks both the caller formats and portfolio plugin formats | |
ea0de12f | 560 | * and looks for matches (walking the hierarchy as well) |
561 | * and returns the intersection | |
562 | * | |
563 | * @param array $callerformats formats the caller supports | |
564 | * @param array $pluginformats formats the portfolio plugin supports | |
565 | */ | |
7812e882 | 566 | function portfolio_supported_formats_intersect($callerformats, $pluginformats) { |
24ba58ee | 567 | global $CFG; |
7812e882 | 568 | $allformats = portfolio_supported_formats(); |
569 | $intersection = array(); | |
570 | foreach ($callerformats as $cf) { | |
571 | if (!array_key_exists($cf, $allformats)) { | |
59dd457e PL |
572 | if (!portfolio_format_is_abstract($cf)) { |
573 | debugging(get_string('invalidformat', 'portfolio', $cf)); | |
574 | } | |
7812e882 | 575 | continue; |
576 | } | |
24ba58ee | 577 | require_once($CFG->libdir . '/portfolio/formats.php'); |
34035201 | 578 | $cfobj = new $allformats[$cf](); |
7812e882 | 579 | foreach ($pluginformats as $p => $pf) { |
580 | if (!array_key_exists($pf, $allformats)) { | |
59dd457e PL |
581 | if (!portfolio_format_is_abstract($pf)) { |
582 | debugging(get_string('invalidformat', 'portfolio', $pf)); | |
583 | } | |
7812e882 | 584 | unset($pluginformats[$p]); // to avoid the same warning over and over |
585 | continue; | |
586 | } | |
34035201 | 587 | if ($cfobj instanceof $allformats[$pf]) { |
7812e882 | 588 | $intersection[] = $cf; |
589 | } | |
590 | } | |
591 | } | |
592 | return $intersection; | |
593 | } | |
594 | ||
59dd457e PL |
595 | /** |
596 | * tiny helper to figure out whether a portfolio format is abstract | |
597 | * | |
598 | * @param string $format the format to test | |
599 | * | |
600 | * @retun bool | |
601 | */ | |
602 | function portfolio_format_is_abstract($format) { | |
603 | if (class_exists($format)) { | |
604 | $class = $format; | |
605 | } else if (class_exists('portfolio_format_' . $format)) { | |
606 | $class = 'portfolio_format_' . $format; | |
607 | } else { | |
608 | $allformats = portfolio_supported_formats(); | |
609 | if (array_key_exists($format, $allformats)) { | |
610 | $class = $allformats[$format]; | |
611 | } | |
612 | } | |
613 | if (empty($class)) { | |
614 | return true; // it may as well be, we can't instantiate it :) | |
615 | } | |
616 | $rc = new ReflectionClass($class); | |
617 | return $rc->isAbstract(); | |
618 | } | |
619 | ||
9d7432f6 | 620 | /** |
621 | * return the combination of the two arrays of formats with duplicates in terms of specificity removed | |
59dd457e | 622 | * and also removes conflicting formats |
9d7432f6 | 623 | * use case: a module is exporting a single file, so the general formats would be FILE and MBKP |
624 | * while the specific formats would be the specific subclass of FILE based on mime (say IMAGE) | |
625 | * and this function would return IMAGE and MBKP | |
626 | * | |
627 | * @param array $specificformats array of more specific formats (eg based on mime detection) | |
628 | * @param array $generalformats array of more general formats (usually more supported) | |
629 | * | |
630 | * @return array merged formats with dups removed | |
631 | */ | |
632 | function portfolio_most_specific_formats($specificformats, $generalformats) { | |
24ba58ee | 633 | global $CFG; |
9d7432f6 | 634 | $allformats = portfolio_supported_formats(); |
59dd457e PL |
635 | if (empty($specificformats)) { |
636 | return $generalformats; | |
637 | } else if (empty($generalformats)) { | |
638 | return $specificformats; | |
639 | } | |
9d7432f6 | 640 | foreach ($specificformats as $f) { |
641 | // look for something less specific and remove it, ie outside of the inheritance tree of the current formats. | |
642 | if (!array_key_exists($f, $allformats)) { | |
24ba58ee | 643 | if (!portfolio_format_is_abstract($f)) { |
59dd457e PL |
644 | throw new portfolio_button_exception('invalidformat', 'portfolio', $f); |
645 | } | |
9d7432f6 | 646 | } |
24ba58ee | 647 | require_once($CFG->libdir . '/portfolio/formats.php'); |
9d7432f6 | 648 | $fobj = new $allformats[$f]; |
649 | foreach ($generalformats as $key => $cf) { | |
650 | $cfclass = $allformats[$cf]; | |
59dd457e PL |
651 | if ($fobj instanceof $cfclass && $cfclass != get_class($fobj)) { |
652 | debugging("unsetting $key $cf because it's not specific enough ($f is better)"); | |
653 | unset($generalformats[$key]); | |
654 | } | |
655 | // check for conflicts | |
656 | if ($fobj->conflicts($cf)) { | |
657 | debugging("unsetting $key $cf because it conflicts with $f"); | |
658 | unset($generalformats[$key]); | |
9d7432f6 | 659 | } |
660 | } | |
59dd457e PL |
661 | //debugging('inside loop'); |
662 | //print_object($generalformats); | |
9d7432f6 | 663 | } |
59dd457e PL |
664 | |
665 | //debugging('final formats'); | |
666 | $finalformats = array_unique(array_merge(array_values($specificformats), array_values($generalformats))); | |
667 | //print_object($finalformats); | |
668 | return $finalformats; | |
9d7432f6 | 669 | } |
670 | ||
6be1dcae | 671 | /** |
672 | * helper function to return a format object from the constant | |
673 | * | |
674 | * @param string $name the constant PORTFOLIO_FORMAT_XXX | |
675 | * | |
676 | * @return portfolio_format object | |
677 | */ | |
678 | function portfolio_format_object($name) { | |
24ba58ee PL |
679 | global $CFG; |
680 | require_once($CFG->libdir . '/portfolio/formats.php'); | |
6be1dcae | 681 | $formats = portfolio_supported_formats(); |
682 | return new $formats[$name]; | |
683 | } | |
684 | ||
67a87e7d | 685 | /** |
686 | * helper function to return an instance of a plugin (with config loaded) | |
687 | * | |
87fcac8d | 688 | * @param int $instance id of instance |
689 | * @param array $record database row that corresponds to this instance | |
690 | * this is passed to avoid unnecessary lookups | |
691 | * Optional, and the record will be retrieved if null. | |
67a87e7d | 692 | * |
693 | * @return subclass of portfolio_plugin_base | |
694 | */ | |
695 | function portfolio_instance($instanceid, $record=null) { | |
696 | global $DB, $CFG; | |
697 | ||
698 | if ($record) { | |
699 | $instance = $record; | |
700 | } else { | |
701 | if (!$instance = $DB->get_record('portfolio_instance', array('id' => $instanceid))) { | |
34035201 | 702 | throw new portfolio_exception('invalidinstance', 'portfolio'); |
67a87e7d | 703 | } |
704 | } | |
24ba58ee | 705 | require_once($CFG->libdir . '/portfolio/plugin.php'); |
edf1fc35 | 706 | require_once($CFG->dirroot . '/portfolio/'. $instance->plugin . '/lib.php'); |
67a87e7d | 707 | $classname = 'portfolio_plugin_' . $instance->plugin; |
708 | return new $classname($instanceid, $instance); | |
709 | } | |
710 | ||
711 | /** | |
87fcac8d | 712 | * Helper function to call a static function on a portfolio plugin class |
713 | * | |
714 | * This will figure out the classname and require the right file and call the function. | |
67a87e7d | 715 | * you can send a variable number of arguments to this function after the first two |
716 | * and they will be passed on to the function you wish to call. | |
717 | * | |
87fcac8d | 718 | * @param string $plugin name of plugin |
67a87e7d | 719 | * @param string $function function to call |
720 | */ | |
721 | function portfolio_static_function($plugin, $function) { | |
722 | global $CFG; | |
723 | ||
724 | $pname = null; | |
725 | if (is_object($plugin) || is_array($plugin)) { | |
726 | $plugin = (object)$plugin; | |
727 | $pname = $plugin->name; | |
728 | } else { | |
729 | $pname = $plugin; | |
730 | } | |
731 | ||
732 | $args = func_get_args(); | |
733 | if (count($args) <= 2) { | |
734 | $args = array(); | |
735 | } | |
736 | else { | |
737 | array_shift($args); | |
738 | array_shift($args); | |
739 | } | |
740 | ||
24ba58ee | 741 | require_once($CFG->libdir . '/portfolio/plugin.php'); |
edf1fc35 | 742 | require_once($CFG->dirroot . '/portfolio/' . $plugin . '/lib.php'); |
67a87e7d | 743 | return call_user_func_array(array('portfolio_plugin_' . $plugin, $function), $args); |
744 | } | |
745 | ||
746 | /** | |
747 | * helper function to check all the plugins for sanity and set any insane ones to invisible. | |
748 | * | |
749 | * @param array $plugins to check (if null, defaults to all) | |
750 | * one string will work too for a single plugin. | |
751 | * | |
752 | * @return array array of insane instances (keys= id, values = reasons (keys for plugin lang) | |
753 | */ | |
754 | function portfolio_plugin_sanity_check($plugins=null) { | |
755 | global $DB; | |
756 | if (is_string($plugins)) { | |
98c8594a | 757 | $plugins = array($plugins); |
67a87e7d | 758 | } else if (empty($plugins)) { |
17da2e6f | 759 | $plugins = get_plugin_list('portfolio'); |
98c8594a | 760 | $plugins = array_keys($plugins); |
67a87e7d | 761 | } |
762 | ||
763 | $insane = array(); | |
98c8594a | 764 | foreach ($plugins as $plugin) { |
67a87e7d | 765 | if ($result = portfolio_static_function($plugin, 'plugin_sanity_check')) { |
766 | $insane[$plugin] = $result; | |
767 | } | |
768 | } | |
769 | if (empty($insane)) { | |
770 | return array(); | |
771 | } | |
772 | list($where, $params) = $DB->get_in_or_equal(array_keys($insane)); | |
773 | $where = ' plugin ' . $where; | |
774 | $DB->set_field_select('portfolio_instance', 'visible', 0, $where, $params); | |
775 | return $insane; | |
776 | } | |
777 | ||
778 | /** | |
779 | * helper function to check all the instances for sanity and set any insane ones to invisible. | |
780 | * | |
781 | * @param array $instances to check (if null, defaults to all) | |
782 | * one instance or id will work too | |
783 | * | |
784 | * @return array array of insane instances (keys= id, values = reasons (keys for plugin lang) | |
785 | */ | |
786 | function portfolio_instance_sanity_check($instances=null) { | |
787 | global $DB; | |
788 | if (empty($instances)) { | |
789 | $instances = portfolio_instances(false); | |
790 | } else if (!is_array($instances)) { | |
791 | $instances = array($instances); | |
792 | } | |
793 | ||
794 | $insane = array(); | |
795 | foreach ($instances as $instance) { | |
796 | if (is_object($instance) && !($instance instanceof portfolio_plugin_base)) { | |
797 | $instance = portfolio_instance($instance->id, $instance); | |
798 | } else if (is_numeric($instance)) { | |
799 | $instance = portfolio_instance($instance); | |
800 | } | |
801 | if (!($instance instanceof portfolio_plugin_base)) { | |
802 | debugging('something weird passed to portfolio_instance_sanity_check, not subclass or id'); | |
803 | continue; | |
804 | } | |
805 | if ($result = $instance->instance_sanity_check()) { | |
806 | $insane[$instance->get('id')] = $result; | |
807 | } | |
808 | } | |
809 | if (empty($insane)) { | |
810 | return array(); | |
811 | } | |
812 | list ($where, $params) = $DB->get_in_or_equal(array_keys($insane)); | |
813 | $where = ' id ' . $where; | |
814 | $DB->set_field_select('portfolio_instance', 'visible', 0, $where, $params); | |
b816c08a | 815 | portfolio_insane_notify_admins($insane, true); |
67a87e7d | 816 | return $insane; |
817 | } | |
818 | ||
819 | /** | |
820 | * helper function to display a table of plugins (or instances) and reasons for disabling | |
821 | * | |
822 | * @param array $insane array of insane plugins (key = plugin (or instance id), value = reason) | |
823 | * @param array $instances if reporting instances rather than whole plugins, pass the array (key = id, value = object) here | |
824 | * | |
825 | */ | |
a50ef3d3 | 826 | function portfolio_report_insane($insane, $instances=false, $return=false) { |
aa9a6867 | 827 | global $OUTPUT; |
67a87e7d | 828 | if (empty($insane)) { |
829 | return; | |
830 | } | |
831 | ||
832 | static $pluginstr; | |
833 | if (empty($pluginstr)) { | |
834 | $pluginstr = get_string('plugin', 'portfolio'); | |
835 | } | |
836 | if ($instances) { | |
837 | $headerstr = get_string('someinstancesdisabled', 'portfolio'); | |
838 | } else { | |
839 | $headerstr = get_string('somepluginsdisabled', 'portfolio'); | |
840 | } | |
841 | ||
aa9a6867 | 842 | $output = $OUTPUT->notification($headerstr, 'notifyproblem'); |
642816a6 | 843 | $table = new html_table(); |
67a87e7d | 844 | $table->head = array($pluginstr, ''); |
845 | $table->data = array(); | |
846 | foreach ($insane as $plugin => $reason) { | |
847 | if ($instances) { | |
67a87e7d | 848 | $instance = $instances[$plugin]; |
849 | $plugin = $instance->get('plugin'); | |
850 | $name = $instance->get('name'); | |
851 | } else { | |
852 | $name = $plugin; | |
853 | } | |
854 | $table->data[] = array($name, get_string($reason, 'portfolio_' . $plugin)); | |
855 | } | |
642816a6 | 856 | $output .= $OUTPUT->table($table); |
a50ef3d3 | 857 | $output .= '<br /><br /><br />'; |
858 | ||
859 | if ($return) { | |
860 | return $output; | |
861 | } | |
862 | echo $output; | |
67a87e7d | 863 | } |
864 | ||
9eb0a772 | 865 | /** |
866 | * fake the url to portfolio/add.php from data from somewhere else | |
867 | * you should use portfolio_add_button instead 99% of the time | |
868 | * | |
87fcac8d | 869 | * @param int $instanceid instanceid (optional, will force a new screen if not specified) |
870 | * @param string $classname callback classname | |
871 | * @param string $classfile file containing the callback class definition | |
872 | * @param array $callbackargs arguments to pass to the callback class | |
9eb0a772 | 873 | */ |
59dd457e | 874 | function portfolio_fake_add_url($instanceid, $classname, $classfile, $callbackargs, $formats) { |
9eb0a772 | 875 | global $CFG; |
59dd457e | 876 | $url = $CFG->wwwroot . '/portfolio/add.php?instance=' . $instanceid . '&callbackclass=' . $classname . '&callbackfile=' . $classfile . '&sesskey=' . sesskey(); |
9eb0a772 | 877 | |
878 | if (is_object($callbackargs)) { | |
879 | $callbackargs = (array)$callbackargs; | |
880 | } | |
881 | if (!is_array($callbackargs) || empty($callbackargs)) { | |
882 | return $url; | |
883 | } | |
884 | foreach ($callbackargs as $key => $value) { | |
59dd457e | 885 | $url .= '&ca_' . $key . '=' . urlencode($value); |
9eb0a772 | 886 | } |
59dd457e | 887 | $url .= '&callerformats=' . implode(',', $formats); |
9eb0a772 | 888 | return $url; |
889 | } | |
67a87e7d | 890 | |
67a87e7d | 891 | |
67a87e7d | 892 | |
87fcac8d | 893 | /** |
894 | * event handler for the portfolio_send event | |
895 | */ | |
896 | function portfolio_handle_event($eventdata) { | |
897 | global $CFG; | |
24ba58ee PL |
898 | |
899 | require_once($CFG->libdir . '/portfolio/exporter.php'); | |
87fcac8d | 900 | $exporter = portfolio_exporter::rewaken_object($eventdata); |
901 | $exporter->process_stage_package(); | |
902 | $exporter->process_stage_send(); | |
903 | $exporter->save(); | |
904 | $exporter->process_stage_cleanup(); | |
905 | return true; | |
67a87e7d | 906 | } |
907 | ||
87fcac8d | 908 | /** |
909 | * main portfolio cronjob | |
910 | * currently just cleans up expired transfer records. | |
911 | * | |
912 | * @todo add hooks in the plugins - either per instance or per plugin | |
913 | */ | |
914 | function portfolio_cron() { | |
915 | global $DB; | |
24ba58ee | 916 | require_once($CFG->libdir . '/portfolio/exporter.php'); |
87fcac8d | 917 | if ($expired = $DB->get_records_select('portfolio_tempdata', 'expirytime < ?', array(time()), '', 'id')) { |
918 | foreach ($expired as $d) { | |
2512cb35 | 919 | try { |
920 | $e = portfolio_exporter::rewaken_object($d->id); | |
921 | $e->process_stage_cleanup(true); | |
922 | } catch (Exception $e) { | |
923 | mtrade('Exception thrown in portfolio cron while cleaning up ' . $d->id . ': ' . $e->getMessage()); | |
924 | } | |
9eb0a772 | 925 | } |
192ce92b | 926 | } |
5071079c | 927 | } |
928 | ||
67a87e7d | 929 | /** |
50fcb1d8 | 930 | * helper function to rethrow a caught portfolio_exception as an export exception |
931 | * | |
932 | * used because when a portfolio_export exception is thrown the export is cancelled | |
933 | * | |
934 | * throws portfolio_export_exceptiog | |
935 | * | |
936 | * @param portfolio_exporter $exporter current exporter object | |
937 | * @param exception $exception exception to rethrow | |
938 | * | |
939 | * @return void | |
940 | */ | |
87fcac8d | 941 | function portfolio_export_rethrow_exception($exporter, $exception) { |
942 | throw new portfolio_export_exception($exporter, $exception->errorcode, $exception->module, $exception->link, $exception->a); | |
943 | } | |
67a87e7d | 944 | |
bee4bce2 | 945 | /** |
946 | * try and determine expected_time for purely file based exports | |
947 | * or exports that might include large file attachments. | |
948 | * | |
50fcb1d8 | 949 | * @global object |
bee4bce2 | 950 | * @param mixed $totest - either an array of stored_file objects or a single stored_file object |
bee4bce2 | 951 | * @return constant PORTFOLIO_TIME_XXX |
952 | */ | |
953 | function portfolio_expected_time_file($totest) { | |
954 | global $CFG; | |
955 | if ($totest instanceof stored_file) { | |
956 | $totest = array($totest); | |
957 | } | |
958 | $size = 0; | |
959 | foreach ($totest as $file) { | |
960 | if (!($file instanceof stored_file)) { | |
961 | debugging('something weird passed to portfolio_expected_time_file - not stored_file object'); | |
962 | debugging(print_r($file, true)); | |
963 | continue; | |
964 | } | |
965 | $size += $file->get_filesize(); | |
966 | } | |
967 | ||
968 | $fileinfo = portfolio_filesize_info(); | |
969 | ||
970 | $moderate = $high = 0; // avoid warnings | |
971 | ||
972 | foreach (array('moderate', 'high') as $setting) { | |
973 | $settingname = 'portfolio_' . $setting . '_filesize_threshold'; | |
974 | if (empty($CFG->{$settingname}) || !array_key_exists($CFG->{$settingname}, $fileinfo['options'])) { | |
975 | debugging("weird or unset admin value for $settingname, using default instead"); | |
976 | $$setting = $fileinfo[$setting]; | |
977 | } else { | |
978 | $$setting = $CFG->{$settingname}; | |
979 | } | |
980 | } | |
981 | ||
982 | if ($size < $moderate) { | |
983 | return PORTFOLIO_TIME_LOW; | |
984 | } else if ($size < $high) { | |
985 | return PORTFOLIO_TIME_MODERATE; | |
986 | } | |
987 | return PORTFOLIO_TIME_HIGH; | |
988 | } | |
989 | ||
990 | ||
991 | /** | |
992 | * the default filesizes and threshold information for file based transfers | |
993 | * this shouldn't need to be used outside the admin pages and the portfolio code | |
994 | */ | |
995 | function portfolio_filesize_info() { | |
996 | $filesizes = array(); | |
997 | $sizelist = array(10240, 51200, 102400, 512000, 1048576, 2097152, 5242880, 10485760, 20971520, 52428800); | |
998 | foreach ($sizelist as $size) { | |
999 | $filesizes[$size] = display_size($size); | |
1000 | } | |
1001 | return array( | |
1002 | 'options' => $filesizes, | |
1003 | 'moderate' => 1048576, | |
1004 | 'high' => 5242880, | |
1005 | ); | |
1006 | } | |
1007 | ||
1008 | /** | |
1009 | * try and determine expected_time for purely database based exports | |
1010 | * or exports that might include large parts of a database | |
1011 | * | |
50fcb1d8 | 1012 | * @global object |
bee4bce2 | 1013 | * @param integer $recordcount - number of records trying to export |
bee4bce2 | 1014 | * @return constant PORTFOLIO_TIME_XXX |
1015 | */ | |
1016 | function portfolio_expected_time_db($recordcount) { | |
1017 | global $CFG; | |
1018 | ||
1019 | if (empty($CFG->portfolio_moderate_dbsize_threshold)) { | |
1020 | set_config('portfolio_moderate_dbsize_threshold', 10); | |
1021 | } | |
1022 | if (empty($CFG->portfolio_high_dbsize_threshold)) { | |
1023 | set_config('portfolio_high_dbsize_threshold', 50); | |
1024 | } | |
1025 | if ($recordcount < $CFG->portfolio_moderate_dbsize_threshold) { | |
1026 | return PORTFOLIO_TIME_LOW; | |
1027 | } else if ($recordcount < $CFG->portfolio_high_dbsize_threshold) { | |
1028 | return PORTFOLIO_TIME_MODERATE; | |
1029 | } | |
1030 | return PORTFOLIO_TIME_HIGH; | |
1031 | } | |
67a87e7d | 1032 | |
50fcb1d8 | 1033 | /** |
1034 | * @global object | |
1035 | */ | |
b816c08a | 1036 | function portfolio_insane_notify_admins($insane, $instances=false) { |
1037 | ||
1038 | global $CFG; | |
1039 | ||
1040 | if (defined('ADMIN_EDITING_PORTFOLIO')) { | |
1041 | return true; | |
1042 | } | |
1043 | ||
1044 | $admins = get_admins(); | |
1045 | ||
1046 | if (empty($admins)) { | |
1047 | return; | |
1048 | } | |
1049 | if ($instances) { | |
1050 | $instances = portfolio_instances(false, false); | |
1051 | } | |
1052 | ||
1053 | $site = get_site(); | |
1054 | ||
1055 | $a = new StdClass; | |
1056 | $a->sitename = $site->fullname; | |
d1aa1e48 | 1057 | $a->fixurl = "$CFG->wwwroot/$CFG->admin/settings.php?section=manageportfolios"; |
b816c08a | 1058 | $a->htmllist = portfolio_report_insane($insane, $instances, true); |
1059 | $a->textlist = ''; | |
1060 | ||
1061 | foreach ($insane as $k => $reason) { | |
1062 | if ($instances) { | |
1063 | $a->textlist = $instances[$k]->get('name') . ': ' . $reason . "\n"; | |
1064 | } else { | |
1065 | $a->textlist = $k . ': ' . $reason . "\n"; | |
1066 | } | |
1067 | } | |
1068 | ||
1069 | $subject = get_string('insanesubject', 'portfolio'); | |
1070 | $plainbody = get_string('insanebody', 'portfolio', $a); | |
1071 | $htmlbody = get_string('insanebodyhtml', 'portfolio', $a); | |
1072 | $smallbody = get_string('insanebodysmall', 'portfolio', $a); | |
1073 | ||
1074 | foreach ($admins as $admin) { | |
1075 | $eventdata = new object(); | |
1076 | $eventdata->modulename = 'portfolio'; | |
1077 | $eventdata->component = 'portfolio'; | |
1078 | $eventdata->name = 'notices'; | |
1079 | $eventdata->userfrom = $admin; | |
1080 | $eventdata->userto = $admin; | |
1081 | $eventdata->subject = $subject; | |
1082 | $eventdata->fullmessage = $plainbody; | |
1083 | $eventdata->fullmessageformat = FORMAT_PLAIN; | |
1084 | $eventdata->fullmessagehtml = $htmlbody; | |
1085 | $eventdata->smallmessage = $smallbody; | |
7c7d3afa | 1086 | message_send($eventdata); |
b816c08a | 1087 | } |
1088 | } | |
f1d2641d PL |
1089 | |
1090 | function portfolio_export_pagesetup($PAGE, $caller) { | |
1091 | // for build navigation | |
1092 | if (!$course = $caller->get('course')) { | |
1093 | $course = $courseid; | |
1094 | } | |
1095 | ||
1096 | // set up the course so that build_navigation works nice | |
1097 | $PAGE->set_course($course); | |
1098 | ||
1099 | list($extranav, $cm) = $caller->get_navigation(); | |
1100 | ||
1101 | // and now we know the course for sure and maybe the cm, call require_login with it | |
1102 | // todo this will have to change when we have things exporting content outside the course context (eg blogs) | |
1103 | require_login($course, false, $cm); | |
1104 | ||
1105 | foreach ($extranav as $navitem) { | |
1106 | $PAGE->navbar->add($navitem['name']); | |
1107 | } | |
1108 | $PAGE->navbar->add(get_string('exporting', 'portfolio')); | |
1109 | } | |
b12fbe8e PL |
1110 | |
1111 | function portfolio_export_type_to_id($type, $userid) { | |
1112 | global $DB; | |
1113 | $sql = 'SELECT t.id FROM {portfolio_tempdata} t JOIN {portfolio_instance} i ON t.instance = i.id WHERE t.userid = ? AND i.plugin = ?'; | |
1114 | return $DB->get_field_sql($sql, array($userid, $type)); | |
1115 | } | |
24ba58ee PL |
1116 | |
1117 | /** | |
1118 | * return a list of current exports for the given user | |
1119 | * this will not go through and call rewaken_object, because it's heavy | |
1120 | * it's really just used to figure out what exports are currently happening. | |
1121 | * this is useful for plugins that don't support multiple exports per session | |
1122 | * | |
1123 | * @param int $userid the user to check for | |
1124 | * @param string $type (optional) the portfolio plugin to filter by | |
1125 | * | |
1126 | * @return array | |
1127 | */ | |
1128 | function portfolio_existing_exports($userid, $type=null) { | |
1129 | global $DB; | |
1130 | $sql = 'SELECT t.*,t.instance,i.plugin,i.name FROM {portfolio_tempdata} t JOIN {portfolio_instance} i ON t.instance = i.id WHERE t.userid = ? '; | |
1131 | $values = array($userid); | |
1132 | if ($type) { | |
1133 | $sql .= ' AND i.plugin = ?'; | |
1134 | $values[] = $type; | |
1135 | } | |
1136 | return $DB->get_records_sql($sql, $values); | |
1137 | } | |
1138 | ||
1139 | /** | |
1140 | * Return an array of existing exports by type for a given user. | |
1141 | * This is much more lightweight than {@see existing_exports} because it only returns the types, rather than the whole serialised data | |
1142 | * so can be used for checking availability of multiple plugins at the same time. | |
1143 | */ | |
1144 | function portfolio_existing_exports_by_plugin($userid) { | |
1145 | global $DB; | |
1146 | $sql = 'SELECT t.id,i.plugin FROM {portfolio_tempdata} t JOIN {portfolio_instance} i ON t.instance = i.id WHERE t.userid = ? '; | |
1147 | $values = array($userid); | |
1148 | return $DB->get_records_sql_menu($sql, $values); | |
1149 | } |