Skip to content

Commit

Permalink
portfolio MDL-20896 added the ability to set mime info for "intended"…
Browse files Browse the repository at this point in the history
… 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)
  • Loading branch information
Penny Leach committed Dec 15, 2009
1 parent ecea942 commit 521a6ab
Show file tree
Hide file tree
Showing 8 changed files with 110 additions and 78 deletions.
1 change: 0 additions & 1 deletion lang/en_utf8/portfolio.php
Expand Up @@ -83,7 +83,6 @@
$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';
Expand Down
13 changes: 13 additions & 0 deletions lib/portfolio/caller.php
Expand Up @@ -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) {
Expand Down Expand Up @@ -473,6 +478,14 @@ protected function add_format($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
* this must be keyed on the argument name, and the array value is a boolean,
Expand Down
5 changes: 5 additions & 0 deletions lib/portfolio/constants.php
Expand Up @@ -213,3 +213,8 @@
*/
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);
134 changes: 70 additions & 64 deletions lib/portfoliolib.php
Expand Up @@ -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.
Expand Down Expand Up @@ -163,7 +164,8 @@ public function set_callback_options($class, array $argarray, $file=null) {
* @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)) {
Expand All @@ -179,6 +181,10 @@ public function set_formats($formats=null) {
$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();
}
Expand All @@ -195,13 +201,33 @@ public function reset_formats() {
*/
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)) {
$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)) {
$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));
}

/*
Expand Down Expand Up @@ -238,27 +264,27 @@ public function to_html($format=null, $addstr=null) {
// 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;
$a->value = print_r($value, true);
debugging(get_string('nonprimative', 'portfolio', $a));
return;
}
$linkoutput .= 'ca_' . $key . '=' . $value . '&amp;';
$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() . '&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 = '';
if (count($this->instances) == 1) {
$tmp = array_values($this->instances);
Expand All @@ -279,26 +305,34 @@ public function to_html($format=null, $addstr=null) {
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 .= '&amp;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');
}
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;
Expand All @@ -316,6 +350,8 @@ public function to_html($format=null, $addstr=null) {
case PORTFOLIO_ADD_TEXT_LINK:
$linkoutput .= '">' . $addstr .'</a>';
break;
case PORTFOLIO_ADD_FAKE_URL:
return urldecode($linkoutput);
default:
debugging(get_string('invalidaddformat', 'portfolio', $format));
}
Expand Down Expand Up @@ -383,14 +419,14 @@ public function get_callbackclass() {
* @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)) {
Expand Down Expand Up @@ -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;
}
Expand Down Expand Up @@ -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];
}
Expand Down Expand Up @@ -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
Expand Down
11 changes: 8 additions & 3 deletions mod/data/export.php
Expand Up @@ -98,11 +98,16 @@
}

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);
}

Expand Down
18 changes: 11 additions & 7 deletions mod/data/export_form.php
Expand Up @@ -58,17 +58,21 @@ function definition() {
}
}
$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'));
Expand Down
4 changes: 2 additions & 2 deletions mod/data/locallib.php
Expand Up @@ -301,14 +301,14 @@ public static function formats($fields, $record) {
}
}
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);
}
return array($formats, $includedfiles);
}

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);
}
}
2 changes: 1 addition & 1 deletion portfolio/add.php
Expand Up @@ -211,7 +211,7 @@
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
Expand Down

0 comments on commit 521a6ab

Please sign in to comment.