Moodle  2.2.1
http://www.collinsharper.com
C:/xampp/htdocs/moodle/lib/portfoliolib.php
Go to the documentation of this file.
00001 <?php
00002 
00003 // This file is part of Moodle - http://moodle.org/
00004 //
00005 // Moodle is free software: you can redistribute it and/or modify
00006 // it under the terms of the GNU General Public License as published by
00007 // the Free Software Foundation, either version 3 of the License, or
00008 // (at your option) any later version.
00009 //
00010 // Moodle is distributed in the hope that it will be useful,
00011 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00012 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00013 // GNU General Public License for more details.
00014 //
00015 // You should have received a copy of the GNU General Public License
00016 // along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
00017 
00032 defined('MOODLE_INTERNAL') || die();
00033 
00034 // require some of the sublibraries first.
00035 // this is not an exhaustive list, the others are pulled in as they're needed
00036 // so we don't have to always include everything unnecessarily for performance
00037 
00038 // very lightweight list of constants. always needed and no further dependencies
00039 require_once($CFG->libdir . '/portfolio/constants.php');
00040 // a couple of exception deinitions. always needed and no further dependencies
00041 require_once($CFG->libdir . '/portfolio/exceptions.php');  // exception classes used by portfolio code
00042 // The base class for the caller classes. We always need this because we're either drawing a button,
00043 // in which case the button needs to know the calling class definition, which requires the base class,
00044 // or we're exporting, in which case we need the caller class anyway.
00045 require_once($CFG->libdir . '/portfolio/caller.php');
00046 
00047 // the other dependencies are included on demand:
00048 // libdir/portfolio/formats.php  - the classes for the export formats
00049 // libdir/portfolio/forms.php    - all portfolio form classes (requires formslib)
00050 // libdir/portfolio/plugin.php   - the base class for the export plugins
00051 // libdir/portfolio/exporter.php - the exporter class
00052 
00053 
00081 class portfolio_add_button {
00082 
00083     private $callbackclass;
00084     private $callbackargs;
00085     private $callbackfile;
00086     private $formats;
00087     private $instances;
00088     private $file; // for single-file exports
00089     private $intendedmimetype; // for writing specific types of files
00090 
00103     public function __construct($options=null) {
00104         global $SESSION, $CFG;
00105 
00106         if (empty($CFG->enableportfolios)) {
00107             debugging('Building portfolio add button while portfolios is disabled. This code can be optimised.', DEBUG_DEVELOPER);
00108         }
00109 
00110         $this->instances = portfolio_instances();
00111         if (empty($options)) {
00112             return true;
00113         }
00114         $constructoroptions = array('callbackclass', 'callbackargs', 'callbackfile', 'formats');
00115         foreach ((array)$options as $key => $value) {
00116             if (!in_array($key, $constructoroptions)) {
00117                 throw new portfolio_button_exception('invalidbuttonproperty', 'portfolio', $key);
00118             }
00119             $this->{$key} = $value;
00120         }
00121     }
00122 
00123     /*
00124     * @param string $class   name of the class containing the callback functions
00125     *                        activity modules should ALWAYS use their name_portfolio_caller
00126     *                        other locations must use something unique
00127     * @param mixed $argarray this can be an array or hash of arguments to pass
00128     *                        back to the callback functions (passed by reference)
00129     *                        these MUST be primatives to be added as hidden form fields.
00130     *                        and the values get cleaned to PARAM_ALPHAEXT or PARAM_NUMBER or PARAM_PATH
00131     * @param string $file    this can be autodetected if it's in the same file as your caller,
00132     *                        but often, the caller is a script.php and the class in a lib.php
00133     *                        so you can pass it here if necessary.
00134     *                        this path should be relative (ie, not include) dirroot, eg '/mod/forum/lib.php'
00135     */
00136     public function set_callback_options($class, array $argarray, $file=null) {
00137         global $CFG;
00138         if (empty($file)) {
00139             $backtrace = debug_backtrace();
00140             if (!array_key_exists(0, $backtrace) || !array_key_exists('file', $backtrace[0]) || !is_readable($backtrace[0]['file'])) {
00141                 throw new portfolio_button_exception('nocallbackfile', 'portfolio');
00142             }
00143 
00144             $file = substr($backtrace[0]['file'], strlen($CFG->dirroot));
00145         } else if (!is_readable($CFG->dirroot . $file)) {
00146             throw new portfolio_button_exception('nocallbackfile', 'portfolio', '', $file);
00147         }
00148         $this->callbackfile = $file;
00149         require_once($CFG->libdir . '/portfolio/caller.php'); // require the base class first
00150         require_once($CFG->dirroot . $file);
00151         if (!class_exists($class)) {
00152             throw new portfolio_button_exception('nocallbackclass', 'portfolio', '', $class);
00153         }
00154 
00155         // this will throw exceptions
00156         // but should not actually do anything other than verify callbackargs
00157         $test = new $class($argarray);
00158         unset($test);
00159 
00160         $this->callbackclass = $class;
00161         $this->callbackargs = $argarray;
00162     }
00163 
00164     /*
00165     * sets the available export formats for this content
00166     * this function will also poll the static function in the caller class
00167     * and make sure we're not overriding a format that has nothing to do with mimetypes
00168     * eg if you pass IMAGE here but the caller can export LEAP2A it will keep LEAP2A as well.
00169     * see portfolio_most_specific_formats for more information
00170     *
00171     * @param array $formats if the calling code knows better than the static method on the calling class (base_supported_formats)
00172     *                       eg, if it's going to be a single file, or if you know it's HTML, you can pass it here instead
00173     *                       this is almost always the case so you should always use this.
00174     *                       {@see portfolio_format_from_mimetype} for how to get the appropriate formats to pass here for uploaded files.
00175     *                       or just call set_format_by_file instead
00176     */
00177     public function set_formats($formats=null) {
00178         if (is_string($formats)) {
00179             $formats = array($formats);
00180         }
00181         if (empty($formats)) {
00182             $formats = array();
00183         }
00184         if (empty($this->callbackclass)) {
00185             throw new portfolio_button_exception('noclassbeforeformats', 'portfolio');
00186         }
00187         $callerformats = call_user_func(array($this->callbackclass, 'base_supported_formats'));
00188         $this->formats = portfolio_most_specific_formats($formats, $callerformats);
00189     }
00190 
00195     public function reset_formats() {
00196         $this->set_formats();
00197     }
00198 
00199 
00209     public function set_format_by_file(stored_file $file, $extraformats=null) {
00210         $this->file = $file;
00211         $fileformat = portfolio_format_from_mimetype($file->get_mimetype());
00212         if (is_string($extraformats)) {
00213             $extraformats = array($extraformats);
00214         } else if (!is_array($extraformats)) {
00215             $extraformats = array();
00216         }
00217         $this->set_formats(array_merge(array($fileformat), $extraformats));
00218     }
00219 
00228     public function set_format_by_intended_file($extn, $extraformats=null) {
00229         $mimetype = mimeinfo('type', 'something. ' . $extn);
00230         $fileformat = portfolio_format_from_mimetype($mimetype);
00231         $this->intendedmimetype = $fileformat;
00232         if (is_string($extraformats)) {
00233             $extraformats = array($extraformats);
00234         } else if (!is_array($extraformats)) {
00235             $extraformats = array();
00236         }
00237         $this->set_formats(array_merge(array($fileformat), $extraformats));
00238     }
00239 
00240     /*
00241     * echo the form/button/icon/text link to the page
00242     *
00243     * @param int $format format to display the button or form or icon or link.
00244     *                    See constants PORTFOLIO_ADD_XXX for more info.
00245     *                    optional, defaults to PORTFOLIO_ADD_FULL_FORM
00246     * @param str $addstr string to use for the button or icon alt text or link text.
00247     *                    this is whole string, not key. optional, defaults to 'Export to portfolio';
00248     */
00249     public function render($format=null, $addstr=null) {
00250         echo $this->to_html($format, $addstr);
00251     }
00252 
00253     /*
00254     * returns the form/button/icon/text link as html
00255     *
00256     * @param int $format format to display the button or form or icon or link.
00257     *                    See constants PORTFOLIO_ADD_XXX for more info.
00258     *                    optional, defaults to PORTFOLIO_ADD_FULL_FORM
00259     * @param str $addstr string to use for the button or icon alt text or link text.
00260     *                    this is whole string, not key.  optional, defaults to 'Add to portfolio';
00261     */
00262     public function to_html($format=null, $addstr=null) {
00263         global $CFG, $COURSE, $OUTPUT, $USER;
00264         if (!$this->is_renderable()) {
00265             return;
00266         }
00267         if (empty($this->callbackclass) || empty($this->callbackfile)) {
00268             throw new portfolio_button_exception('mustsetcallbackoptions', 'portfolio');
00269         }
00270         if (empty($this->formats)) {
00271             // use the caller defaults
00272             $this->set_formats();
00273         }
00274         $url = new moodle_url('/portfolio/add.php');
00275         foreach ($this->callbackargs as $key => $value) {
00276             if (!empty($value) && !is_string($value) && !is_numeric($value)) {
00277                 $a = new stdClass();
00278                 $a->key = $key;
00279                 $a->value = print_r($value, true);
00280                 debugging(get_string('nonprimative', 'portfolio', $a));
00281                 return;
00282             }
00283             $url->param('ca_' . $key, $value);
00284         }
00285         $url->param('sesskey', sesskey());
00286         $url->param('callbackfile', $this->callbackfile);
00287         $url->param('callbackclass', $this->callbackclass);
00288         $url->param('course', (!empty($COURSE)) ? $COURSE->id : 0);
00289         $url->param('callerformats', implode(',', $this->formats));
00290         $mimetype = null;
00291         if ($this->file instanceof stored_file) {
00292             $mimetype = $this->file->get_mimetype();
00293         } else if ($this->intendedmimetype) {
00294             $mimetype = $this->intendedmimetype;
00295         }
00296         $selectoutput = '';
00297         if (count($this->instances) == 1) {
00298             $tmp = array_values($this->instances);
00299             $instance = $tmp[0];
00300 
00301             $formats = portfolio_supported_formats_intersect($this->formats, $instance->supported_formats());
00302             if (count($formats) == 0) {
00303                 // bail. no common formats.
00304                 //debugging(get_string('nocommonformats', 'portfolio', (object)array('location' => $this->callbackclass, 'formats' => implode(',', $this->formats))));
00305                 return;
00306             }
00307             if ($error = portfolio_instance_sanity_check($instance)) {
00308                 // bail, plugin is misconfigured
00309                 //debugging(get_string('instancemisconfigured', 'portfolio', get_string($error[$instance->get('id')], 'portfolio_' . $instance->get('plugin'))));
00310                 return;
00311             }
00312             if (!$instance->allows_multiple_exports() && $already = portfolio_existing_exports($USER->id, $instance->get('plugin'))) {
00313                 //debugging(get_string('singleinstancenomultiallowed', 'portfolio'));
00314                 return;
00315             }
00316             if ($mimetype&& !$instance->file_mime_check($mimetype)) {
00317                 // bail, we have a specific file or mimetype and this plugin doesn't support it
00318                 //debugging(get_string('mimecheckfail', 'portfolio', (object)array('plugin' => $instance->get('plugin'), 'mimetype' => $mimetype)));
00319                 return;
00320             }
00321             $url->param('instance', $instance->get('id'));
00322         }
00323         else {
00324             if (!$selectoutput = portfolio_instance_select($this->instances, $this->formats, $this->callbackclass, $mimetype, 'instance', true)) {
00325                 return;
00326             }
00327         }
00328         // if we just want a url to redirect to, do it now
00329         if ($format == PORTFOLIO_ADD_FAKE_URL) {
00330             return $url->out(false);
00331         }
00332 
00333         if (empty($addstr)) {
00334             $addstr = get_string('addtoportfolio', 'portfolio');
00335         }
00336         if (empty($format)) {
00337             $format = PORTFOLIO_ADD_FULL_FORM;
00338         }
00339 
00340         $formoutput = '<form method="post" action="' . $CFG->wwwroot . '/portfolio/add.php" id="portfolio-add-button">' . "\n";
00341         $formoutput .= html_writer::input_hidden_params($url);
00342         $linkoutput = '<a class="portfolio-add-link" title="'.$addstr.'" href="' . $url->out();
00343 
00344         switch ($format) {
00345             case PORTFOLIO_ADD_FULL_FORM:
00346                 $formoutput .= $selectoutput;
00347                 $formoutput .= "\n" . '<input type="submit" value="' . $addstr .'" />';
00348                 $formoutput .= "\n" . '</form>';
00349             break;
00350             case PORTFOLIO_ADD_ICON_FORM:
00351                 $formoutput .= $selectoutput;
00352                 $formoutput .= "\n" . '<input class="portfolio-add-icon" type="image" src="' . $OUTPUT->pix_url('t/portfolioadd') . '" alt=' . $addstr .'" />';
00353                 $formoutput .= "\n" . '</form>';
00354             break;
00355             case PORTFOLIO_ADD_ICON_LINK:
00356                 $linkoutput .= '"><img class="portfolio-add-icon iconsmall" src="' . $OUTPUT->pix_url('t/portfolioadd') . '" alt="' . $addstr .'" /></a>';
00357             break;
00358             case PORTFOLIO_ADD_TEXT_LINK:
00359                 $linkoutput .= '">' . $addstr .'</a>';
00360             break;
00361             default:
00362                 debugging(get_string('invalidaddformat', 'portfolio', $format));
00363         }
00364         $output = (in_array($format, array(PORTFOLIO_ADD_FULL_FORM, PORTFOLIO_ADD_ICON_FORM)) ? $formoutput : $linkoutput);
00365         return $output;
00366     }
00367 
00373     private function is_renderable() {
00374         global $CFG;
00375         if (empty($CFG->enableportfolios)) {
00376             return false;
00377         }
00378         if (defined('PORTFOLIO_INTERNAL')) {
00379             // something somewhere has detected a risk of this being called during inside the preparation
00380             // eg forum_print_attachments
00381             return false;
00382         }
00383         if (empty($this->instances) || count($this->instances) == 0) {
00384             return false;
00385         }
00386         return true;
00387     }
00388 
00393     public function get_formats() {
00394         return $this->formats;
00395     }
00396 
00401     public function get_callbackargs() {
00402         return $this->callbackargs;
00403     }
00404 
00409     public function get_callbackfile() {
00410         return $this->callbackfile;
00411     }
00412 
00417     public function get_callbackclass() {
00418         return $this->callbackclass;
00419     }
00420 }
00421 
00435 function portfolio_instance_select($instances, $callerformats, $callbackclass, $mimetype=null, $selectname='instance', $return=false, $returnarray=false) {
00436     global $CFG, $USER;
00437 
00438     if (empty($CFG->enableportfolios)) {
00439         return;
00440     }
00441 
00442     $insane = portfolio_instance_sanity_check();
00443     $pinsane = portfolio_plugin_sanity_check();
00444 
00445     $count = 0;
00446     $selectoutput = "\n" . '<select name="' . $selectname . '">' . "\n";
00447     $existingexports = portfolio_existing_exports_by_plugin($USER->id);
00448     foreach ($instances as $instance) {
00449         $formats = portfolio_supported_formats_intersect($callerformats, $instance->supported_formats());
00450         if (count($formats) == 0) {
00451             // bail. no common formats.
00452             continue;
00453         }
00454         if (array_key_exists($instance->get('id'), $insane)) {
00455             // bail, plugin is misconfigured
00456             //debugging(get_string('instanceismisconfigured', 'portfolio', get_string($insane[$instance->get('id')], 'portfolio_' . $instance->get('plugin'))));
00457             continue;
00458         } else if (array_key_exists($instance->get('plugin'), $pinsane)) {
00459             // bail, plugin is misconfigured
00460             //debugging(get_string('pluginismisconfigured', 'portfolio', get_string($pinsane[$instance->get('plugin')], 'portfolio_' . $instance->get('plugin'))));
00461             continue;
00462         }
00463         if (!$instance->allows_multiple_exports() && in_array($instance->get('plugin'), $existingexports)) {
00464             // bail, already exporting something with this plugin and it doesn't support multiple exports
00465             continue;
00466         }
00467         if ($mimetype && !$instance->file_mime_check($mimetype)) {
00468             //debugging(get_string('mimecheckfail', 'portfolio', (object)array('plugin' => $instance->get('plugin'), 'mimetype' => $mimetype())));
00469             // bail, we have a specific file and this plugin doesn't support it
00470             continue;
00471         }
00472         $count++;
00473         $selectoutput .= "\n" . '<option value="' . $instance->get('id') . '">' . $instance->get('name') . '</option>' . "\n";
00474         $options[$instance->get('id')] = $instance->get('name');
00475     }
00476     if (empty($count)) {
00477         // bail. no common formats.
00478         //debugging(get_string('nocommonformats', 'portfolio', (object)array('location' => $callbackclass, 'formats' => implode(',', $callerformats))));
00479         return;
00480     }
00481     $selectoutput .= "\n" . "</select>\n";
00482     if (!empty($returnarray)) {
00483         return $options;
00484     }
00485     if (!empty($return)) {
00486         return $selectoutput;
00487     }
00488     echo $selectoutput;
00489 }
00490 
00501 function portfolio_instances($visibleonly=true, $useronly=true) {
00502 
00503     global $DB, $USER;
00504 
00505     $values = array();
00506     $sql = 'SELECT * FROM {portfolio_instance}';
00507 
00508     if ($visibleonly || $useronly) {
00509         $values[] = 1;
00510         $sql .= ' WHERE visible = ?';
00511     }
00512     if ($useronly) {
00513         $sql .= ' AND id NOT IN (
00514                 SELECT instance FROM {portfolio_instance_user}
00515                 WHERE userid = ? AND name = ? AND ' . $DB->sql_compare_text('value') . ' = ?
00516             )';
00517         $values = array_merge($values, array($USER->id, 'visible', 0));
00518     }
00519     $sql .= ' ORDER BY name';
00520 
00521     $instances = array();
00522     foreach ($DB->get_records_sql($sql, $values) as $instance) {
00523         $instances[$instance->id] = portfolio_instance($instance->id, $instance);
00524     }
00525     return $instances;
00526 }
00527 
00537 function portfolio_supported_formats() {
00538     return array(
00539         PORTFOLIO_FORMAT_FILE         => 'portfolio_format_file',
00540         PORTFOLIO_FORMAT_IMAGE        => 'portfolio_format_image',
00541         PORTFOLIO_FORMAT_RICHHTML     => 'portfolio_format_richhtml',
00542         PORTFOLIO_FORMAT_PLAINHTML    => 'portfolio_format_plainhtml',
00543         PORTFOLIO_FORMAT_TEXT         => 'portfolio_format_text',
00544         PORTFOLIO_FORMAT_VIDEO        => 'portfolio_format_video',
00545         PORTFOLIO_FORMAT_PDF          => 'portfolio_format_pdf',
00546         PORTFOLIO_FORMAT_DOCUMENT     => 'portfolio_format_document',
00547         PORTFOLIO_FORMAT_SPREADSHEET  => 'portfolio_format_spreadsheet',
00548         PORTFOLIO_FORMAT_PRESENTATION => 'portfolio_format_presentation',
00549         /*PORTFOLIO_FORMAT_MBKP, */ // later
00550         PORTFOLIO_FORMAT_LEAP2A       => 'portfolio_format_leap2a',
00551         PORTFOLIO_FORMAT_RICH         => 'portfolio_format_rich',
00552     );
00553 }
00554 
00569 function portfolio_format_from_mimetype($mimetype) {
00570     global $CFG;
00571     static $alreadymatched;
00572     if (empty($alreadymatched)) {
00573         $alreadymatched = array();
00574     }
00575     if (array_key_exists($mimetype, $alreadymatched)) {
00576         return $alreadymatched[$mimetype];
00577     }
00578     $allformats = portfolio_supported_formats();
00579     require_once($CFG->libdir . '/portfolio/formats.php');
00580     foreach ($allformats as $format => $classname) {
00581         $supportedmimetypes = call_user_func(array($classname, 'mimetypes'));
00582         if (!is_array($supportedmimetypes)) {
00583             debugging("one of the portfolio format classes, $classname, said it supported something funny for mimetypes, should have been array...");
00584             debugging(print_r($supportedmimetypes, true));
00585             continue;
00586         }
00587         if (in_array($mimetype, $supportedmimetypes)) {
00588             $alreadymatched[$mimetype] = $format;
00589             return $format;
00590         }
00591     }
00592     return PORTFOLIO_FORMAT_FILE; // base case for files...
00593 }
00594 
00605 function portfolio_supported_formats_intersect($callerformats, $pluginformats) {
00606     global $CFG;
00607     $allformats = portfolio_supported_formats();
00608     $intersection = array();
00609     foreach ($callerformats as $cf) {
00610         if (!array_key_exists($cf, $allformats)) {
00611             if (!portfolio_format_is_abstract($cf)) {
00612                 debugging(get_string('invalidformat', 'portfolio', $cf));
00613             }
00614             continue;
00615         }
00616         require_once($CFG->libdir . '/portfolio/formats.php');
00617         $cfobj = new $allformats[$cf]();
00618         foreach ($pluginformats as $p => $pf) {
00619             if (!array_key_exists($pf, $allformats)) {
00620                 if (!portfolio_format_is_abstract($pf)) {
00621                     debugging(get_string('invalidformat', 'portfolio', $pf));
00622                 }
00623                 unset($pluginformats[$p]); // to avoid the same warning over and over
00624                 continue;
00625             }
00626             if ($cfobj instanceof $allformats[$pf]) {
00627                 $intersection[] = $cf;
00628             }
00629         }
00630     }
00631     return $intersection;
00632 }
00633 
00641 function portfolio_format_is_abstract($format) {
00642     if (class_exists($format)) {
00643         $class = $format;
00644     } else if (class_exists('portfolio_format_' . $format)) {
00645         $class = 'portfolio_format_' . $format;
00646     } else {
00647         $allformats = portfolio_supported_formats();
00648         if (array_key_exists($format, $allformats)) {
00649             $class = $allformats[$format];
00650         }
00651     }
00652     if (empty($class)) {
00653         return true; // it may as well be, we can't instantiate it :)
00654     }
00655     $rc = new ReflectionClass($class);
00656     return $rc->isAbstract();
00657 }
00658 
00671 function portfolio_most_specific_formats($specificformats, $generalformats) {
00672     global $CFG;
00673     $allformats = portfolio_supported_formats();
00674     if (empty($specificformats)) {
00675         return $generalformats;
00676     } else if (empty($generalformats)) {
00677         return $specificformats;
00678     }
00679     $removedformats = array();
00680     foreach ($specificformats as $k => $f) {
00681         // look for something less specific and remove it, ie outside of the inheritance tree of the current formats.
00682         if (!array_key_exists($f, $allformats)) {
00683             if (!portfolio_format_is_abstract($f)) {
00684                 throw new portfolio_button_exception('invalidformat', 'portfolio', $f);
00685             }
00686         }
00687         if (in_array($f, $removedformats)) {
00688             // already been removed from the general list
00689             //debugging("skipping $f because it was already removed");
00690             unset($specificformats[$k]);
00691         }
00692         require_once($CFG->libdir . '/portfolio/formats.php');
00693         $fobj = new $allformats[$f];
00694         foreach ($generalformats as $key => $cf) {
00695             if (in_array($cf, $removedformats)) {
00696                 //debugging("skipping $cf because it was already removed");
00697                 continue;
00698             }
00699             $cfclass = $allformats[$cf];
00700             $cfobj = new $allformats[$cf];
00701             if ($fobj instanceof $cfclass && $cfclass != get_class($fobj)) {
00702                 //debugging("unsetting $key $cf because it's not specific enough ($f is better)");
00703                 unset($generalformats[$key]);
00704                 $removedformats[] = $cf;
00705                 continue;
00706             }
00707             // check for conflicts
00708             if ($fobj->conflicts($cf)) {
00709                 //debugging("unsetting $key $cf because it conflicts with $f");
00710                 unset($generalformats[$key]);
00711                 $removedformats[] = $cf;
00712                 continue;
00713             }
00714             if ($cfobj->conflicts($f)) {
00715                 //debugging("unsetting $key $cf because it reverse-conflicts with $f");
00716                 $removedformats[] = $cf;
00717                 unset($generalformats[$key]);
00718                 continue;
00719             }
00720         }
00721         //debugging('inside loop');
00722         //print_object($generalformats);
00723     }
00724 
00725     //debugging('final formats');
00726     $finalformats =  array_unique(array_merge(array_values($specificformats), array_values($generalformats)));
00727     //print_object($finalformats);
00728     return $finalformats;
00729 }
00730 
00738 function portfolio_format_object($name) {
00739     global $CFG;
00740     require_once($CFG->libdir . '/portfolio/formats.php');
00741     $formats = portfolio_supported_formats();
00742     return new $formats[$name];
00743 }
00744 
00755 function portfolio_instance($instanceid, $record=null) {
00756     global $DB, $CFG;
00757 
00758     if ($record) {
00759         $instance  = $record;
00760     } else {
00761         if (!$instance = $DB->get_record('portfolio_instance', array('id' => $instanceid))) {
00762             throw new portfolio_exception('invalidinstance', 'portfolio');
00763         }
00764     }
00765     require_once($CFG->libdir . '/portfolio/plugin.php');
00766     require_once($CFG->dirroot . '/portfolio/'. $instance->plugin . '/lib.php');
00767     $classname = 'portfolio_plugin_' . $instance->plugin;
00768     return new $classname($instanceid, $instance);
00769 }
00770 
00781 function portfolio_static_function($plugin, $function) {
00782     global $CFG;
00783 
00784     $pname = null;
00785     if (is_object($plugin) || is_array($plugin)) {
00786         $plugin = (object)$plugin;
00787         $pname = $plugin->name;
00788     } else {
00789         $pname = $plugin;
00790     }
00791 
00792     $args = func_get_args();
00793     if (count($args) <= 2) {
00794         $args = array();
00795     }
00796     else {
00797         array_shift($args);
00798         array_shift($args);
00799     }
00800 
00801     require_once($CFG->libdir . '/portfolio/plugin.php');
00802     require_once($CFG->dirroot . '/portfolio/' . $plugin .  '/lib.php');
00803     return call_user_func_array(array('portfolio_plugin_' . $plugin, $function), $args);
00804 }
00805 
00814 function portfolio_plugin_sanity_check($plugins=null) {
00815     global $DB;
00816     if (is_string($plugins)) {
00817         $plugins = array($plugins);
00818     } else if (empty($plugins)) {
00819         $plugins = get_plugin_list('portfolio');
00820         $plugins = array_keys($plugins);
00821     }
00822 
00823     $insane = array();
00824     foreach ($plugins as $plugin) {
00825         if ($result = portfolio_static_function($plugin, 'plugin_sanity_check')) {
00826             $insane[$plugin] = $result;
00827         }
00828     }
00829     if (empty($insane)) {
00830         return array();
00831     }
00832     list($where, $params) = $DB->get_in_or_equal(array_keys($insane));
00833     $where = ' plugin ' . $where;
00834     $DB->set_field_select('portfolio_instance', 'visible', 0, $where, $params);
00835     return $insane;
00836 }
00837 
00846 function portfolio_instance_sanity_check($instances=null) {
00847     global $DB;
00848     if (empty($instances)) {
00849         $instances = portfolio_instances(false);
00850     } else if (!is_array($instances)) {
00851         $instances = array($instances);
00852     }
00853 
00854     $insane = array();
00855     foreach ($instances as $instance) {
00856         if (is_object($instance) && !($instance instanceof portfolio_plugin_base)) {
00857             $instance = portfolio_instance($instance->id, $instance);
00858         } else if (is_numeric($instance)) {
00859             $instance = portfolio_instance($instance);
00860         }
00861         if (!($instance instanceof portfolio_plugin_base)) {
00862             debugging('something weird passed to portfolio_instance_sanity_check, not subclass or id');
00863             continue;
00864         }
00865         if ($result = $instance->instance_sanity_check()) {
00866             $insane[$instance->get('id')] = $result;
00867         }
00868     }
00869     if (empty($insane)) {
00870         return array();
00871     }
00872     list ($where, $params) = $DB->get_in_or_equal(array_keys($insane));
00873     $where = ' id ' . $where;
00874     $DB->set_field_select('portfolio_instance', 'visible', 0, $where, $params);
00875     portfolio_insane_notify_admins($insane, true);
00876     return $insane;
00877 }
00878 
00886 function portfolio_report_insane($insane, $instances=false, $return=false) {
00887     global $OUTPUT;
00888     if (empty($insane)) {
00889         return;
00890     }
00891 
00892     static $pluginstr;
00893     if (empty($pluginstr)) {
00894         $pluginstr = get_string('plugin', 'portfolio');
00895     }
00896     if ($instances) {
00897         $headerstr = get_string('someinstancesdisabled', 'portfolio');
00898     } else {
00899         $headerstr = get_string('somepluginsdisabled', 'portfolio');
00900     }
00901 
00902     $output = $OUTPUT->notification($headerstr, 'notifyproblem');
00903     $table = new html_table();
00904     $table->head = array($pluginstr, '');
00905     $table->data = array();
00906     foreach ($insane as $plugin => $reason) {
00907         if ($instances) {
00908             $instance = $instances[$plugin];
00909             $plugin   = $instance->get('plugin');
00910             $name     = $instance->get('name');
00911         } else {
00912             $name = $plugin;
00913         }
00914         $table->data[] = array($name, get_string($reason, 'portfolio_' . $plugin));
00915     }
00916     $output .= html_writer::table($table);
00917     $output .= '<br /><br /><br />';
00918 
00919     if ($return) {
00920         return $output;
00921     }
00922     echo $output;
00923 }
00924 
00925 
00929 function portfolio_handle_event($eventdata) {
00930     global $CFG;
00931 
00932     require_once($CFG->libdir . '/portfolio/exporter.php');
00933     $exporter = portfolio_exporter::rewaken_object($eventdata);
00934     $exporter->process_stage_package();
00935     $exporter->process_stage_send();
00936     $exporter->save();
00937     $exporter->process_stage_cleanup();
00938     return true;
00939 }
00940 
00947 function portfolio_cron() {
00948     global $DB, $CFG;
00949 
00950     require_once($CFG->libdir . '/portfolio/exporter.php');
00951     if ($expired = $DB->get_records_select('portfolio_tempdata', 'expirytime < ?', array(time()), '', 'id')) {
00952         foreach ($expired as $d) {
00953             try {
00954                 $e = portfolio_exporter::rewaken_object($d->id);
00955                 $e->process_stage_cleanup(true);
00956             } catch (Exception $e) {
00957                 mtrace('Exception thrown in portfolio cron while cleaning up ' . $d->id . ': ' . $e->getMessage());
00958             }
00959         }
00960     }
00961 }
00962 
00975 function portfolio_export_rethrow_exception($exporter, $exception) {
00976     throw new portfolio_export_exception($exporter, $exception->errorcode, $exception->module, $exception->link, $exception->a);
00977 }
00978 
00987 function portfolio_expected_time_file($totest) {
00988     global $CFG;
00989     if ($totest instanceof stored_file) {
00990         $totest = array($totest);
00991     }
00992     $size = 0;
00993     foreach ($totest as $file) {
00994         if (!($file instanceof stored_file)) {
00995             debugging('something weird passed to portfolio_expected_time_file - not stored_file object');
00996             debugging(print_r($file, true));
00997             continue;
00998         }
00999         $size += $file->get_filesize();
01000     }
01001 
01002     $fileinfo = portfolio_filesize_info();
01003 
01004     $moderate = $high = 0; // avoid warnings
01005 
01006     foreach (array('moderate', 'high') as $setting) {
01007         $settingname = 'portfolio_' . $setting . '_filesize_threshold';
01008         if (empty($CFG->{$settingname}) || !array_key_exists($CFG->{$settingname}, $fileinfo['options'])) {
01009             debugging("weird or unset admin value for $settingname, using default instead");
01010             $$setting = $fileinfo[$setting];
01011         } else {
01012             $$setting = $CFG->{$settingname};
01013         }
01014     }
01015 
01016     if ($size < $moderate) {
01017         return PORTFOLIO_TIME_LOW;
01018     } else if ($size < $high) {
01019         return PORTFOLIO_TIME_MODERATE;
01020     }
01021     return PORTFOLIO_TIME_HIGH;
01022 }
01023 
01024 
01029 function portfolio_filesize_info() {
01030     $filesizes = array();
01031     $sizelist = array(10240, 51200, 102400, 512000, 1048576, 2097152, 5242880, 10485760, 20971520, 52428800);
01032     foreach ($sizelist as $size) {
01033         $filesizes[$size] = display_size($size);
01034     }
01035     return array(
01036         'options' => $filesizes,
01037         'moderate' => 1048576,
01038         'high'     => 5242880,
01039     );
01040 }
01041 
01050 function portfolio_expected_time_db($recordcount) {
01051     global $CFG;
01052 
01053     if (empty($CFG->portfolio_moderate_dbsize_threshold)) {
01054         set_config('portfolio_moderate_dbsize_threshold', 10);
01055     }
01056     if (empty($CFG->portfolio_high_dbsize_threshold)) {
01057         set_config('portfolio_high_dbsize_threshold', 50);
01058     }
01059     if ($recordcount < $CFG->portfolio_moderate_dbsize_threshold) {
01060         return PORTFOLIO_TIME_LOW;
01061     } else if ($recordcount < $CFG->portfolio_high_dbsize_threshold) {
01062         return PORTFOLIO_TIME_MODERATE;
01063     }
01064     return PORTFOLIO_TIME_HIGH;
01065 }
01066 
01070 function portfolio_insane_notify_admins($insane, $instances=false) {
01071 
01072     global $CFG;
01073 
01074     if (defined('ADMIN_EDITING_PORTFOLIO')) {
01075         return true;
01076     }
01077 
01078     $admins = get_admins();
01079 
01080     if (empty($admins)) {
01081         return;
01082     }
01083     if ($instances) {
01084         $instances = portfolio_instances(false, false);
01085     }
01086 
01087     $site = get_site();
01088 
01089     $a = new StdClass;
01090     $a->sitename = format_string($site->fullname, true, array('context' => get_context_instance(CONTEXT_COURSE, SITEID)));
01091     $a->fixurl   = "$CFG->wwwroot/$CFG->admin/settings.php?section=manageportfolios";
01092     $a->htmllist = portfolio_report_insane($insane, $instances, true);
01093     $a->textlist = '';
01094 
01095     foreach ($insane as $k => $reason) {
01096         if ($instances) {
01097             $a->textlist = $instances[$k]->get('name') . ': ' . $reason . "\n";
01098         } else {
01099             $a->textlist = $k . ': ' . $reason . "\n";
01100         }
01101     }
01102 
01103     $subject   = get_string('insanesubject', 'portfolio');
01104     $plainbody = get_string('insanebody', 'portfolio', $a);
01105     $htmlbody  = get_string('insanebodyhtml', 'portfolio', $a);
01106     $smallbody = get_string('insanebodysmall', 'portfolio', $a);
01107 
01108     foreach ($admins as $admin) {
01109         $eventdata = new stdClass();
01110         $eventdata->modulename = 'portfolio';
01111         $eventdata->component = 'portfolio';
01112         $eventdata->name = 'notices';
01113         $eventdata->userfrom = $admin;
01114         $eventdata->userto = $admin;
01115         $eventdata->subject = $subject;
01116         $eventdata->fullmessage = $plainbody;
01117         $eventdata->fullmessageformat = FORMAT_PLAIN;
01118         $eventdata->fullmessagehtml = $htmlbody;
01119         $eventdata->smallmessage = $smallbody;
01120         message_send($eventdata);
01121     }
01122 }
01123 
01124 function portfolio_export_pagesetup($PAGE, $caller) {
01125     // set up the context so that build_navigation works nice
01126     $caller->set_context($PAGE);
01127 
01128     list($extranav, $cm) = $caller->get_navigation();
01129 
01130     // and now we know the course for sure and maybe the cm, call require_login with it
01131     require_login($PAGE->course, false, $cm);
01132 
01133     foreach ($extranav as $navitem) {
01134         $PAGE->navbar->add($navitem['name']);
01135     }
01136     $PAGE->navbar->add(get_string('exporting', 'portfolio'));
01137 }
01138 
01139 function portfolio_export_type_to_id($type, $userid) {
01140     global $DB;
01141     $sql = 'SELECT t.id FROM {portfolio_tempdata} t JOIN {portfolio_instance} i ON t.instance = i.id WHERE t.userid = ? AND i.plugin = ?';
01142     return $DB->get_field_sql($sql, array($userid, $type));
01143 }
01144 
01156 function portfolio_existing_exports($userid, $type=null) {
01157     global $DB;
01158     $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 = ? ';
01159     $values = array($userid);
01160     if ($type) {
01161         $sql .= ' AND i.plugin = ?';
01162         $values[] = $type;
01163     }
01164     return $DB->get_records_sql($sql, $values);
01165 }
01166 
01172 function portfolio_existing_exports_by_plugin($userid) {
01173     global $DB;
01174     $sql = 'SELECT t.id,i.plugin FROM {portfolio_tempdata} t JOIN {portfolio_instance} i ON t.instance = i.id WHERE t.userid = ? ';
01175     $values = array($userid);
01176     return $DB->get_records_sql_menu($sql, $values);
01177 }
01178 
01186 function portfolio_format_text_options() {
01187 
01188     $options                = new stdClass();
01189     $options->para          = false;
01190     $options->newlines      = true;
01191     $options->filter        = false;
01192     $options->noclean       = true;
01193     $options->overflowdiv   = false;
01194 
01195     return $options;
01196 }
01197 
01202 function portfolio_rewrite_pluginfile_url_callback($contextid, $component, $filearea, $itemid, $format, $options, $matches) {
01203     $matches = $matches[0]; // no internal matching
01204     $dom = new DomDocument();
01205     if (!$dom->loadXML($matches)) {
01206         return $matches;
01207     }
01208     $attributes = array();
01209     foreach ($dom->documentElement->attributes as $attr => $node) {
01210         $attributes[$attr] = $node->value;
01211     }
01212     // now figure out the file
01213     $fs = get_file_storage();
01214     $key = 'href';
01215     if (!array_key_exists('href', $attributes) && array_key_exists('src', $attributes)) {
01216         $key = 'src';
01217     }
01218     if (!array_key_exists($key, $attributes)) {
01219         debugging('Couldn\'t find an attribute to use that contains @@PLUGINFILE@@ in portfolio_rewrite_pluginfile');
01220         return $matches;
01221     }
01222     $filename = substr($attributes[$key], strpos($attributes[$key], '@@PLUGINFILE@@') + strlen('@@PLUGINFILE@@'));
01223     $filepath = '/';
01224     if (strpos($filename, '/') !== 0) {
01225         $bits = explode('/', $filename);
01226         $filename = array_pop($bits);
01227         $filepath = implode('/', $bits);
01228     }
01229     if (!$file = $fs->get_file($contextid, $component, $filearea, $itemid, $filepath, $filename)) {
01230         debugging("Couldn't find a file from the embedded path info context $contextid component $component filearea $filearea itemid $itemid filepath $filepath name $filename");
01231         return $matches;
01232     }
01233     if (empty($options)) {
01234         $options = array();
01235     }
01236     $options['attributes'] = $attributes;
01237     return $format->file_output($file, $options);
01238 }
01239 
01240 
01256 function portfolio_rewrite_pluginfile_urls($text, $contextid, $component, $filearea, $itemid, $format, $options=null) {
01257     $pattern = '/(<[^<]*?="@@PLUGINFILE@@\/[^>]*?(?:\/>|>.*?<\/[^>]*?>))/';
01258     $callback = partial('portfolio_rewrite_pluginfile_url_callback', $contextid, $component, $filearea, $itemid, $format, $options);
01259     return preg_replace_callback($pattern, $callback, $text);
01260 }
01261 // this function has to go last, because the regexp screws up syntax highlighting in some editors
01262 
 All Data Structures Namespaces Files Functions Variables Enumerations