1 |
efrain |
1 |
<?php
|
|
|
2 |
// This file is part of Moodle - http://moodle.org/
|
|
|
3 |
//
|
|
|
4 |
// Moodle is free software: you can redistribute it and/or modify
|
|
|
5 |
// it under the terms of the GNU General Public License as published by
|
|
|
6 |
// the Free Software Foundation, either version 3 of the License, or
|
|
|
7 |
// (at your option) any later version.
|
|
|
8 |
//
|
|
|
9 |
// Moodle is distributed in the hope that it will be useful,
|
|
|
10 |
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
11 |
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
12 |
// GNU General Public License for more details.
|
|
|
13 |
//
|
|
|
14 |
// You should have received a copy of the GNU General Public License
|
|
|
15 |
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
|
|
16 |
|
|
|
17 |
/**
|
|
|
18 |
* This file contains all global functions to do with manipulating portfolios.
|
|
|
19 |
*
|
|
|
20 |
* Everything else that is logically namespaced by class is in its own file
|
|
|
21 |
* in lib/portfolio/ directory.
|
|
|
22 |
*
|
|
|
23 |
* Major Contributors
|
|
|
24 |
* - Penny Leach <penny@catalyst.net.nz>
|
|
|
25 |
*
|
|
|
26 |
* @package core_portfolio
|
|
|
27 |
* @category 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
|
|
|
30 |
*/
|
|
|
31 |
|
|
|
32 |
defined('MOODLE_INTERNAL') || die();
|
|
|
33 |
|
|
|
34 |
// require some of the sublibraries first.
|
|
|
35 |
// this is not an exhaustive list, the others are pulled in as they're needed
|
|
|
36 |
// so we don't have to always include everything unnecessarily for performance
|
|
|
37 |
|
|
|
38 |
// very lightweight list of constants. always needed and no further dependencies
|
|
|
39 |
require_once($CFG->libdir . '/portfolio/constants.php');
|
|
|
40 |
// a couple of exception deinitions. always needed and no further dependencies
|
|
|
41 |
require_once($CFG->libdir . '/portfolio/exceptions.php'); // exception classes used by portfolio code
|
|
|
42 |
// The base class for the caller classes. We always need this because we're either drawing a button,
|
|
|
43 |
// in which case the button needs to know the calling class definition, which requires the base class,
|
|
|
44 |
// or we're exporting, in which case we need the caller class anyway.
|
|
|
45 |
require_once($CFG->libdir . '/portfolio/caller.php');
|
|
|
46 |
|
|
|
47 |
// the other dependencies are included on demand:
|
|
|
48 |
// libdir/portfolio/formats.php - the classes for the export formats
|
|
|
49 |
// libdir/portfolio/forms.php - all portfolio form classes (requires formslib)
|
|
|
50 |
// libdir/portfolio/plugin.php - the base class for the export plugins
|
|
|
51 |
// libdir/portfolio/exporter.php - the exporter class
|
|
|
52 |
|
|
|
53 |
|
|
|
54 |
/**
|
|
|
55 |
* Use this to add a portfolio button or icon or form to a page.
|
|
|
56 |
*
|
|
|
57 |
* These class methods do not check permissions. the caller must check permissions first.
|
|
|
58 |
* Later, during the export process, the caller class is instantiated and the check_permissions method is called
|
|
|
59 |
* If you are exporting a single file, you should always call set_format_by_file($file)
|
|
|
60 |
* This class can be used like this:
|
|
|
61 |
* <code>
|
|
|
62 |
* $button = new portfolio_add_button();
|
|
|
63 |
* $button->set_callback_options('name_of_caller_class', array('id' => 6), 'yourcomponent'); eg. mod_forum
|
|
|
64 |
* $button->render(PORTFOLIO_ADD_FULL_FORM, get_string('addeverythingtoportfolio', 'yourcomponent'));
|
|
|
65 |
* </code>
|
|
|
66 |
* or like this:
|
|
|
67 |
* <code>
|
|
|
68 |
* $button = new portfolio_add_button(array('callbackclass' => 'name_of_caller_class', 'callbackargs' => array('id' => 6), 'callbackcomponent' => 'yourcomponent')); eg. mod_forum
|
|
|
69 |
* $somehtml .= $button->to_html(PORTFOLIO_ADD_TEXT_LINK);
|
|
|
70 |
* </code>
|
|
|
71 |
*
|
|
|
72 |
* @package core_portfolio
|
|
|
73 |
* @category portfolio
|
|
|
74 |
* @copyright 1999 onwards Martin Dougiamas {@link http://moodle.com}
|
|
|
75 |
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
|
|
76 |
*/
|
|
|
77 |
class portfolio_add_button {
|
|
|
78 |
|
|
|
79 |
/** @var string the name of the callback functions */
|
|
|
80 |
private $callbackclass;
|
|
|
81 |
|
|
|
82 |
/** @var array can be an array of arguments to pass back to the callback functions (passed by reference)*/
|
|
|
83 |
private $callbackargs;
|
|
|
84 |
|
|
|
85 |
/** @var string caller file */
|
|
|
86 |
private $callbackcomponent;
|
|
|
87 |
|
|
|
88 |
/** @var array array of more specific formats (eg based on mime detection) */
|
|
|
89 |
private $formats;
|
|
|
90 |
|
|
|
91 |
/** @var array array of portfolio instances */
|
|
|
92 |
private $instances;
|
|
|
93 |
|
|
|
94 |
/** @var stored_file for single-file exports */
|
|
|
95 |
private $file;
|
|
|
96 |
|
|
|
97 |
/** @var string for writing specific types of files*/
|
|
|
98 |
private $intendedmimetype;
|
|
|
99 |
|
|
|
100 |
/**
|
|
|
101 |
* Constructor. Either pass the options here or set them using the helper methods.
|
|
|
102 |
* Generally the code will be clearer if you use the helper methods.
|
|
|
103 |
*
|
|
|
104 |
* @param array $options keyed array of options:
|
|
|
105 |
* key 'callbackclass': name of the caller class (eg forum_portfolio_caller')
|
|
|
106 |
* key 'callbackargs': the array of callback arguments your caller class wants passed to it in the constructor
|
|
|
107 |
* key 'callbackcomponent': the file containing the class definition of your caller class.
|
|
|
108 |
* See set_callback_options for more information on these three.
|
|
|
109 |
* key 'formats': an array of PORTFOLIO_FORMATS this caller will support
|
|
|
110 |
* See set_formats or set_format_by_file for more information on this.
|
|
|
111 |
*/
|
|
|
112 |
public function __construct($options=null) {
|
|
|
113 |
global $SESSION, $CFG;
|
|
|
114 |
|
|
|
115 |
if (empty($CFG->enableportfolios)) {
|
|
|
116 |
debugging('Building portfolio add button while portfolios is disabled. This code can be optimised.', DEBUG_DEVELOPER);
|
|
|
117 |
}
|
|
|
118 |
|
|
|
119 |
$cache = cache::make('core', 'portfolio_add_button_portfolio_instances');
|
|
|
120 |
$instances = $cache->get('instances');
|
|
|
121 |
if ($instances === false) {
|
|
|
122 |
$instances = portfolio_instances();
|
|
|
123 |
$cache->set('instances', $instances);
|
|
|
124 |
}
|
|
|
125 |
|
|
|
126 |
$this->instances = $instances;
|
|
|
127 |
if (empty($options)) {
|
|
|
128 |
return true;
|
|
|
129 |
}
|
|
|
130 |
$constructoroptions = array('callbackclass', 'callbackargs', 'callbackcomponent');
|
|
|
131 |
foreach ((array)$options as $key => $value) {
|
|
|
132 |
if (!in_array($key, $constructoroptions)) {
|
|
|
133 |
throw new portfolio_button_exception('invalidbuttonproperty', 'portfolio', $key);
|
|
|
134 |
}
|
|
|
135 |
}
|
|
|
136 |
|
|
|
137 |
$this->set_callback_options($options['callbackclass'], $options['callbackargs'], $options['callbackcomponent']);
|
|
|
138 |
}
|
|
|
139 |
|
|
|
140 |
/**
|
|
|
141 |
* Function to set the callback options
|
|
|
142 |
*
|
|
|
143 |
* @param string $class Name of the class containing the callback functions
|
|
|
144 |
* activity components should ALWAYS use their name_portfolio_caller
|
|
|
145 |
* other locations must use something unique
|
|
|
146 |
* @param array $argarray This can be an array or hash of arguments to pass
|
|
|
147 |
* back to the callback functions (passed by reference)
|
|
|
148 |
* these MUST be primatives to be added as hidden form fields.
|
|
|
149 |
* and the values get cleaned to PARAM_ALPHAEXT or PARAM_FLOAT or PARAM_PATH
|
|
|
150 |
* @param string $component This is the name of the component in Moodle, eg 'mod_forum'
|
|
|
151 |
*/
|
|
|
152 |
public function set_callback_options($class, array $argarray, $component) {
|
|
|
153 |
global $CFG;
|
|
|
154 |
|
|
|
155 |
// Require the base class first before any other files.
|
|
|
156 |
require_once($CFG->libdir . '/portfolio/caller.php');
|
|
|
157 |
|
|
|
158 |
// Include any potential callback files and check for errors.
|
|
|
159 |
portfolio_include_callback_file($component, $class);
|
|
|
160 |
|
|
|
161 |
// This will throw exceptions but should not actually do anything other than verify callbackargs.
|
|
|
162 |
$test = new $class($argarray);
|
|
|
163 |
unset($test);
|
|
|
164 |
|
|
|
165 |
$this->callbackcomponent = $component;
|
|
|
166 |
$this->callbackclass = $class;
|
|
|
167 |
$this->callbackargs = $argarray;
|
|
|
168 |
}
|
|
|
169 |
|
|
|
170 |
/**
|
|
|
171 |
* Sets the available export formats for this content.
|
|
|
172 |
* This function will also poll the static function in the caller class
|
|
|
173 |
* and make sure we're not overriding a format that has nothing to do with mimetypes.
|
|
|
174 |
* Eg: if you pass IMAGE here but the caller can export LEAP2A it will keep LEAP2A as well.
|
|
|
175 |
* @see portfolio_most_specific_formats for more information
|
|
|
176 |
* @see portfolio_format_from_mimetype
|
|
|
177 |
*
|
|
|
178 |
* @param array $formats if the calling code knows better than the static method on the calling class (base_supported_formats).
|
|
|
179 |
* Eg: if it's going to be a single file, or if you know it's HTML, you can pass it here instead.
|
|
|
180 |
* This is almost always the case so it should be use all the times
|
|
|
181 |
* portfolio_format_from_mimetype for how to get the appropriate formats to pass here for uploaded files.
|
|
|
182 |
* or just call set_format_by_file instead
|
|
|
183 |
*/
|
|
|
184 |
public function set_formats($formats=null) {
|
|
|
185 |
if (is_string($formats)) {
|
|
|
186 |
$formats = array($formats);
|
|
|
187 |
}
|
|
|
188 |
if (empty($formats)) {
|
|
|
189 |
$formats = array();
|
|
|
190 |
}
|
|
|
191 |
if (empty($this->callbackclass)) {
|
|
|
192 |
throw new portfolio_button_exception('noclassbeforeformats', 'portfolio');
|
|
|
193 |
}
|
|
|
194 |
$callerformats = call_user_func(array($this->callbackclass, 'base_supported_formats'));
|
|
|
195 |
$this->formats = portfolio_most_specific_formats($formats, $callerformats);
|
|
|
196 |
}
|
|
|
197 |
|
|
|
198 |
/**
|
|
|
199 |
* Reset formats to the default,
|
|
|
200 |
* which is usually what base_supported_formats returns
|
|
|
201 |
*/
|
|
|
202 |
public function reset_formats() {
|
|
|
203 |
$this->set_formats();
|
|
|
204 |
}
|
|
|
205 |
|
|
|
206 |
|
|
|
207 |
/**
|
|
|
208 |
* If we already know we have exactly one file,
|
|
|
209 |
* bypass set_formats and just pass the file
|
|
|
210 |
* so we can detect the formats by mimetype.
|
|
|
211 |
*
|
|
|
212 |
* @param stored_file $file file to set the format from
|
|
|
213 |
* @param array $extraformats any additional formats other than by mimetype
|
|
|
214 |
* eg leap2a etc
|
|
|
215 |
*/
|
|
|
216 |
public function set_format_by_file(stored_file $file, $extraformats=null) {
|
|
|
217 |
$this->file = $file;
|
|
|
218 |
$fileformat = portfolio_format_from_mimetype($file->get_mimetype());
|
|
|
219 |
if (is_string($extraformats)) {
|
|
|
220 |
$extraformats = array($extraformats);
|
|
|
221 |
} else if (!is_array($extraformats)) {
|
|
|
222 |
$extraformats = array();
|
|
|
223 |
}
|
|
|
224 |
$this->set_formats(array_merge(array($fileformat), $extraformats));
|
|
|
225 |
}
|
|
|
226 |
|
|
|
227 |
/**
|
|
|
228 |
* Correllary this is use to set_format_by_file, but it is also used when there is no stored_file and
|
|
|
229 |
* when we're writing out a new type of file (like csv or pdf)
|
|
|
230 |
*
|
|
|
231 |
* @param string $extn the file extension we intend to generate
|
|
|
232 |
* @param array $extraformats any additional formats other than by mimetype
|
|
|
233 |
* eg leap2a etc
|
|
|
234 |
*/
|
|
|
235 |
public function set_format_by_intended_file($extn, $extraformats=null) {
|
|
|
236 |
$mimetype = mimeinfo('type', 'something. ' . $extn);
|
|
|
237 |
$fileformat = portfolio_format_from_mimetype($mimetype);
|
|
|
238 |
$this->intendedmimetype = $fileformat;
|
|
|
239 |
if (is_string($extraformats)) {
|
|
|
240 |
$extraformats = array($extraformats);
|
|
|
241 |
} else if (!is_array($extraformats)) {
|
|
|
242 |
$extraformats = array();
|
|
|
243 |
}
|
|
|
244 |
$this->set_formats(array_merge(array($fileformat), $extraformats));
|
|
|
245 |
}
|
|
|
246 |
|
|
|
247 |
/**
|
|
|
248 |
* Echo the form/button/icon/text link to the page
|
|
|
249 |
*
|
|
|
250 |
* @param int $format format to display the button or form or icon or link.
|
|
|
251 |
* See constants PORTFOLIO_ADD_XXX for more info.
|
|
|
252 |
* optional, defaults to PORTFOLIO_ADD_FULL_FORM
|
|
|
253 |
* @param string $addstr string to use for the button or icon alt text or link text.
|
|
|
254 |
* this is whole string, not key. optional, defaults to 'Export to portfolio';
|
|
|
255 |
*/
|
|
|
256 |
public function render($format=null, $addstr=null) {
|
|
|
257 |
echo $this->to_html($format, $addstr);
|
|
|
258 |
}
|
|
|
259 |
|
|
|
260 |
/**
|
|
|
261 |
* Returns the form/button/icon/text link as html
|
|
|
262 |
*
|
|
|
263 |
* @param int $format format to display the button or form or icon or link.
|
|
|
264 |
* See constants PORTFOLIO_ADD_XXX for more info.
|
|
|
265 |
* Optional, defaults to PORTFOLIO_ADD_FULL_FORM
|
|
|
266 |
* @param string $addstr string to use for the button or icon alt text or link text.
|
|
|
267 |
* This is whole string, not key. optional, defaults to 'Add to portfolio';
|
|
|
268 |
* @return void|string|moodle_url
|
|
|
269 |
*/
|
|
|
270 |
public function to_html($format=null, $addstr=null) {
|
|
|
271 |
global $CFG, $COURSE, $OUTPUT, $USER;
|
|
|
272 |
if (!$this->is_renderable()) {
|
|
|
273 |
return;
|
|
|
274 |
}
|
|
|
275 |
if (empty($this->callbackclass) || empty($this->callbackcomponent)) {
|
|
|
276 |
throw new portfolio_button_exception('mustsetcallbackoptions', 'portfolio');
|
|
|
277 |
}
|
|
|
278 |
if (empty($this->formats)) {
|
|
|
279 |
// use the caller defaults
|
|
|
280 |
$this->set_formats();
|
|
|
281 |
}
|
|
|
282 |
$url = new moodle_url('/portfolio/add.php');
|
|
|
283 |
foreach ($this->callbackargs as $key => $value) {
|
|
|
284 |
if (!empty($value) && !is_string($value) && !is_numeric($value)) {
|
|
|
285 |
$a = new stdClass();
|
|
|
286 |
$a->key = $key;
|
|
|
287 |
$a->value = print_r($value, true);
|
|
|
288 |
debugging(get_string('nonprimative', 'portfolio', $a));
|
|
|
289 |
return;
|
|
|
290 |
}
|
|
|
291 |
$url->param('ca_' . $key, $value);
|
|
|
292 |
}
|
|
|
293 |
$url->param('sesskey', sesskey());
|
|
|
294 |
$url->param('callbackcomponent', $this->callbackcomponent);
|
|
|
295 |
$url->param('callbackclass', $this->callbackclass);
|
|
|
296 |
$url->param('course', (!empty($COURSE)) ? $COURSE->id : 0);
|
|
|
297 |
$url->param('callerformats', implode(',', $this->formats));
|
|
|
298 |
$mimetype = null;
|
|
|
299 |
if ($this->file instanceof stored_file) {
|
|
|
300 |
$mimetype = $this->file->get_mimetype();
|
|
|
301 |
} else if ($this->intendedmimetype) {
|
|
|
302 |
$mimetype = $this->intendedmimetype;
|
|
|
303 |
}
|
|
|
304 |
$selectoutput = '';
|
|
|
305 |
if (count($this->instances) == 1) {
|
|
|
306 |
$tmp = array_values($this->instances);
|
|
|
307 |
$instance = $tmp[0];
|
|
|
308 |
|
|
|
309 |
$formats = portfolio_supported_formats_intersect($this->formats, $instance->supported_formats());
|
|
|
310 |
if (count($formats) == 0) {
|
|
|
311 |
// bail. no common formats.
|
|
|
312 |
//debugging(get_string('nocommonformats', 'portfolio', (object)array('location' => $this->callbackclass, 'formats' => implode(',', $this->formats))));
|
|
|
313 |
return;
|
|
|
314 |
}
|
|
|
315 |
if ($error = portfolio_instance_sanity_check($instance)) {
|
|
|
316 |
// bail, plugin is misconfigured
|
|
|
317 |
//debugging(get_string('instancemisconfigured', 'portfolio', get_string($error[$instance->get('id')], 'portfolio_' . $instance->get('plugin'))));
|
|
|
318 |
return;
|
|
|
319 |
}
|
|
|
320 |
if (!$instance->allows_multiple_exports() && $already = portfolio_existing_exports($USER->id, $instance->get('plugin'))) {
|
|
|
321 |
//debugging(get_string('singleinstancenomultiallowed', 'portfolio'));
|
|
|
322 |
return;
|
|
|
323 |
}
|
|
|
324 |
if ($mimetype&& !$instance->file_mime_check($mimetype)) {
|
|
|
325 |
// bail, we have a specific file or mimetype and this plugin doesn't support it
|
|
|
326 |
//debugging(get_string('mimecheckfail', 'portfolio', (object)array('plugin' => $instance->get('plugin'), 'mimetype' => $mimetype)));
|
|
|
327 |
return;
|
|
|
328 |
}
|
|
|
329 |
$url->param('instance', $instance->get('id'));
|
|
|
330 |
}
|
|
|
331 |
else {
|
|
|
332 |
if (!$selectoutput = portfolio_instance_select($this->instances, $this->formats, $this->callbackclass, $mimetype, 'instance', true)) {
|
|
|
333 |
return;
|
|
|
334 |
}
|
|
|
335 |
}
|
|
|
336 |
// If we just want a moodle_url to redirect to, do it now.
|
|
|
337 |
if ($format == PORTFOLIO_ADD_MOODLE_URL) {
|
|
|
338 |
return $url;
|
|
|
339 |
}
|
|
|
340 |
|
|
|
341 |
// if we just want a url to redirect to, do it now
|
|
|
342 |
if ($format == PORTFOLIO_ADD_FAKE_URL) {
|
|
|
343 |
return $url->out(false);
|
|
|
344 |
}
|
|
|
345 |
|
|
|
346 |
if (empty($addstr)) {
|
|
|
347 |
$addstr = get_string('addtoportfolio', 'portfolio');
|
|
|
348 |
}
|
|
|
349 |
if (empty($format)) {
|
|
|
350 |
$format = PORTFOLIO_ADD_FULL_FORM;
|
|
|
351 |
}
|
|
|
352 |
|
|
|
353 |
$formoutput = '<form method="post" action="' . $CFG->wwwroot . '/portfolio/add.php" id="portfolio-add-button">' . "\n";
|
|
|
354 |
$formoutput .= html_writer::input_hidden_params($url);
|
|
|
355 |
$linkoutput = '';
|
|
|
356 |
|
|
|
357 |
switch ($format) {
|
|
|
358 |
case PORTFOLIO_ADD_FULL_FORM:
|
|
|
359 |
$formoutput .= $selectoutput;
|
|
|
360 |
$formoutput .= "\n" . '<input type="submit" class="btn btn-secondary" value="' . $addstr .'" />';
|
|
|
361 |
$formoutput .= "\n" . '</form>';
|
|
|
362 |
break;
|
|
|
363 |
case PORTFOLIO_ADD_ICON_FORM:
|
|
|
364 |
$formoutput .= $selectoutput;
|
|
|
365 |
$formoutput .= "\n" . '<button class="portfolio-add-icon">' . $OUTPUT->pix_icon('t/portfolioadd', $addstr) . '</button>';
|
|
|
366 |
$formoutput .= "\n" . '</form>';
|
|
|
367 |
break;
|
|
|
368 |
case PORTFOLIO_ADD_ICON_LINK:
|
|
|
369 |
$linkoutput = $OUTPUT->action_icon($url, new pix_icon('t/portfolioadd', $addstr, '',
|
|
|
370 |
array('class' => 'portfolio-add-icon smallicon')));
|
|
|
371 |
break;
|
|
|
372 |
case PORTFOLIO_ADD_TEXT_LINK:
|
|
|
373 |
$linkoutput = html_writer::link($url, $addstr, array('class' => 'portfolio-add-link',
|
|
|
374 |
'title' => $addstr));
|
|
|
375 |
break;
|
|
|
376 |
default:
|
|
|
377 |
debugging(get_string('invalidaddformat', 'portfolio', $format));
|
|
|
378 |
}
|
|
|
379 |
$output = (in_array($format, array(PORTFOLIO_ADD_FULL_FORM, PORTFOLIO_ADD_ICON_FORM)) ? $formoutput : $linkoutput);
|
|
|
380 |
return $output;
|
|
|
381 |
}
|
|
|
382 |
|
|
|
383 |
/**
|
|
|
384 |
* Perform some internal checks.
|
|
|
385 |
* These are not errors, just situations
|
|
|
386 |
* where it's not appropriate to add the button
|
|
|
387 |
*
|
|
|
388 |
* @return bool
|
|
|
389 |
*/
|
|
|
390 |
private function is_renderable() {
|
|
|
391 |
global $CFG;
|
|
|
392 |
if (empty($CFG->enableportfolios)) {
|
|
|
393 |
return false;
|
|
|
394 |
}
|
|
|
395 |
if (defined('PORTFOLIO_INTERNAL')) {
|
|
|
396 |
// something somewhere has detected a risk of this being called during inside the preparation
|
|
|
397 |
// eg forum_print_attachments
|
|
|
398 |
return false;
|
|
|
399 |
}
|
|
|
400 |
if (empty($this->instances) || count($this->instances) == 0) {
|
|
|
401 |
return false;
|
|
|
402 |
}
|
|
|
403 |
return true;
|
|
|
404 |
}
|
|
|
405 |
|
|
|
406 |
/**
|
|
|
407 |
* Getter for $format property
|
|
|
408 |
*
|
|
|
409 |
* @return array
|
|
|
410 |
*/
|
|
|
411 |
public function get_formats() {
|
|
|
412 |
return $this->formats;
|
|
|
413 |
}
|
|
|
414 |
|
|
|
415 |
/**
|
|
|
416 |
* Getter for $callbackargs property
|
|
|
417 |
*
|
|
|
418 |
* @return array
|
|
|
419 |
*/
|
|
|
420 |
public function get_callbackargs() {
|
|
|
421 |
return $this->callbackargs;
|
|
|
422 |
}
|
|
|
423 |
|
|
|
424 |
/**
|
|
|
425 |
* Getter for $callbackcomponent property
|
|
|
426 |
*
|
|
|
427 |
* @return string
|
|
|
428 |
*/
|
|
|
429 |
public function get_callbackcomponent() {
|
|
|
430 |
return $this->callbackcomponent;
|
|
|
431 |
}
|
|
|
432 |
|
|
|
433 |
/**
|
|
|
434 |
* Getter for $callbackclass property
|
|
|
435 |
*
|
|
|
436 |
* @return string
|
|
|
437 |
*/
|
|
|
438 |
public function get_callbackclass() {
|
|
|
439 |
return $this->callbackclass;
|
|
|
440 |
}
|
|
|
441 |
}
|
|
|
442 |
|
|
|
443 |
/**
|
|
|
444 |
* Returns a drop menu with a list of available instances.
|
|
|
445 |
*
|
|
|
446 |
* @param array $instances array of portfolio plugin instance objects - the instances to put in the menu
|
|
|
447 |
* @param array $callerformats array of PORTFOLIO_FORMAT_XXX constants - the formats the caller supports (this is used to filter plugins)
|
|
|
448 |
* @param string $callbackclass the callback class name - used for debugging only for when there are no common formats
|
|
|
449 |
* @param string $mimetype if we already know we have exactly one file, or are going to write one, pass it here to do mime filtering.
|
|
|
450 |
* @param string $selectname the name of the select element. Optional, defaults to instance.
|
|
|
451 |
* @param bool $return whether to print or return the output. Optional, defaults to print.
|
|
|
452 |
* @param bool $returnarray if returning, whether to return the HTML or the array of options. Optional, defaults to HTML.
|
|
|
453 |
* @return void|array|string the html, from <select> to </select> inclusive.
|
|
|
454 |
*/
|
|
|
455 |
function portfolio_instance_select($instances, $callerformats, $callbackclass, $mimetype=null, $selectname='instance', $return=false, $returnarray=false) {
|
|
|
456 |
global $CFG, $USER;
|
|
|
457 |
|
|
|
458 |
if (empty($CFG->enableportfolios)) {
|
|
|
459 |
return;
|
|
|
460 |
}
|
|
|
461 |
|
|
|
462 |
$insane = portfolio_instance_sanity_check();
|
|
|
463 |
$pinsane = portfolio_plugin_sanity_check();
|
|
|
464 |
|
|
|
465 |
$count = 0;
|
|
|
466 |
$selectoutput = "\n" . '<label class="accesshide" for="instanceid">' . get_string('plugin', 'portfolio') . '</label>';
|
|
|
467 |
$selectoutput .= "\n" . '<select id="instanceid" name="' . $selectname . '" class="custom-select">' . "\n";
|
|
|
468 |
$existingexports = portfolio_existing_exports_by_plugin($USER->id);
|
|
|
469 |
foreach ($instances as $instance) {
|
|
|
470 |
$formats = portfolio_supported_formats_intersect($callerformats, $instance->supported_formats());
|
|
|
471 |
if (count($formats) == 0) {
|
|
|
472 |
// bail. no common formats.
|
|
|
473 |
continue;
|
|
|
474 |
}
|
|
|
475 |
if (array_key_exists($instance->get('id'), $insane)) {
|
|
|
476 |
// bail, plugin is misconfigured
|
|
|
477 |
//debugging(get_string('instanceismisconfigured', 'portfolio', get_string($insane[$instance->get('id')], 'portfolio_' . $instance->get('plugin'))));
|
|
|
478 |
continue;
|
|
|
479 |
} else if (array_key_exists($instance->get('plugin'), $pinsane)) {
|
|
|
480 |
// bail, plugin is misconfigured
|
|
|
481 |
//debugging(get_string('pluginismisconfigured', 'portfolio', get_string($pinsane[$instance->get('plugin')], 'portfolio_' . $instance->get('plugin'))));
|
|
|
482 |
continue;
|
|
|
483 |
}
|
|
|
484 |
if (!$instance->allows_multiple_exports() && in_array($instance->get('plugin'), $existingexports)) {
|
|
|
485 |
// bail, already exporting something with this plugin and it doesn't support multiple exports
|
|
|
486 |
continue;
|
|
|
487 |
}
|
|
|
488 |
if ($mimetype && !$instance->file_mime_check($mimetype)) {
|
|
|
489 |
//debugging(get_string('mimecheckfail', 'portfolio', (object)array('plugin' => $instance->get('plugin'), 'mimetype' => $mimetype())));
|
|
|
490 |
// bail, we have a specific file and this plugin doesn't support it
|
|
|
491 |
continue;
|
|
|
492 |
}
|
|
|
493 |
$count++;
|
|
|
494 |
$selectoutput .= "\n" . '<option value="' . $instance->get('id') . '">' . $instance->get('name') . '</option>' . "\n";
|
|
|
495 |
$options[$instance->get('id')] = $instance->get('name');
|
|
|
496 |
}
|
|
|
497 |
if (empty($count)) {
|
|
|
498 |
// bail. no common formats.
|
|
|
499 |
//debugging(get_string('nocommonformats', 'portfolio', (object)array('location' => $callbackclass, 'formats' => implode(',', $callerformats))));
|
|
|
500 |
return;
|
|
|
501 |
}
|
|
|
502 |
$selectoutput .= "\n" . "</select>\n";
|
|
|
503 |
if (!empty($returnarray)) {
|
|
|
504 |
return $options;
|
|
|
505 |
}
|
|
|
506 |
if (!empty($return)) {
|
|
|
507 |
return $selectoutput;
|
|
|
508 |
}
|
|
|
509 |
echo $selectoutput;
|
|
|
510 |
}
|
|
|
511 |
|
|
|
512 |
/**
|
|
|
513 |
* Return all portfolio instances
|
|
|
514 |
*
|
|
|
515 |
* @todo MDL-15768 - check capabilities here
|
|
|
516 |
* @param bool $visibleonly Don't include hidden instances. Defaults to true and will be overridden to true if the next parameter is true
|
|
|
517 |
* @param bool $useronly Check the visibility preferences and permissions of the logged in user. Defaults to true.
|
|
|
518 |
* @return array of portfolio instances (full objects, not just database records)
|
|
|
519 |
*/
|
|
|
520 |
function portfolio_instances($visibleonly=true, $useronly=true) {
|
|
|
521 |
|
|
|
522 |
global $DB, $USER;
|
|
|
523 |
|
|
|
524 |
$values = array();
|
|
|
525 |
$sql = 'SELECT * FROM {portfolio_instance}';
|
|
|
526 |
|
|
|
527 |
if ($visibleonly || $useronly) {
|
|
|
528 |
$values[] = 1;
|
|
|
529 |
$sql .= ' WHERE visible = ?';
|
|
|
530 |
}
|
|
|
531 |
if ($useronly) {
|
|
|
532 |
$sql .= ' AND id NOT IN (
|
|
|
533 |
SELECT instance FROM {portfolio_instance_user}
|
|
|
534 |
WHERE userid = ? AND name = ? AND ' . $DB->sql_compare_text('value') . ' = ?
|
|
|
535 |
)';
|
|
|
536 |
$values = array_merge($values, array($USER->id, 'visible', 0));
|
|
|
537 |
}
|
|
|
538 |
$sql .= ' ORDER BY name';
|
|
|
539 |
|
|
|
540 |
$instances = array();
|
|
|
541 |
foreach ($DB->get_records_sql($sql, $values) as $instance) {
|
|
|
542 |
$instances[$instance->id] = portfolio_instance($instance->id, $instance);
|
|
|
543 |
}
|
|
|
544 |
return $instances;
|
|
|
545 |
}
|
|
|
546 |
|
|
|
547 |
/**
|
|
|
548 |
* Return whether there are visible instances in portfolio.
|
|
|
549 |
*
|
|
|
550 |
* @return bool true when there are some visible instances.
|
|
|
551 |
*/
|
|
|
552 |
function portfolio_has_visible_instances() {
|
|
|
553 |
global $DB;
|
|
|
554 |
return $DB->record_exists('portfolio_instance', array('visible' => 1));
|
|
|
555 |
}
|
|
|
556 |
|
|
|
557 |
/**
|
|
|
558 |
* Supported formats currently in use.
|
|
|
559 |
* Canonical place for a list of all formats
|
|
|
560 |
* that portfolio plugins and callers
|
|
|
561 |
* can use for exporting content
|
|
|
562 |
*
|
|
|
563 |
* @return array keyed array of all the available export formats (constant => classname)
|
|
|
564 |
*/
|
|
|
565 |
function portfolio_supported_formats() {
|
|
|
566 |
return array(
|
|
|
567 |
PORTFOLIO_FORMAT_FILE => 'portfolio_format_file',
|
|
|
568 |
PORTFOLIO_FORMAT_IMAGE => 'portfolio_format_image',
|
|
|
569 |
PORTFOLIO_FORMAT_RICHHTML => 'portfolio_format_richhtml',
|
|
|
570 |
PORTFOLIO_FORMAT_PLAINHTML => 'portfolio_format_plainhtml',
|
|
|
571 |
PORTFOLIO_FORMAT_TEXT => 'portfolio_format_text',
|
|
|
572 |
PORTFOLIO_FORMAT_VIDEO => 'portfolio_format_video',
|
|
|
573 |
PORTFOLIO_FORMAT_PDF => 'portfolio_format_pdf',
|
|
|
574 |
PORTFOLIO_FORMAT_DOCUMENT => 'portfolio_format_document',
|
|
|
575 |
PORTFOLIO_FORMAT_SPREADSHEET => 'portfolio_format_spreadsheet',
|
|
|
576 |
PORTFOLIO_FORMAT_PRESENTATION => 'portfolio_format_presentation',
|
|
|
577 |
/*PORTFOLIO_FORMAT_MBKP, */ // later
|
|
|
578 |
PORTFOLIO_FORMAT_LEAP2A => 'portfolio_format_leap2a',
|
|
|
579 |
PORTFOLIO_FORMAT_RICH => 'portfolio_format_rich',
|
|
|
580 |
);
|
|
|
581 |
}
|
|
|
582 |
|
|
|
583 |
/**
|
|
|
584 |
* Deduce export format from file mimetype
|
|
|
585 |
* This function returns the revelant portfolio export format
|
|
|
586 |
* which is used to determine which portfolio plugins can be used
|
|
|
587 |
* for exporting this content
|
|
|
588 |
* according to the given mime type
|
|
|
589 |
* this only works when exporting exactly <b>one</b> file, or generating a new one
|
|
|
590 |
* (like a pdf or csv export)
|
|
|
591 |
*
|
|
|
592 |
* @param string $mimetype (usually $file->get_mimetype())
|
|
|
593 |
* @return string the format constant (see PORTFOLIO_FORMAT_XXX constants)
|
|
|
594 |
*/
|
|
|
595 |
function portfolio_format_from_mimetype($mimetype) {
|
|
|
596 |
global $CFG;
|
|
|
597 |
static $alreadymatched;
|
|
|
598 |
if (empty($alreadymatched)) {
|
|
|
599 |
$alreadymatched = array();
|
|
|
600 |
}
|
|
|
601 |
if (array_key_exists($mimetype, $alreadymatched)) {
|
|
|
602 |
return $alreadymatched[$mimetype];
|
|
|
603 |
}
|
|
|
604 |
$allformats = portfolio_supported_formats();
|
|
|
605 |
require_once($CFG->libdir . '/portfolio/formats.php');
|
|
|
606 |
foreach ($allformats as $format => $classname) {
|
|
|
607 |
$supportedmimetypes = call_user_func(array($classname, 'mimetypes'));
|
|
|
608 |
if (!is_array($supportedmimetypes)) {
|
|
|
609 |
debugging("one of the portfolio format classes, $classname, said it supported something funny for mimetypes, should have been array...");
|
|
|
610 |
debugging(print_r($supportedmimetypes, true));
|
|
|
611 |
continue;
|
|
|
612 |
}
|
|
|
613 |
if (in_array($mimetype, $supportedmimetypes)) {
|
|
|
614 |
$alreadymatched[$mimetype] = $format;
|
|
|
615 |
return $format;
|
|
|
616 |
}
|
|
|
617 |
}
|
|
|
618 |
return PORTFOLIO_FORMAT_FILE; // base case for files...
|
|
|
619 |
}
|
|
|
620 |
|
|
|
621 |
/**
|
|
|
622 |
* Intersection of plugin formats and caller formats.
|
|
|
623 |
* Walks both the caller formats and portfolio plugin formats
|
|
|
624 |
* and looks for matches (walking the hierarchy as well)
|
|
|
625 |
* and returns the intersection
|
|
|
626 |
*
|
|
|
627 |
* @param array $callerformats formats the caller supports
|
|
|
628 |
* @param array $pluginformats formats the portfolio plugin supports
|
|
|
629 |
* @return array
|
|
|
630 |
*/
|
|
|
631 |
function portfolio_supported_formats_intersect($callerformats, $pluginformats) {
|
|
|
632 |
global $CFG;
|
|
|
633 |
$allformats = portfolio_supported_formats();
|
|
|
634 |
$intersection = array();
|
|
|
635 |
foreach ($callerformats as $cf) {
|
|
|
636 |
if (!array_key_exists($cf, $allformats)) {
|
|
|
637 |
if (!portfolio_format_is_abstract($cf)) {
|
|
|
638 |
debugging(get_string('invalidformat', 'portfolio', $cf));
|
|
|
639 |
}
|
|
|
640 |
continue;
|
|
|
641 |
}
|
|
|
642 |
require_once($CFG->libdir . '/portfolio/formats.php');
|
|
|
643 |
$cfobj = new $allformats[$cf]();
|
|
|
644 |
foreach ($pluginformats as $p => $pf) {
|
|
|
645 |
if (!array_key_exists($pf, $allformats)) {
|
|
|
646 |
if (!portfolio_format_is_abstract($pf)) {
|
|
|
647 |
debugging(get_string('invalidformat', 'portfolio', $pf));
|
|
|
648 |
}
|
|
|
649 |
unset($pluginformats[$p]); // to avoid the same warning over and over
|
|
|
650 |
continue;
|
|
|
651 |
}
|
|
|
652 |
if ($cfobj instanceof $allformats[$pf]) {
|
|
|
653 |
$intersection[] = $cf;
|
|
|
654 |
}
|
|
|
655 |
}
|
|
|
656 |
}
|
|
|
657 |
return $intersection;
|
|
|
658 |
}
|
|
|
659 |
|
|
|
660 |
/**
|
|
|
661 |
* Tiny helper to figure out whether a portfolio format is abstract
|
|
|
662 |
*
|
|
|
663 |
* @param string $format the format to test
|
|
|
664 |
* @return bool
|
|
|
665 |
*/
|
|
|
666 |
function portfolio_format_is_abstract($format) {
|
|
|
667 |
if (class_exists($format)) {
|
|
|
668 |
$class = $format;
|
|
|
669 |
} else if (class_exists('portfolio_format_' . $format)) {
|
|
|
670 |
$class = 'portfolio_format_' . $format;
|
|
|
671 |
} else {
|
|
|
672 |
$allformats = portfolio_supported_formats();
|
|
|
673 |
if (array_key_exists($format, $allformats)) {
|
|
|
674 |
$class = $allformats[$format];
|
|
|
675 |
}
|
|
|
676 |
}
|
|
|
677 |
if (empty($class)) {
|
|
|
678 |
return true; // it may as well be, we can't instantiate it :)
|
|
|
679 |
}
|
|
|
680 |
$rc = new ReflectionClass($class);
|
|
|
681 |
return $rc->isAbstract();
|
|
|
682 |
}
|
|
|
683 |
|
|
|
684 |
/**
|
|
|
685 |
* Return the combination of the two arrays of formats with duplicates in terms of specificity removed
|
|
|
686 |
* and also removes conflicting formats.
|
|
|
687 |
* Use case: a module is exporting a single file, so the general formats would be FILE and MBKP
|
|
|
688 |
* while the specific formats would be the specific subclass of FILE based on mime (say IMAGE)
|
|
|
689 |
* and this function would return IMAGE and MBKP
|
|
|
690 |
*
|
|
|
691 |
* @param array $specificformats array of more specific formats (eg based on mime detection)
|
|
|
692 |
* @param array $generalformats array of more general formats (usually more supported)
|
|
|
693 |
* @return array merged formats with dups removed
|
|
|
694 |
*/
|
|
|
695 |
function portfolio_most_specific_formats($specificformats, $generalformats) {
|
|
|
696 |
global $CFG;
|
|
|
697 |
$allformats = portfolio_supported_formats();
|
|
|
698 |
if (empty($specificformats)) {
|
|
|
699 |
return $generalformats;
|
|
|
700 |
} else if (empty($generalformats)) {
|
|
|
701 |
return $specificformats;
|
|
|
702 |
}
|
|
|
703 |
$removedformats = array();
|
|
|
704 |
foreach ($specificformats as $k => $f) {
|
|
|
705 |
// look for something less specific and remove it, ie outside of the inheritance tree of the current formats.
|
|
|
706 |
if (!array_key_exists($f, $allformats)) {
|
|
|
707 |
if (!portfolio_format_is_abstract($f)) {
|
|
|
708 |
throw new portfolio_button_exception('invalidformat', 'portfolio', $f);
|
|
|
709 |
}
|
|
|
710 |
}
|
|
|
711 |
if (in_array($f, $removedformats)) {
|
|
|
712 |
// already been removed from the general list
|
|
|
713 |
//debugging("skipping $f because it was already removed");
|
|
|
714 |
unset($specificformats[$k]);
|
|
|
715 |
}
|
|
|
716 |
require_once($CFG->libdir . '/portfolio/formats.php');
|
|
|
717 |
$fobj = new $allformats[$f];
|
|
|
718 |
foreach ($generalformats as $key => $cf) {
|
|
|
719 |
if (in_array($cf, $removedformats)) {
|
|
|
720 |
//debugging("skipping $cf because it was already removed");
|
|
|
721 |
continue;
|
|
|
722 |
}
|
|
|
723 |
$cfclass = $allformats[$cf];
|
|
|
724 |
$cfobj = new $allformats[$cf];
|
|
|
725 |
if ($fobj instanceof $cfclass && $cfclass != get_class($fobj)) {
|
|
|
726 |
//debugging("unsetting $key $cf because it's not specific enough ($f is better)");
|
|
|
727 |
unset($generalformats[$key]);
|
|
|
728 |
$removedformats[] = $cf;
|
|
|
729 |
continue;
|
|
|
730 |
}
|
|
|
731 |
// check for conflicts
|
|
|
732 |
if ($fobj->conflicts($cf)) {
|
|
|
733 |
//debugging("unsetting $key $cf because it conflicts with $f");
|
|
|
734 |
unset($generalformats[$key]);
|
|
|
735 |
$removedformats[] = $cf;
|
|
|
736 |
continue;
|
|
|
737 |
}
|
|
|
738 |
if ($cfobj->conflicts($f)) {
|
|
|
739 |
//debugging("unsetting $key $cf because it reverse-conflicts with $f");
|
|
|
740 |
$removedformats[] = $cf;
|
|
|
741 |
unset($generalformats[$key]);
|
|
|
742 |
continue;
|
|
|
743 |
}
|
|
|
744 |
}
|
|
|
745 |
//debugging('inside loop');
|
|
|
746 |
//print_object($generalformats);
|
|
|
747 |
}
|
|
|
748 |
|
|
|
749 |
//debugging('final formats');
|
|
|
750 |
$finalformats = array_unique(array_merge(array_values($specificformats), array_values($generalformats)));
|
|
|
751 |
//print_object($finalformats);
|
|
|
752 |
return $finalformats;
|
|
|
753 |
}
|
|
|
754 |
|
|
|
755 |
/**
|
|
|
756 |
* Helper function to return a format object from the constant
|
|
|
757 |
*
|
|
|
758 |
* @param string $name the constant PORTFOLIO_FORMAT_XXX
|
|
|
759 |
* @return portfolio_format
|
|
|
760 |
*/
|
|
|
761 |
function portfolio_format_object($name) {
|
|
|
762 |
global $CFG;
|
|
|
763 |
require_once($CFG->libdir . '/portfolio/formats.php');
|
|
|
764 |
$formats = portfolio_supported_formats();
|
|
|
765 |
return new $formats[$name];
|
|
|
766 |
}
|
|
|
767 |
|
|
|
768 |
/**
|
|
|
769 |
* Helper function to return an instance of a plugin (with config loaded)
|
|
|
770 |
*
|
|
|
771 |
* @param int $instanceid id of instance
|
|
|
772 |
* @param object $record database row that corresponds to this instance
|
|
|
773 |
* this is passed to avoid unnecessary lookups
|
|
|
774 |
* Optional, and the record will be retrieved if null.
|
|
|
775 |
* @return object of portfolio_plugin_XXX
|
|
|
776 |
*/
|
|
|
777 |
function portfolio_instance($instanceid, $record=null) {
|
|
|
778 |
global $DB, $CFG;
|
|
|
779 |
|
|
|
780 |
if ($record) {
|
|
|
781 |
$instance = $record;
|
|
|
782 |
} else {
|
|
|
783 |
if (!$instance = $DB->get_record('portfolio_instance', array('id' => $instanceid))) {
|
|
|
784 |
throw new portfolio_exception('invalidinstance', 'portfolio');
|
|
|
785 |
}
|
|
|
786 |
}
|
|
|
787 |
require_once($CFG->libdir . '/portfolio/plugin.php');
|
|
|
788 |
require_once($CFG->dirroot . '/portfolio/'. $instance->plugin . '/lib.php');
|
|
|
789 |
$classname = 'portfolio_plugin_' . $instance->plugin;
|
|
|
790 |
return new $classname($instanceid, $instance);
|
|
|
791 |
}
|
|
|
792 |
|
|
|
793 |
/**
|
|
|
794 |
* Helper function to call a static function on a portfolio plugin class.
|
|
|
795 |
* This will figure out the classname and require the right file and call the function.
|
|
|
796 |
* You can send a variable number of arguments to this function after the first two
|
|
|
797 |
* and they will be passed on to the function you wish to call.
|
|
|
798 |
*
|
|
|
799 |
* @param string $plugin name of plugin
|
|
|
800 |
* @param string $function function to call
|
|
|
801 |
* @return mixed
|
|
|
802 |
*/
|
|
|
803 |
function portfolio_static_function($plugin, $function) {
|
|
|
804 |
global $CFG;
|
|
|
805 |
|
|
|
806 |
$pname = null;
|
|
|
807 |
if (is_object($plugin) || is_array($plugin)) {
|
|
|
808 |
$plugin = (object)$plugin;
|
|
|
809 |
$pname = $plugin->name;
|
|
|
810 |
} else {
|
|
|
811 |
$pname = $plugin;
|
|
|
812 |
}
|
|
|
813 |
|
|
|
814 |
$args = func_get_args();
|
|
|
815 |
if (count($args) <= 2) {
|
|
|
816 |
$args = array();
|
|
|
817 |
}
|
|
|
818 |
else {
|
|
|
819 |
array_shift($args);
|
|
|
820 |
array_shift($args);
|
|
|
821 |
}
|
|
|
822 |
|
|
|
823 |
require_once($CFG->libdir . '/portfolio/plugin.php');
|
|
|
824 |
require_once($CFG->dirroot . '/portfolio/' . $plugin . '/lib.php');
|
|
|
825 |
return call_user_func_array(array('portfolio_plugin_' . $plugin, $function), $args);
|
|
|
826 |
}
|
|
|
827 |
|
|
|
828 |
/**
|
|
|
829 |
* Helper function to check all the plugins for sanity and set any insane ones to invisible.
|
|
|
830 |
*
|
|
|
831 |
* @param array $plugins array of supported plugin types
|
|
|
832 |
* @return array array of insane instances (keys= id, values = reasons (keys for plugin lang)
|
|
|
833 |
*/
|
|
|
834 |
function portfolio_plugin_sanity_check($plugins=null) {
|
|
|
835 |
global $DB;
|
|
|
836 |
if (is_string($plugins)) {
|
|
|
837 |
$plugins = array($plugins);
|
|
|
838 |
} else if (empty($plugins)) {
|
|
|
839 |
$plugins = core_component::get_plugin_list('portfolio');
|
|
|
840 |
$plugins = array_keys($plugins);
|
|
|
841 |
}
|
|
|
842 |
|
|
|
843 |
$insane = array();
|
|
|
844 |
foreach ($plugins as $plugin) {
|
|
|
845 |
if ($result = portfolio_static_function($plugin, 'plugin_sanity_check')) {
|
|
|
846 |
$insane[$plugin] = $result;
|
|
|
847 |
}
|
|
|
848 |
}
|
|
|
849 |
if (empty($insane)) {
|
|
|
850 |
return array();
|
|
|
851 |
}
|
|
|
852 |
list($where, $params) = $DB->get_in_or_equal(array_keys($insane));
|
|
|
853 |
$where = ' plugin ' . $where;
|
|
|
854 |
$DB->set_field_select('portfolio_instance', 'visible', 0, $where, $params);
|
|
|
855 |
return $insane;
|
|
|
856 |
}
|
|
|
857 |
|
|
|
858 |
/**
|
|
|
859 |
* Helper function to check all the instances for sanity and set any insane ones to invisible.
|
|
|
860 |
*
|
|
|
861 |
* @param array $instances array of plugin instances
|
|
|
862 |
* @return array array of insane instances (keys= id, values = reasons (keys for plugin lang)
|
|
|
863 |
*/
|
|
|
864 |
function portfolio_instance_sanity_check($instances=null) {
|
|
|
865 |
global $DB;
|
|
|
866 |
if (empty($instances)) {
|
|
|
867 |
$instances = portfolio_instances(false);
|
|
|
868 |
} else if (!is_array($instances)) {
|
|
|
869 |
$instances = array($instances);
|
|
|
870 |
}
|
|
|
871 |
|
|
|
872 |
$insane = array();
|
|
|
873 |
foreach ($instances as $instance) {
|
|
|
874 |
if (is_object($instance) && !($instance instanceof portfolio_plugin_base)) {
|
|
|
875 |
$instance = portfolio_instance($instance->id, $instance);
|
|
|
876 |
} else if (is_numeric($instance)) {
|
|
|
877 |
$instance = portfolio_instance($instance);
|
|
|
878 |
}
|
|
|
879 |
if (!($instance instanceof portfolio_plugin_base)) {
|
|
|
880 |
debugging('something weird passed to portfolio_instance_sanity_check, not subclass or id');
|
|
|
881 |
continue;
|
|
|
882 |
}
|
|
|
883 |
if ($result = $instance->instance_sanity_check()) {
|
|
|
884 |
$insane[$instance->get('id')] = $result;
|
|
|
885 |
}
|
|
|
886 |
}
|
|
|
887 |
if (empty($insane)) {
|
|
|
888 |
return array();
|
|
|
889 |
}
|
|
|
890 |
list ($where, $params) = $DB->get_in_or_equal(array_keys($insane));
|
|
|
891 |
$where = ' id ' . $where;
|
|
|
892 |
$DB->set_field_select('portfolio_instance', 'visible', 0, $where, $params);
|
|
|
893 |
portfolio_insane_notify_admins($insane, true);
|
|
|
894 |
return $insane;
|
|
|
895 |
}
|
|
|
896 |
|
|
|
897 |
/**
|
|
|
898 |
* Helper function to display a table of plugins (or instances) and reasons for disabling
|
|
|
899 |
*
|
|
|
900 |
* @param array $insane array of portfolio plugin
|
|
|
901 |
* @param array $instances if reporting instances rather than whole plugins, pass the array (key = id, value = object) here
|
|
|
902 |
* @param bool $return option to deliver the report in html format or print it out directly to the page.
|
|
|
903 |
* @return void|string of portfolio report in html table format
|
|
|
904 |
*/
|
|
|
905 |
function portfolio_report_insane($insane, $instances=false, $return=false) {
|
|
|
906 |
global $OUTPUT;
|
|
|
907 |
if (empty($insane)) {
|
|
|
908 |
return;
|
|
|
909 |
}
|
|
|
910 |
|
|
|
911 |
static $pluginstr;
|
|
|
912 |
if (empty($pluginstr)) {
|
|
|
913 |
$pluginstr = get_string('plugin', 'portfolio');
|
|
|
914 |
}
|
|
|
915 |
if ($instances) {
|
|
|
916 |
$headerstr = get_string('someinstancesdisabled', 'portfolio');
|
|
|
917 |
} else {
|
|
|
918 |
$headerstr = get_string('somepluginsdisabled', 'portfolio');
|
|
|
919 |
}
|
|
|
920 |
|
|
|
921 |
$output = $OUTPUT->notification($headerstr, 'notifyproblem');
|
|
|
922 |
$table = new html_table();
|
|
|
923 |
$table->head = array($pluginstr, '');
|
|
|
924 |
$table->data = array();
|
|
|
925 |
foreach ($insane as $plugin => $reason) {
|
|
|
926 |
if ($instances) {
|
|
|
927 |
$instance = $instances[$plugin];
|
|
|
928 |
$plugin = $instance->get('plugin');
|
|
|
929 |
$name = $instance->get('name');
|
|
|
930 |
} else {
|
|
|
931 |
$name = $plugin;
|
|
|
932 |
}
|
|
|
933 |
$table->data[] = array($name, get_string($reason, 'portfolio_' . $plugin));
|
|
|
934 |
}
|
|
|
935 |
$output .= html_writer::table($table);
|
|
|
936 |
$output .= '<br /><br /><br />';
|
|
|
937 |
|
|
|
938 |
if ($return) {
|
|
|
939 |
return $output;
|
|
|
940 |
}
|
|
|
941 |
echo $output;
|
|
|
942 |
}
|
|
|
943 |
|
|
|
944 |
/**
|
|
|
945 |
* Helper function to rethrow a caught portfolio_exception as an export exception.
|
|
|
946 |
* Used because when a portfolio_export exception is thrown the export is cancelled
|
|
|
947 |
* throws portfolio_export_exceptiog
|
|
|
948 |
*
|
|
|
949 |
* @param portfolio_exporter $exporter current exporter object
|
|
|
950 |
* @param object $exception exception to rethrow
|
|
|
951 |
*/
|
|
|
952 |
function portfolio_export_rethrow_exception($exporter, $exception) {
|
|
|
953 |
throw new portfolio_export_exception($exporter, $exception->errorcode, $exception->module, $exception->link, $exception->a);
|
|
|
954 |
}
|
|
|
955 |
|
|
|
956 |
/**
|
|
|
957 |
* Try and determine expected_time for purely file based exports
|
|
|
958 |
* or exports that might include large file attachments.
|
|
|
959 |
*
|
|
|
960 |
* @param stored_file|array $totest - either an array of stored_file objects or a single stored_file object
|
|
|
961 |
* @return string PORTFOLIO_TIME_XXX
|
|
|
962 |
*/
|
|
|
963 |
function portfolio_expected_time_file($totest) {
|
|
|
964 |
global $CFG;
|
|
|
965 |
if ($totest instanceof stored_file) {
|
|
|
966 |
$totest = array($totest);
|
|
|
967 |
}
|
|
|
968 |
$size = 0;
|
|
|
969 |
foreach ($totest as $file) {
|
|
|
970 |
if (!($file instanceof stored_file)) {
|
|
|
971 |
debugging('something weird passed to portfolio_expected_time_file - not stored_file object');
|
|
|
972 |
debugging(print_r($file, true));
|
|
|
973 |
continue;
|
|
|
974 |
}
|
|
|
975 |
$size += $file->get_filesize();
|
|
|
976 |
}
|
|
|
977 |
|
|
|
978 |
$fileinfo = portfolio_filesize_info();
|
|
|
979 |
|
|
|
980 |
$moderate = $high = 0; // avoid warnings
|
|
|
981 |
|
|
|
982 |
foreach (array('moderate', 'high') as $setting) {
|
|
|
983 |
$settingname = 'portfolio_' . $setting . '_filesize_threshold';
|
|
|
984 |
if (empty($CFG->{$settingname}) || !array_key_exists($CFG->{$settingname}, $fileinfo['options'])) {
|
|
|
985 |
debugging("weird or unset admin value for $settingname, using default instead");
|
|
|
986 |
$$setting = $fileinfo[$setting];
|
|
|
987 |
} else {
|
|
|
988 |
$$setting = $CFG->{$settingname};
|
|
|
989 |
}
|
|
|
990 |
}
|
|
|
991 |
|
|
|
992 |
if ($size < $moderate) {
|
|
|
993 |
return PORTFOLIO_TIME_LOW;
|
|
|
994 |
} else if ($size < $high) {
|
|
|
995 |
return PORTFOLIO_TIME_MODERATE;
|
|
|
996 |
}
|
|
|
997 |
return PORTFOLIO_TIME_HIGH;
|
|
|
998 |
}
|
|
|
999 |
|
|
|
1000 |
|
|
|
1001 |
/**
|
|
|
1002 |
* The default filesizes and threshold information for file based transfers.
|
|
|
1003 |
* This shouldn't need to be used outside the admin pages and the portfolio code
|
|
|
1004 |
*
|
|
|
1005 |
* @return array
|
|
|
1006 |
*/
|
|
|
1007 |
function portfolio_filesize_info() {
|
|
|
1008 |
$filesizes = array();
|
|
|
1009 |
$sizelist = array(10240, 51200, 102400, 512000, 1048576, 2097152, 5242880, 10485760, 20971520, 52428800);
|
|
|
1010 |
foreach ($sizelist as $size) {
|
|
|
1011 |
$filesizes[$size] = display_size($size, 0);
|
|
|
1012 |
}
|
|
|
1013 |
return array(
|
|
|
1014 |
'options' => $filesizes,
|
|
|
1015 |
'moderate' => 1048576,
|
|
|
1016 |
'high' => 5242880,
|
|
|
1017 |
);
|
|
|
1018 |
}
|
|
|
1019 |
|
|
|
1020 |
/**
|
|
|
1021 |
* Try and determine expected_time for purely database based exports
|
|
|
1022 |
* or exports that might include large parts of a database.
|
|
|
1023 |
*
|
|
|
1024 |
* @param int $recordcount number of records trying to export
|
|
|
1025 |
* @return string PORTFOLIO_TIME_XXX
|
|
|
1026 |
*/
|
|
|
1027 |
function portfolio_expected_time_db($recordcount) {
|
|
|
1028 |
global $CFG;
|
|
|
1029 |
|
|
|
1030 |
if (empty($CFG->portfolio_moderate_db_threshold)) {
|
|
|
1031 |
set_config('portfolio_moderate_db_threshold', 20);
|
|
|
1032 |
}
|
|
|
1033 |
if (empty($CFG->portfolio_high_db_threshold)) {
|
|
|
1034 |
set_config('portfolio_high_db_threshold', 50);
|
|
|
1035 |
}
|
|
|
1036 |
if ($recordcount < $CFG->portfolio_moderate_db_threshold) {
|
|
|
1037 |
return PORTFOLIO_TIME_LOW;
|
|
|
1038 |
} else if ($recordcount < $CFG->portfolio_high_db_threshold) {
|
|
|
1039 |
return PORTFOLIO_TIME_MODERATE;
|
|
|
1040 |
}
|
|
|
1041 |
return PORTFOLIO_TIME_HIGH;
|
|
|
1042 |
}
|
|
|
1043 |
|
|
|
1044 |
/**
|
|
|
1045 |
* Function to send portfolio report to admins
|
|
|
1046 |
*
|
|
|
1047 |
* @param array $insane array of insane plugins
|
|
|
1048 |
* @param bool $instances (optional) if reporting instances rather than whole plugins
|
|
|
1049 |
*/
|
|
|
1050 |
function portfolio_insane_notify_admins($insane, $instances=false) {
|
|
|
1051 |
|
|
|
1052 |
global $CFG;
|
|
|
1053 |
|
|
|
1054 |
if (defined('ADMIN_EDITING_PORTFOLIO')) {
|
|
|
1055 |
return true;
|
|
|
1056 |
}
|
|
|
1057 |
|
|
|
1058 |
$admins = get_admins();
|
|
|
1059 |
|
|
|
1060 |
if (empty($admins)) {
|
|
|
1061 |
return;
|
|
|
1062 |
}
|
|
|
1063 |
if ($instances) {
|
|
|
1064 |
$instances = portfolio_instances(false, false);
|
|
|
1065 |
}
|
|
|
1066 |
|
|
|
1067 |
$site = get_site();
|
|
|
1068 |
|
|
|
1069 |
$a = new StdClass;
|
|
|
1070 |
$a->sitename = format_string($site->fullname, true, array('context' => context_course::instance(SITEID)));
|
|
|
1071 |
$a->fixurl = "$CFG->wwwroot/$CFG->admin/settings.php?section=manageportfolios";
|
|
|
1072 |
$a->htmllist = portfolio_report_insane($insane, $instances, true);
|
|
|
1073 |
$a->textlist = '';
|
|
|
1074 |
|
|
|
1075 |
foreach ($insane as $k => $reason) {
|
|
|
1076 |
if ($instances) {
|
|
|
1077 |
$a->textlist = $instances[$k]->get('name') . ': ' . $reason . "\n";
|
|
|
1078 |
} else {
|
|
|
1079 |
$a->textlist = $k . ': ' . $reason . "\n";
|
|
|
1080 |
}
|
|
|
1081 |
}
|
|
|
1082 |
|
|
|
1083 |
$subject = get_string('insanesubject', 'portfolio');
|
|
|
1084 |
$plainbody = get_string('insanebody', 'portfolio', $a);
|
|
|
1085 |
$htmlbody = get_string('insanebodyhtml', 'portfolio', $a);
|
|
|
1086 |
$smallbody = get_string('insanebodysmall', 'portfolio', $a);
|
|
|
1087 |
|
|
|
1088 |
foreach ($admins as $admin) {
|
|
|
1089 |
$eventdata = new \core\message\message();
|
|
|
1090 |
$eventdata->courseid = SITEID;
|
|
|
1091 |
$eventdata->modulename = 'portfolio';
|
|
|
1092 |
$eventdata->component = 'portfolio';
|
|
|
1093 |
$eventdata->name = 'notices';
|
|
|
1094 |
$eventdata->userfrom = get_admin();
|
|
|
1095 |
$eventdata->userto = $admin;
|
|
|
1096 |
$eventdata->subject = $subject;
|
|
|
1097 |
$eventdata->fullmessage = $plainbody;
|
|
|
1098 |
$eventdata->fullmessageformat = FORMAT_PLAIN;
|
|
|
1099 |
$eventdata->fullmessagehtml = $htmlbody;
|
|
|
1100 |
$eventdata->smallmessage = $smallbody;
|
|
|
1101 |
message_send($eventdata);
|
|
|
1102 |
}
|
|
|
1103 |
}
|
|
|
1104 |
|
|
|
1105 |
/**
|
|
|
1106 |
* Setup page export
|
|
|
1107 |
*
|
|
|
1108 |
* @param moodle_page $PAGE global variable from page object
|
|
|
1109 |
* @param portfolio_caller_base $caller plugin type caller
|
|
|
1110 |
*/
|
|
|
1111 |
function portfolio_export_pagesetup($PAGE, $caller) {
|
|
|
1112 |
// set up the context so that build_navigation works nice
|
|
|
1113 |
$caller->set_context($PAGE);
|
|
|
1114 |
|
|
|
1115 |
list($extranav, $cm) = $caller->get_navigation();
|
|
|
1116 |
|
|
|
1117 |
// and now we know the course for sure and maybe the cm, call require_login with it
|
|
|
1118 |
require_login($PAGE->course, false, $cm);
|
|
|
1119 |
$PAGE->activityheader->set_attrs([
|
|
|
1120 |
'description' => '',
|
|
|
1121 |
'hidecompletion' => true
|
|
|
1122 |
]);
|
|
|
1123 |
foreach ($extranav as $navitem) {
|
|
|
1124 |
$PAGE->navbar->add($navitem['name']);
|
|
|
1125 |
}
|
|
|
1126 |
$PAGE->navbar->add(get_string('exporting', 'portfolio'));
|
|
|
1127 |
}
|
|
|
1128 |
|
|
|
1129 |
/**
|
|
|
1130 |
* Get export type id
|
|
|
1131 |
*
|
|
|
1132 |
* @param string $type plugin type
|
|
|
1133 |
* @param int $userid the user to check for
|
|
|
1134 |
* @return mixed|bool
|
|
|
1135 |
*/
|
|
|
1136 |
function portfolio_export_type_to_id($type, $userid) {
|
|
|
1137 |
global $DB;
|
|
|
1138 |
$sql = 'SELECT t.id FROM {portfolio_tempdata} t JOIN {portfolio_instance} i ON t.instance = i.id WHERE t.userid = ? AND i.plugin = ?';
|
|
|
1139 |
return $DB->get_field_sql($sql, array($userid, $type));
|
|
|
1140 |
}
|
|
|
1141 |
|
|
|
1142 |
/**
|
|
|
1143 |
* Return a list of current exports for the given user.
|
|
|
1144 |
* This will not go through and call rewaken_object, because it's heavy.
|
|
|
1145 |
* It's really just used to figure out what exports are currently happening.
|
|
|
1146 |
* This is useful for plugins that don't support multiple exports per session
|
|
|
1147 |
*
|
|
|
1148 |
* @param int $userid the user to check for
|
|
|
1149 |
* @param string $type (optional) the portfolio plugin to filter by
|
|
|
1150 |
* @return array
|
|
|
1151 |
*/
|
|
|
1152 |
function portfolio_existing_exports($userid, $type=null) {
|
|
|
1153 |
global $DB;
|
|
|
1154 |
$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 = ? ';
|
|
|
1155 |
$values = array($userid);
|
|
|
1156 |
if ($type) {
|
|
|
1157 |
$sql .= ' AND i.plugin = ?';
|
|
|
1158 |
$values[] = $type;
|
|
|
1159 |
}
|
|
|
1160 |
return $DB->get_records_sql($sql, $values);
|
|
|
1161 |
}
|
|
|
1162 |
|
|
|
1163 |
/**
|
|
|
1164 |
* Return an array of existing exports by type for a given user.
|
|
|
1165 |
* This is much more lightweight than existing_exports because it only returns the types, rather than the whole serialised data
|
|
|
1166 |
* so can be used for checking availability of multiple plugins at the same time.
|
|
|
1167 |
* @see existing_exports
|
|
|
1168 |
*
|
|
|
1169 |
* @param int $userid the user to check for
|
|
|
1170 |
* @return array
|
|
|
1171 |
*/
|
|
|
1172 |
function portfolio_existing_exports_by_plugin($userid) {
|
|
|
1173 |
global $DB;
|
|
|
1174 |
$sql = 'SELECT t.id,i.plugin FROM {portfolio_tempdata} t JOIN {portfolio_instance} i ON t.instance = i.id WHERE t.userid = ? ';
|
|
|
1175 |
$values = array($userid);
|
|
|
1176 |
return $DB->get_records_sql_menu($sql, $values);
|
|
|
1177 |
}
|
|
|
1178 |
|
|
|
1179 |
/**
|
|
|
1180 |
* Return default common options for {@link format_text()} when preparing a content to be exported.
|
|
|
1181 |
* It is important not to apply filters and not to clean the HTML in format_text()
|
|
|
1182 |
*
|
|
|
1183 |
* @return stdClass
|
|
|
1184 |
*/
|
|
|
1185 |
function portfolio_format_text_options() {
|
|
|
1186 |
|
|
|
1187 |
$options = new stdClass();
|
|
|
1188 |
$options->para = false;
|
|
|
1189 |
$options->newlines = true;
|
|
|
1190 |
$options->filter = false;
|
|
|
1191 |
$options->noclean = true;
|
|
|
1192 |
$options->overflowdiv = false;
|
|
|
1193 |
|
|
|
1194 |
return $options;
|
|
|
1195 |
}
|
|
|
1196 |
|
|
|
1197 |
/**
|
|
|
1198 |
* callback function from {@link portfolio_rewrite_pluginfile_urls}
|
|
|
1199 |
* looks through preg_replace matches and replaces content with whatever the active portfolio export format says
|
|
|
1200 |
*
|
|
|
1201 |
* @param int $contextid module context id
|
|
|
1202 |
* @param string $component module name (eg:mod_assign)
|
|
|
1203 |
* @param string $filearea normal file_area arguments
|
|
|
1204 |
* @param int $itemid component item id
|
|
|
1205 |
* @param portfolio_format $format exporter format type
|
|
|
1206 |
* @param array $options extra options to pass through to the file_output function in the format (optional)
|
|
|
1207 |
* @param array $matches internal matching
|
|
|
1208 |
* @return object|array|string
|
|
|
1209 |
*/
|
|
|
1210 |
function portfolio_rewrite_pluginfile_url_callback($contextid, $component, $filearea, $itemid, $format, $options, $matches) {
|
|
|
1211 |
$matches = $matches[0]; // No internal matching.
|
|
|
1212 |
|
|
|
1213 |
// Loads the HTML.
|
|
|
1214 |
$dom = new DomDocument();
|
|
|
1215 |
if (!$dom->loadHTML($matches)) {
|
|
|
1216 |
return $matches;
|
|
|
1217 |
}
|
|
|
1218 |
|
|
|
1219 |
// Navigates to the node.
|
|
|
1220 |
$xpath = new DOMXPath($dom);
|
|
|
1221 |
$nodes = $xpath->query('/html/body/child::*');
|
|
|
1222 |
if (empty($nodes) || count($nodes) > 1) {
|
|
|
1223 |
// Unexpected sequence, none or too many nodes.
|
|
|
1224 |
return $matches;
|
|
|
1225 |
}
|
|
|
1226 |
$dom = $nodes->item(0);
|
|
|
1227 |
|
|
|
1228 |
$attributes = array();
|
|
|
1229 |
foreach ($dom->attributes as $attr => $node) {
|
|
|
1230 |
$attributes[$attr] = $node->value;
|
|
|
1231 |
}
|
|
|
1232 |
// now figure out the file
|
|
|
1233 |
$fs = get_file_storage();
|
|
|
1234 |
$key = 'href';
|
|
|
1235 |
if (!array_key_exists('href', $attributes) && array_key_exists('src', $attributes)) {
|
|
|
1236 |
$key = 'src';
|
|
|
1237 |
}
|
|
|
1238 |
if (!array_key_exists($key, $attributes)) {
|
|
|
1239 |
debugging('Couldn\'t find an attribute to use that contains @@PLUGINFILE@@ in portfolio_rewrite_pluginfile');
|
|
|
1240 |
return $matches;
|
|
|
1241 |
}
|
|
|
1242 |
$filename = substr($attributes[$key], strpos($attributes[$key], '@@PLUGINFILE@@') + strlen('@@PLUGINFILE@@'));
|
|
|
1243 |
$filepath = '/';
|
|
|
1244 |
if (strpos($filename, '/') !== 0) {
|
|
|
1245 |
$bits = explode('/', $filename);
|
|
|
1246 |
$filename = array_pop($bits);
|
|
|
1247 |
$filepath = implode('/', $bits);
|
|
|
1248 |
}
|
|
|
1249 |
if (!$file = $fs->get_file($contextid, $component, $filearea, $itemid, $filepath, urldecode($filename))) {
|
|
|
1250 |
debugging("Couldn't find a file from the embedded path info context $contextid component $component filearea $filearea itemid $itemid filepath $filepath name $filename");
|
|
|
1251 |
return $matches;
|
|
|
1252 |
}
|
|
|
1253 |
if (empty($options)) {
|
|
|
1254 |
$options = array();
|
|
|
1255 |
}
|
|
|
1256 |
$options['attributes'] = $attributes;
|
|
|
1257 |
return $format->file_output($file, $options);
|
|
|
1258 |
}
|
|
|
1259 |
|
|
|
1260 |
/**
|
|
|
1261 |
* Function to require any potential callback files, throwing exceptions
|
|
|
1262 |
* if an issue occurs.
|
|
|
1263 |
*
|
|
|
1264 |
* @param string $component This is the name of the component in Moodle, eg 'mod_forum'
|
|
|
1265 |
* @param string $class Name of the class containing the callback functions
|
|
|
1266 |
* activity components should ALWAYS use their name_portfolio_caller
|
|
|
1267 |
* other locations must use something unique
|
|
|
1268 |
*/
|
|
|
1269 |
function portfolio_include_callback_file($component, $class = null) {
|
|
|
1270 |
global $CFG;
|
|
|
1271 |
require_once($CFG->libdir . '/adminlib.php');
|
|
|
1272 |
|
|
|
1273 |
// It's possible that they are passing a file path rather than passing a component.
|
|
|
1274 |
// We want to try and convert this to a component name, eg. mod_forum.
|
|
|
1275 |
$pos = strrpos($component, '/');
|
|
|
1276 |
if ($pos !== false) {
|
|
|
1277 |
// Get rid of the first slash (if it exists).
|
|
|
1278 |
$component = ltrim($component, '/');
|
|
|
1279 |
// Get a list of valid plugin types.
|
|
|
1280 |
$plugintypes = core_component::get_plugin_types();
|
|
|
1281 |
// Assume it is not valid for now.
|
|
|
1282 |
$isvalid = false;
|
|
|
1283 |
// Go through the plugin types.
|
|
|
1284 |
foreach ($plugintypes as $type => $path) {
|
|
|
1285 |
// Getting the path relative to the dirroot.
|
|
|
1286 |
$path = preg_replace('|^' . preg_quote($CFG->dirroot, '|') . '/|', '', $path);
|
|
|
1287 |
if (strrpos($component, $path) === 0) {
|
|
|
1288 |
// Found the plugin type.
|
|
|
1289 |
$isvalid = true;
|
|
|
1290 |
$plugintype = $type;
|
|
|
1291 |
$pluginpath = $path;
|
|
|
1292 |
}
|
|
|
1293 |
}
|
|
|
1294 |
// Throw exception if not a valid component.
|
|
|
1295 |
if (!$isvalid) {
|
|
|
1296 |
throw new coding_exception('Somehow a non-valid plugin path was passed, could be a hackz0r attempt, exiting.');
|
|
|
1297 |
}
|
|
|
1298 |
// Remove the file name.
|
|
|
1299 |
$component = trim(substr($component, 0, $pos), '/');
|
|
|
1300 |
// Replace the path with the type.
|
|
|
1301 |
$component = str_replace($pluginpath, $plugintype, $component);
|
|
|
1302 |
// Ok, replace '/' with '_'.
|
|
|
1303 |
$component = str_replace('/', '_', $component);
|
|
|
1304 |
// Place a debug message saying the third parameter should be changed.
|
|
|
1305 |
debugging('The third parameter sent to the function set_callback_options should be the component name, not a file path, please update this.', DEBUG_DEVELOPER);
|
|
|
1306 |
}
|
|
|
1307 |
|
|
|
1308 |
// Check that it is a valid component.
|
|
|
1309 |
if (!get_component_version($component)) {
|
|
|
1310 |
throw new portfolio_button_exception('nocallbackcomponent', 'portfolio', '', $component);
|
|
|
1311 |
}
|
|
|
1312 |
|
|
|
1313 |
// Obtain the component's location.
|
|
|
1314 |
if (!$componentloc = core_component::get_component_directory($component)) {
|
|
|
1315 |
throw new portfolio_button_exception('nocallbackcomponent', 'portfolio', '', $component);
|
|
|
1316 |
}
|
|
|
1317 |
|
|
|
1318 |
// Check if the component contains the necessary file for the portfolio plugin.
|
|
|
1319 |
// These are locallib.php, portfoliolib.php and portfolio_callback.php.
|
|
|
1320 |
$filefound = false;
|
|
|
1321 |
if (file_exists($componentloc . '/locallib.php')) {
|
|
|
1322 |
$filefound = true;
|
|
|
1323 |
require_once($componentloc . '/locallib.php');
|
|
|
1324 |
}
|
|
|
1325 |
if (file_exists($componentloc . '/portfoliolib.php')) {
|
|
|
1326 |
$filefound = true;
|
|
|
1327 |
debugging('Please standardise your plugin by renaming your portfolio callback file to locallib.php, or if that file already exists moving the portfolio functionality there.', DEBUG_DEVELOPER);
|
|
|
1328 |
require_once($componentloc . '/portfoliolib.php');
|
|
|
1329 |
}
|
|
|
1330 |
if (file_exists($componentloc . '/portfolio_callback.php')) {
|
|
|
1331 |
$filefound = true;
|
|
|
1332 |
debugging('Please standardise your plugin by renaming your portfolio callback file to locallib.php, or if that file already exists moving the portfolio functionality there.', DEBUG_DEVELOPER);
|
|
|
1333 |
require_once($componentloc . '/portfolio_callback.php');
|
|
|
1334 |
}
|
|
|
1335 |
|
|
|
1336 |
// Ensure that we found a file we can use, if not throw an exception.
|
|
|
1337 |
if (!$filefound) {
|
|
|
1338 |
throw new portfolio_button_exception('nocallbackfile', 'portfolio', '', $component);
|
|
|
1339 |
}
|
|
|
1340 |
|
|
|
1341 |
if (!is_null($class)) {
|
|
|
1342 |
// If class is specified, check it exists and extends portfolio_caller_base.
|
|
|
1343 |
if (!class_exists($class) || !is_subclass_of($class, 'portfolio_caller_base')) {
|
|
|
1344 |
throw new portfolio_button_exception('nocallbackclass', 'portfolio', '', $class);
|
|
|
1345 |
}
|
|
|
1346 |
}
|
|
|
1347 |
}
|
|
|
1348 |
|
|
|
1349 |
/**
|
|
|
1350 |
* Go through all the @@PLUGINFILE@@ matches in some text,
|
|
|
1351 |
* extract the file information and pass it back to the portfolio export format
|
|
|
1352 |
* to regenerate the html to output
|
|
|
1353 |
*
|
|
|
1354 |
* @param string $text the text to search through
|
|
|
1355 |
* @param int $contextid normal file_area arguments
|
|
|
1356 |
* @param string $component module name
|
|
|
1357 |
* @param string $filearea normal file_area arguments
|
|
|
1358 |
* @param int $itemid normal file_area arguments
|
|
|
1359 |
* @param portfolio_format $format the portfolio export format
|
|
|
1360 |
* @param array $options additional options to be included in the plugin file url (optional)
|
|
|
1361 |
* @return mixed
|
|
|
1362 |
*/
|
|
|
1363 |
function portfolio_rewrite_pluginfile_urls($text, $contextid, $component, $filearea, $itemid, $format, $options=null) {
|
|
|
1364 |
$patterns = array(
|
|
|
1365 |
'(<(a|A)[^<]*?href="@@PLUGINFILE@@/[^>]*?>.*?</(a|A)>)',
|
|
|
1366 |
'(<(img|IMG)\s[^<]*?src="@@PLUGINFILE@@/[^>]*?/?>)',
|
|
|
1367 |
);
|
|
|
1368 |
$pattern = '~' . implode('|', $patterns) . '~';
|
|
|
1369 |
$callback = partial('portfolio_rewrite_pluginfile_url_callback', $contextid, $component, $filearea, $itemid, $format, $options);
|
|
|
1370 |
return preg_replace_callback($pattern, $callback, $text);
|
|
|
1371 |
}
|
|
|
1372 |
// this function has to go last, because the regexp screws up syntax highlighting in some editors
|