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)
This commit is contained in:
Penny Leach 2009-12-15 12:36:49 +00:00
parent ecea942368
commit 521a6ab04d
8 changed files with 110 additions and 78 deletions

View File

@ -83,7 +83,6 @@ $string['instancenotdelete'] = 'Failed to delete portfolio';
$string['instancesaved'] = 'Portfolio saved successfully'; $string['instancesaved'] = 'Portfolio saved successfully';
$string['invalidaddformat'] = 'Invalid add format passed to portfolio_add_button. ($a) Must be one of PORTFOLIO_ADD_XXX'; $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['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['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['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'; $string['invalidpreparepackagefile'] = 'Invalid call to prepare_package_file - either single or multifiles must be set';

View File

@ -74,6 +74,11 @@ abstract class portfolio_caller_base {
*/ */
protected $multifiles; protected $multifiles;
/**
* set this for generated-file exports
*/
protected $intendedmimetype;
public function __construct($callbackargs) { public function __construct($callbackargs) {
$expected = call_user_func(array(get_class($this), 'expected_callbackargs')); $expected = call_user_func(array(get_class($this), 'expected_callbackargs'));
foreach ($expected as $key => $required) { foreach ($expected as $key => $required) {
@ -473,6 +478,14 @@ abstract class portfolio_caller_base {
$this->supportedformats[] = $format; $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 * 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, * this must be keyed on the argument name, and the array value is a boolean,

View File

@ -213,3 +213,8 @@ define('PORTFOLIO_ADD_ICON_LINK', 3);
*/ */
define('PORTFOLIO_ADD_TEXT_LINK', 4); 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);

View File

@ -84,6 +84,7 @@ class portfolio_add_button {
private $formats; private $formats;
private $instances; private $instances;
private $file; // for single-file exports 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. * 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) * @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 * 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. * 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) { public function set_formats($formats=null) {
if (is_string($formats)) { if (is_string($formats)) {
@ -179,6 +181,10 @@ class portfolio_add_button {
$this->formats = portfolio_most_specific_formats($formats, $callerformats); $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() { public function reset_formats() {
$this->set_formats(); $this->set_formats();
} }
@ -195,13 +201,33 @@ class portfolio_add_button {
*/ */
public function set_format_by_file(stored_file $file, $extraformats=null) { public function set_format_by_file(stored_file $file, $extraformats=null) {
$this->file = $file; $this->file = $file;
$fileformat = portfolio_format_from_mimetype($file->get_mimetype());
if (is_string($extraformats)) { if (is_string($extraformats)) {
$this->set_formats(array(portfolio_format_from_file($file), $extraformats)); $extraformats = array($extraformats);
} else if (is_array($extraformats)) { } else if (!is_array($extraformats)) {
$this->set_formats(array_merge(array(portfolio_format_from_file($file)), $extraformats)); $extraformats = array();
} else {
$this->set_formats(portfolio_format_from_file($file));
} }
$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 // use the caller defaults
$this->set_formats(); $this->set_formats();
} }
$formoutput = '<form method="post" action="' . $CFG->wwwroot . '/portfolio/add.php" id="portfolio-add-button">' . "\n"; $url = new moodle_url('/portfolio/add.php');
$linkoutput = '<a href="' . $CFG->wwwroot . '/portfolio/add.php?';
foreach ($this->callbackargs as $key => $value) { foreach ($this->callbackargs as $key => $value) {
if (!empty($value) && !is_string($value) && !is_numeric($value)) { if (!empty($value) && !is_string($value) && !is_numeric($value)) {
$a->key = $key; $a->key = $key;
@ -247,18 +272,19 @@ class portfolio_add_button {
debugging(get_string('nonprimative', 'portfolio', $a)); debugging(get_string('nonprimative', 'portfolio', $a));
return; return;
} }
$linkoutput .= 'ca_' . $key . '=' . $value . '&amp;'; $url->param('ca_' . $key, $value);
$formoutput .= "\n" . '<input type="hidden" name="ca_' . $key . '" value="' . $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() . '&amp;';
$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 . '&amp;callbackclass='
. $this->callbackclass . '&amp;course=' . (!empty($COURSE) ? $COURSE->id : 0)
. '&amp;callerformats=' . implode(',', $this->formats);
$selectoutput = ''; $selectoutput = '';
if (count($this->instances) == 1) { if (count($this->instances) == 1) {
$tmp = array_values($this->instances); $tmp = array_values($this->instances);
@ -279,19 +305,22 @@ class portfolio_add_button {
debugging(get_string('singleinstancenomultiallowed', 'portfolio')); debugging(get_string('singleinstancenomultiallowed', 'portfolio'));
return; return;
} }
if ($this->file && $this->file instanceof stored_file && !$instance->file_mime_check($this->file->get_mimetype())) { if ($mimetype&& !$instance->file_mime_check($mimetype)) {
// bail, we have a specific file and this plugin doesn't support it // 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' => $this->file->get_mimetype()))); debugging(get_string('mimecheckfail', 'portfolio', (object)array('plugin' => $instance->get('plugin'), 'mimetype' => $mimetype)));
return; return;
} }
$formoutput .= "\n" . '<input type="hidden" name="instance" value="' . $instance->get('id') . '" />'; $url->param('instance', $instance->get('id'));
$linkoutput .= '&amp;instance=' . $instance->get('id');
} }
else { 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; 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)) { if (empty($addstr)) {
$addstr = get_string('addtoportfolio', 'portfolio'); $addstr = get_string('addtoportfolio', 'portfolio');
@ -299,6 +328,11 @@ class portfolio_add_button {
if (empty($format)) { if (empty($format)) {
$format = PORTFOLIO_ADD_FULL_FORM; $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) { switch ($format) {
case PORTFOLIO_ADD_FULL_FORM: case PORTFOLIO_ADD_FULL_FORM:
$formoutput .= $selectoutput; $formoutput .= $selectoutput;
@ -316,6 +350,8 @@ class portfolio_add_button {
case PORTFOLIO_ADD_TEXT_LINK: case PORTFOLIO_ADD_TEXT_LINK:
$linkoutput .= '">' . $addstr .'</a>'; $linkoutput .= '">' . $addstr .'</a>';
break; break;
case PORTFOLIO_ADD_FAKE_URL:
return urldecode($linkoutput);
default: default:
debugging(get_string('invalidaddformat', 'portfolio', $format)); 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 $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 $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 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 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 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. * @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. * @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; global $CFG, $USER;
if (empty($CFG->enableportfolios)) { 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 // bail, already exporting something with this plugin and it doesn't support multiple exports
continue; continue;
} }
if ($file && $file instanceof stored_file && !$instance->file_mime_check($file->get_mimetype())) { if ($mimetype && !$instance->file_mime_check($mimetype)) {
debugging(get_string('mimecheckfail', 'portfolio', (object)array('plugin' => $instance->get('plugin'), 'mimetype' => $this->file->get_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 // bail, we have a specific file and this plugin doesn't support it
continue; continue;
} }
@ -516,23 +552,20 @@ function portfolio_supported_formats() {
* This function returns the revelant portfolio export format * This function returns the revelant portfolio export format
* which is used to determine which portfolio plugins can be used * which is used to determine which portfolio plugins can be used
* for exporting this content * for exporting this content
* according to the mime type of the given file * according to the given mime type
* this only works when exporting exactly <b>one</b> file * 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) * @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; global $CFG;
static $alreadymatched; static $alreadymatched;
if (empty($alreadymatched)) { if (empty($alreadymatched)) {
$alreadymatched = array(); $alreadymatched = array();
} }
if (!($file instanceof stored_file)) {
throw new portfolio_exception('invalidfileargument', 'portfolio');
}
$mimetype = $file->get_mimetype();
if (array_key_exists($mimetype, $alreadymatched)) { if (array_key_exists($mimetype, $alreadymatched)) {
return $alreadymatched[$mimetype]; return $alreadymatched[$mimetype];
} }
@ -862,33 +895,6 @@ function portfolio_report_insane($insane, $instances=false, $return=false) {
echo $output; 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 * event handler for the portfolio_send event

View File

@ -98,11 +98,16 @@ if($mform->is_cancelled()) {
} }
if (array_key_exists('portfolio', $formdata) && !empty($formdata['portfolio'])) { 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['id'] = $cm->id;
$formdata['exporttype'] = 'csv'; // force for now
require_once($CFG->libdir . '/portfoliolib.php'); 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); redirect($url);
} }

View File

@ -58,17 +58,21 @@ class mod_data_export_form extends moodleform {
} }
} }
$this->add_checkbox_controller(1, null, null, 1); $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))) { 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( if ($portfoliooptions = portfolio_instance_select(
portfolio_instances(), portfolio_instances(),
call_user_func(array('data_portfolio_caller', 'base_supported_formats')), call_user_func(array('data_portfolio_caller', 'base_supported_formats')),
'data_portfolio_caller', '/mod/data/locallib.php', '', true, true)) { 'data_portfolio_caller',
$mform->addElement('header', 'notice', get_string('portfolionotfile', 'data') . ':'); mimeinfo('type', 'export.csv'),
$portfoliooptions[0] = get_string('none'); 'instance',
ksort($portfoliooptions); true,
$mform->addElement('select', 'portfolio', get_string('portfolio', 'portfolio'), $portfoliooptions); 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')); $this->add_action_buttons(true, get_string('exportdatabaserecords', 'data'));

View File

@ -301,7 +301,7 @@ class data_portfolio_caller extends portfolio_module_caller_base {
} }
} }
if (count($includedfiles) == 1 && count($fields) == 1) { 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) { } else if (count($includedfiles) > 0) {
$formats = array(PORTFOLIO_FORMAT_RICHHTML); $formats = array(PORTFOLIO_FORMAT_RICHHTML);
} }
@ -309,6 +309,6 @@ class data_portfolio_caller extends portfolio_module_caller_base {
} }
public static function base_supported_formats() { 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);
} }
} }

View File

@ -211,7 +211,7 @@ if (!$exporter->get('instance')) {
portfolio_instances(), portfolio_instances(),
$exporter->get('caller')->supported_formats(), $exporter->get('caller')->supported_formats(),
get_class($exporter->get('caller')), get_class($exporter->get('caller')),
$exporter->get('caller')->get('singlefile'), $exporter->get('caller')->get_mimetype(),
'instance', 'instance',
true, true,
true true