From 521a6ab04d06e5ffdb444ea766ccbf352e622aab Mon Sep 17 00:00:00 2001 From: Penny Leach <penny@liip.ch> Date: Tue, 15 Dec 2009 12:36:49 +0000 Subject: [PATCH] portfolio MDL-20896 added the ability to set mime info for "intended" files This means for places in Moodle that are going to write a file, like a CSV file, they can set the intended mimetype of the generated file. Previously you had to use a stored_file object. This also gets rid of portfolio_fake_add_url function and replaces the data module implementation with a button. I also refactored portfolio_add_button::to_html to use moodle_url so it's easy to return the same parameters to hidden form fields, an escaped url (for a link), and a non escaped url (to redirect to, which is what the data module does) --- lang/en_utf8/portfolio.php | 1 - lib/portfolio/caller.php | 13 ++++ lib/portfolio/constants.php | 5 ++ lib/portfoliolib.php | 134 +++++++++++++++++++----------------- mod/data/export.php | 11 ++- mod/data/export_form.php | 18 +++-- mod/data/locallib.php | 4 +- portfolio/add.php | 2 +- 8 files changed, 110 insertions(+), 78 deletions(-) diff --git a/lang/en_utf8/portfolio.php b/lang/en_utf8/portfolio.php index a18e3d72968..42dca51ba5c 100644 --- a/lang/en_utf8/portfolio.php +++ b/lang/en_utf8/portfolio.php @@ -83,7 +83,6 @@ $string['instancenotdelete'] = 'Failed to delete portfolio'; $string['instancesaved'] = 'Portfolio saved successfully'; $string['invalidaddformat'] = 'Invalid add format passed to portfolio_add_button. ($a) Must be one of PORTFOLIO_ADD_XXX'; $string['invalidtempid'] = 'Invalid export id. maybe it has expired'; -$string['invalidfileargument'] = 'Invalid file argument passed to portfolio_format_from_file - must be stored_file object'; $string['invalidfileareaargs'] = 'Invalid file area arguments passed to set_file_and_format_data - must contain contextid, filearea and itemid'; $string['invalidsha1file'] = 'Invalid call to get_sha1_file - either single or multifiles must be set'; $string['invalidpreparepackagefile'] = 'Invalid call to prepare_package_file - either single or multifiles must be set'; diff --git a/lib/portfolio/caller.php b/lib/portfolio/caller.php index ae600aad4b2..431a8aa6f61 100644 --- a/lib/portfolio/caller.php +++ b/lib/portfolio/caller.php @@ -74,6 +74,11 @@ abstract class portfolio_caller_base { */ protected $multifiles; + /** + * set this for generated-file exports + */ + protected $intendedmimetype; + public function __construct($callbackargs) { $expected = call_user_func(array(get_class($this), 'expected_callbackargs')); foreach ($expected as $key => $required) { @@ -473,6 +478,14 @@ abstract class portfolio_caller_base { $this->supportedformats[] = $format; } + public function get_mimetype() { + if ($this->singlefile instanceof stored_file) { + return $this->singlefile->get_mimetype(); + } else if (!empty($this->intendedmimetype)) { + return $this->intendedmimetype; + } + } + /** * array of arguments the caller expects to be passed through to it * this must be keyed on the argument name, and the array value is a boolean, diff --git a/lib/portfolio/constants.php b/lib/portfolio/constants.php index 1492cea6516..c1c744af2a4 100644 --- a/lib/portfolio/constants.php +++ b/lib/portfolio/constants.php @@ -213,3 +213,8 @@ define('PORTFOLIO_ADD_ICON_LINK', 3); */ define('PORTFOLIO_ADD_TEXT_LINK', 4); +/** + * hacky way to turn the button class into a url to redirect to + * this replaces the old portfolio_fake_add_url function + */ +define('PORTFOLIO_ADD_FAKE_URL', 5); diff --git a/lib/portfoliolib.php b/lib/portfoliolib.php index 44f961678c6..0558866f777 100644 --- a/lib/portfoliolib.php +++ b/lib/portfoliolib.php @@ -84,6 +84,7 @@ class portfolio_add_button { private $formats; private $instances; private $file; // for single-file exports + private $intendedmimetype; // for writing specific types of files /** * constructor. either pass the options here or set them using the helper methods. @@ -163,7 +164,8 @@ class portfolio_add_button { * @param array $formats if the calling code knows better than the static method on the calling class (base_supported_formats) * eg, if it's going to be a single file, or if you know it's HTML, you can pass it here instead * this is almost always the case so you should always use this. - * {@see portfolio_format_from_file} for how to get the appropriate formats to pass here for uploaded files. + * {@see portfolio_format_from_mimetype} for how to get the appropriate formats to pass here for uploaded files. + * or just call set_format_by_file instead */ public function set_formats($formats=null) { if (is_string($formats)) { @@ -179,6 +181,10 @@ class portfolio_add_button { $this->formats = portfolio_most_specific_formats($formats, $callerformats); } + /** + * reset formats to the default + * which is usually what base_supported_formats returns + */ public function reset_formats() { $this->set_formats(); } @@ -195,13 +201,33 @@ class portfolio_add_button { */ public function set_format_by_file(stored_file $file, $extraformats=null) { $this->file = $file; + $fileformat = portfolio_format_from_mimetype($file->get_mimetype()); if (is_string($extraformats)) { - $this->set_formats(array(portfolio_format_from_file($file), $extraformats)); - } else if (is_array($extraformats)) { - $this->set_formats(array_merge(array(portfolio_format_from_file($file)), $extraformats)); - } else { - $this->set_formats(portfolio_format_from_file($file)); + $extraformats = array($extraformats); + } else if (!is_array($extraformats)) { + $extraformats = array(); } + $this->set_formats(array_merge(array($fileformat), $extraformats)); + } + + /** + * correllary to set_format_by_file, but this is used when we don't yet have a stored_file + * when we're writing out a new type of file (like csv or pdf) + * + * @param string $extn the file extension we intend to generate + * @param mixed $extraformats any additional formats other than by mimetype + * eg leap2a etc + */ + public function set_format_by_intended_file($extn, $extraformats=null) { + $mimetype = mimeinfo('type', 'something. ' . $extn); + $fileformat = portfolio_format_from_mimetype($mimetype); + $this->intendedmimetype = $fileformat; + if (is_string($extraformats)) { + $extraformats = array($extraformats); + } else if (!is_array($extraformats)) { + $extraformats = array(); + } + $this->set_formats(array_merge(array($fileformat), $extraformats)); } /* @@ -238,8 +264,7 @@ class portfolio_add_button { // use the caller defaults $this->set_formats(); } - $formoutput = '<form method="post" action="' . $CFG->wwwroot . '/portfolio/add.php" id="portfolio-add-button">' . "\n"; - $linkoutput = '<a href="' . $CFG->wwwroot . '/portfolio/add.php?'; + $url = new moodle_url('/portfolio/add.php'); foreach ($this->callbackargs as $key => $value) { if (!empty($value) && !is_string($value) && !is_numeric($value)) { $a->key = $key; @@ -247,18 +272,19 @@ class portfolio_add_button { debugging(get_string('nonprimative', 'portfolio', $a)); return; } - $linkoutput .= 'ca_' . $key . '=' . $value . '&'; - $formoutput .= "\n" . '<input type="hidden" name="ca_' . $key . '" value="' . $value . '" />'; + $url->param('ca_' . $key, $value); + } + $url->param('sesskey', sesskey()); + $url->param('callbackfile', $this->callbackfile); + $url->param('callbackclass', $this->callbackclass); + $url->param('course', (!empty($COURSE)) ? $COURSE->id : 0); + $url->param('callerformats', implode(',', $this->formats)); + $mimetype = null; + if ($this->file instanceof stored_file) { + $mimetype = $this->file->get_mimetype(); + } else if ($this->intendedmimetype) { + $mimetype = $this->intendedmimetype; } - $formoutput .= "\n" . '<input type="hidden" name="sesskey" value="' . sesskey() . '" />'; - $linkoutput .= 'sesskey=' . sesskey() . '&'; - $formoutput .= "\n" . '<input type="hidden" name="callbackfile" value="' . $this->callbackfile . '" />'; - $formoutput .= "\n" . '<input type="hidden" name="callbackclass" value="' . $this->callbackclass . '" />'; - $formoutput .= "\n" . '<input type="hidden" name="course" value="' . (!empty($COURSE) ? $COURSE->id : 0) . '" />'; - $formoutput .= "\n" . '<input type="hidden" name="callerformats" value="' . implode(',', $this->formats) . '" />'; - $linkoutput .= 'callbackfile=' . $this->callbackfile . '&callbackclass=' - . $this->callbackclass . '&course=' . (!empty($COURSE) ? $COURSE->id : 0) - . '&callerformats=' . implode(',', $this->formats); $selectoutput = ''; if (count($this->instances) == 1) { $tmp = array_values($this->instances); @@ -279,19 +305,22 @@ class portfolio_add_button { debugging(get_string('singleinstancenomultiallowed', 'portfolio')); return; } - if ($this->file && $this->file instanceof stored_file && !$instance->file_mime_check($this->file->get_mimetype())) { - // bail, we have a specific file and this plugin doesn't support it - debugging(get_string('mimecheckfail', 'portfolio', (object)array('plugin' => $instance->get('plugin'), 'mimetype' => $this->file->get_mimetype()))); + if ($mimetype&& !$instance->file_mime_check($mimetype)) { + // bail, we have a specific file or mimetype and this plugin doesn't support it + debugging(get_string('mimecheckfail', 'portfolio', (object)array('plugin' => $instance->get('plugin'), 'mimetype' => $mimetype))); return; } - $formoutput .= "\n" . '<input type="hidden" name="instance" value="' . $instance->get('id') . '" />'; - $linkoutput .= '&instance=' . $instance->get('id'); + $url->param('instance', $instance->get('id')); } else { - if (!$selectoutput = portfolio_instance_select($this->instances, $this->formats, $this->file, $this->callbackclass, 'instance', true)) { + if (!$selectoutput = portfolio_instance_select($this->instances, $this->formats, $this->callbackclass, $mimetype, 'instance', true)) { return; } } + // if we just want a url to redirect to, do it now + if ($format == PORTFOLIO_ADD_FAKE_URL) { + return $url->out(false, array(), false); + } if (empty($addstr)) { $addstr = get_string('addtoportfolio', 'portfolio'); @@ -299,6 +328,11 @@ class portfolio_add_button { if (empty($format)) { $format = PORTFOLIO_ADD_FULL_FORM; } + + $formoutput = '<form method="post" action="' . $CFG->wwwroot . '/portfolio/add.php" id="portfolio-add-button">' . "\n"; + $formoutput .= $url->hidden_params_out(); + $linkoutput = '<a href="' . $url->out(); + switch ($format) { case PORTFOLIO_ADD_FULL_FORM: $formoutput .= $selectoutput; @@ -316,6 +350,8 @@ class portfolio_add_button { case PORTFOLIO_ADD_TEXT_LINK: $linkoutput .= '">' . $addstr .'</a>'; break; + case PORTFOLIO_ADD_FAKE_URL: + return urldecode($linkoutput); default: debugging(get_string('invalidaddformat', 'portfolio', $format)); } @@ -383,14 +419,14 @@ class portfolio_add_button { * @param array $instances array of portfolio plugin instance objects - the instances to put in the menu * @param array $callerformats array of PORTFOLIO_FORMAT_XXX constants - the formats the caller supports (this is used to filter plugins) * @param array $callbackclass the callback class name - used for debugging only for when there are no common formats -* @param stored_file $file if we already know we have exactly one file, pass it here to do mime filtering. +* @param mimetype $mimetype if we already know we have exactly one file, or are going to write one, pass it here to do mime filtering. * @param string $selectname the name of the select element. Optional, defaults to instance. * @param boolean $return whether to print or return the output. Optional, defaults to print. * @param booealn $returnarray if returning, whether to return the HTML or the array of options. Optional, defaults to HTML. * * @return string the html, from <select> to </select> inclusive. */ -function portfolio_instance_select($instances, $callerformats, $callbackclass, $file=null, $selectname='instance', $return=false, $returnarray=false) { +function portfolio_instance_select($instances, $callerformats, $callbackclass, $mimetype=null, $selectname='instance', $return=false, $returnarray=false) { global $CFG, $USER; if (empty($CFG->enableportfolios)) { @@ -422,8 +458,8 @@ function portfolio_instance_select($instances, $callerformats, $callbackclass, $ // bail, already exporting something with this plugin and it doesn't support multiple exports continue; } - if ($file && $file instanceof stored_file && !$instance->file_mime_check($file->get_mimetype())) { - debugging(get_string('mimecheckfail', 'portfolio', (object)array('plugin' => $instance->get('plugin'), 'mimetype' => $this->file->get_mimetype()))); + if ($mimetype && !$instance->file_mime_check($mimetype)) { + debugging(get_string('mimecheckfail', 'portfolio', (object)array('plugin' => $instance->get('plugin'), 'mimetype' => $mimetype()))); // bail, we have a specific file and this plugin doesn't support it continue; } @@ -516,23 +552,20 @@ function portfolio_supported_formats() { * This function returns the revelant portfolio export format * which is used to determine which portfolio plugins can be used * for exporting this content -* according to the mime type of the given file -* this only works when exporting exactly <b>one</b> file +* according to the given mime type +* this only works when exporting exactly <b>one</b> file, or generating a new one +* (like a pdf or csv export) * -* @param stored_file $file file to check mime type for +* @param string $mimetype (usually $file->get_mimetype()) * * @return string the format constant (see PORTFOLIO_FORMAT_XXX constants) */ -function portfolio_format_from_file(stored_file $file) { +function portfolio_format_from_mimetype($mimetype) { global $CFG; static $alreadymatched; if (empty($alreadymatched)) { $alreadymatched = array(); } - if (!($file instanceof stored_file)) { - throw new portfolio_exception('invalidfileargument', 'portfolio'); - } - $mimetype = $file->get_mimetype(); if (array_key_exists($mimetype, $alreadymatched)) { return $alreadymatched[$mimetype]; } @@ -862,33 +895,6 @@ function portfolio_report_insane($insane, $instances=false, $return=false) { echo $output; } -/** -* fake the url to portfolio/add.php from data from somewhere else -* you should use portfolio_add_button instead 99% of the time -* -* @param int $instanceid instanceid (optional, will force a new screen if not specified) -* @param string $classname callback classname -* @param string $classfile file containing the callback class definition -* @param array $callbackargs arguments to pass to the callback class -*/ -function portfolio_fake_add_url($instanceid, $classname, $classfile, $callbackargs, $formats) { - global $CFG; - $url = $CFG->wwwroot . '/portfolio/add.php?instance=' . $instanceid . '&callbackclass=' . $classname . '&callbackfile=' . $classfile . '&sesskey=' . sesskey(); - - if (is_object($callbackargs)) { - $callbackargs = (array)$callbackargs; - } - if (!is_array($callbackargs) || empty($callbackargs)) { - return $url; - } - foreach ($callbackargs as $key => $value) { - $url .= '&ca_' . $key . '=' . urlencode($value); - } - $url .= '&callerformats=' . implode(',', $formats); - return $url; -} - - /** * event handler for the portfolio_send event diff --git a/mod/data/export.php b/mod/data/export.php index bf2b588db16..85a5eddae10 100644 --- a/mod/data/export.php +++ b/mod/data/export.php @@ -98,11 +98,16 @@ if($mform->is_cancelled()) { } if (array_key_exists('portfolio', $formdata) && !empty($formdata['portfolio'])) { - // fake portfolio callback stuff and redirect + // fake portfolio callback stuff and redirect $formdata['id'] = $cm->id; - $formdata['exporttype'] = 'csv'; // force for now require_once($CFG->libdir . '/portfoliolib.php'); - $url = portfolio_fake_add_url($formdata['portfolio'], 'data_portfolio_caller', '/mod/data/locallib.php', $formdata, array(PORTFOLIO_FORMAT_SPREADSHEET)); + $button = new portfolio_add_button(); + $button->set_callback_options('data_portfolio_caller', $formdata, '/mod/data/locallib.php'); + if ($formdata['exporttype'] == 'csv') { + $button->set_format_by_intended_file('csv'); // so we can do mime checking + } + $url = $button->to_html(PORTFOLIO_ADD_FAKE_URL); + $url .= '&instance=' . $formdata['portfolio']; // add on the instance since we know it redirect($url); } diff --git a/mod/data/export_form.php b/mod/data/export_form.php index 22799c19c12..9c27e418918 100644 --- a/mod/data/export_form.php +++ b/mod/data/export_form.php @@ -58,17 +58,21 @@ class mod_data_export_form extends moodleform { } } $this->add_checkbox_controller(1, null, null, 1); - require_once($CFG->libdir . '/portfoliolib.php'); - require_once($CFG->dirroot . '/mod/data/locallib.php'); if ($CFG->enableportfolios && has_capability('mod/data:exportallentries', get_context_instance(CONTEXT_MODULE, $this->_cm->id))) { + require_once($CFG->libdir . '/portfoliolib.php'); + require_once($CFG->dirroot . '/mod/data/locallib.php'); if ($portfoliooptions = portfolio_instance_select( portfolio_instances(), call_user_func(array('data_portfolio_caller', 'base_supported_formats')), - 'data_portfolio_caller', '/mod/data/locallib.php', '', true, true)) { - $mform->addElement('header', 'notice', get_string('portfolionotfile', 'data') . ':'); - $portfoliooptions[0] = get_string('none'); - ksort($portfoliooptions); - $mform->addElement('select', 'portfolio', get_string('portfolio', 'portfolio'), $portfoliooptions); + 'data_portfolio_caller', + mimeinfo('type', 'export.csv'), + 'instance', + true, + true)) { + $mform->addElement('header', 'notice', get_string('portfolionotfile', 'data') . ':'); + $portfoliooptions[0] = get_string('none'); + ksort($portfoliooptions); + $mform->addElement('select', 'portfolio', get_string('portfolio', 'portfolio'), $portfoliooptions); } } $this->add_action_buttons(true, get_string('exportdatabaserecords', 'data')); diff --git a/mod/data/locallib.php b/mod/data/locallib.php index 39f82a89fa9..b8c34c1efee 100644 --- a/mod/data/locallib.php +++ b/mod/data/locallib.php @@ -301,7 +301,7 @@ class data_portfolio_caller extends portfolio_module_caller_base { } } if (count($includedfiles) == 1 && count($fields) == 1) { - $formats= array(portfolio_format_from_file($includedfiles[0])); + $formats= array(portfolio_format_from_mimetype($includedfiles[0]->get_mimetype())); } else if (count($includedfiles) > 0) { $formats = array(PORTFOLIO_FORMAT_RICHHTML); } @@ -309,6 +309,6 @@ class data_portfolio_caller extends portfolio_module_caller_base { } public static function base_supported_formats() { - return array(PORTFOLIO_FORMAT_FILE, PORTFOLIO_FORMAT_RICHHTML, PORTFOLIO_FORMAT_PLAINHTML); + return array(PORTFOLIO_FORMAT_SPREADSHEET, PORTFOLIO_FORMAT_RICHHTML, PORTFOLIO_FORMAT_PLAINHTML); } } diff --git a/portfolio/add.php b/portfolio/add.php index 0b988838f95..e9a7f1b080e 100644 --- a/portfolio/add.php +++ b/portfolio/add.php @@ -211,7 +211,7 @@ if (!$exporter->get('instance')) { portfolio_instances(), $exporter->get('caller')->supported_formats(), get_class($exporter->get('caller')), - $exporter->get('caller')->get('singlefile'), + $exporter->get('caller')->get_mimetype(), 'instance', true, true