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