]> git.mjollnir.org Git - moodle.git/commitdiff
more portfolio work in progress, needs rebasing portfolio
authorPenny Leach <penny@mjollnir.org>
Sun, 10 Jan 2010 21:46:19 +0000 (22:46 +0100)
committerPenny Leach <penny@mjollnir.org>
Sun, 10 Jan 2010 21:46:19 +0000 (22:46 +0100)
lib/portfolio/formats.php
lib/portfoliolib.php
mod/data/export.php
mod/data/export_form.php
mod/data/lib.php
mod/data/locallib.php
portfolio/add.php

index f4899561ff8b72219825e57d8b5c27f034780056..752bcbc32eeb0526511c7953692063e246d76167 100644 (file)
@@ -107,7 +107,7 @@ abstract class portfolio_format {
      *
      * @return boolean
      */
-    public static function conflicts($format) {
+    public function conflicts($format) {
         return false;
     }
 }
@@ -128,6 +128,15 @@ class portfolio_format_file extends portfolio_format {
     public static function file_output($file, $options=null) {
         throw new portfolio_exception('fileoutputnotsupported', 'portfolio');
     }
+
+    public function conflicts($format) {
+        if (get_class($this) == 'portfolio_format_file') { return false; }
+        $f = portfolio_format_object($format);
+        $formats = portfolio_supported_formats();
+        $const = array_search(get_class($this), $formats);
+        debugging("const is $const");
+        return portfolio_format_is_subclass($format, PORTFOLIO_FORMAT_FILE) || ($const && $f->conflicts($const));
+    }
 }
 
 /**
@@ -153,8 +162,8 @@ class portfolio_format_plainhtml extends portfolio_format_file {
         return array('text/html');
     }
 
-    public static function conflicts($format) {
-        return ($format == PORTFOLIO_FORMAT_RICHHTML);
+    public function conflicts($format) {
+        return $format == PORTFOLIO_FORMAT_RICHHTML || parent::conflicts($format);
     }
 }
 
@@ -181,9 +190,8 @@ class portfolio_format_text extends portfolio_format_file {
         return array('text/plain');
     }
 
-    public static function conflicts($format ) {
-        return ($format == PORTFOLIO_FORMAT_PLAINHTML
-            || $format == PORTFOLIO_FORMAT_RICHHTML);
+    public function conflicts($format ) {
+        return $format == PORTFOLIO_FORMAT_RICHHTML || parent::conflicts($format);
     }
 }
 
@@ -215,8 +223,8 @@ class portfolio_format_richhtml extends portfolio_format_rich {
         }
         return self::make_tag($file, $path, $attributes);
     }
-    public static function conflicts($format) { // TODO revisit the conflict with file, since we zip here
-        return ($format == PORTFOLIO_FORMAT_PLAINHTML || $format == PORTFOLIO_FORMAT_FILE);
+    public function conflicts($format) {
+        return ($format == PORTFOLIO_FORMAT_PLAINHTML || portfolio_format_is_subclass($format, PORTFOLIO_FORMAT_FILE));
     }
 
 }
index fa4065a4b774e881aaafceff827a11f04095db6c..b6b37642ad3ec50b2d36f153782dbbb93a3ea0bd 100644 (file)
@@ -136,13 +136,13 @@ class portfolio_add_button {
 
             $file = substr($backtrace[0]['file'], strlen($CFG->dirroot));
         } else if (!is_readable($CFG->dirroot . $file)) {
-            throw new portfolio_button_exception('nocallbackfile', 'portfolio', $file);
+            throw new portfolio_button_exception('nocallbackfile', 'portfolio', '', $file);
         }
         $this->callbackfile = $file;
         require_once($CFG->libdir . '/portfolio/caller.php'); // require the base class first
         require_once($CFG->dirroot . $file);
         if (!class_exists($class)) {
-            throw new portfolio_button_exception('nocallbackclass', 'portfolio', $class);
+            throw new portfolio_button_exception('nocallbackclass', 'portfolio', '', $class);
         }
 
         // this will throw exceptions
@@ -219,7 +219,7 @@ class portfolio_add_button {
      *                                  eg leap2a etc
      */
     public function set_format_by_intended_file($extn, $extraformats=null) {
-        $mimetype = mimeinfo('type', 'something. ' . $extn);
+        $mimetype = mimeinfo('type', 'something.' . $extn);
         $fileformat = portfolio_format_from_mimetype($mimetype);
         $this->intendedmimetype = $fileformat;
         if (is_string($extraformats)) {
@@ -680,14 +680,17 @@ function portfolio_most_specific_formats($specificformats, $generalformats) {
         require_once($CFG->libdir . '/portfolio/formats.php');
         $fobj = new $allformats[$f];
         foreach ($generalformats as $key => $cf) {
+            if ($f == $cf) {
+                continue;
+            }
             $cfclass = $allformats[$cf];
-            if ($fobj instanceof $cfclass && $cfclass != get_class($fobj)) {
-                debugging("unsetting $key $cf because it's not specific enough ($f is better)");
+            if ($fobj instanceof $cfclass) {
+                //debugging("unsetting $key $cf because it's not specific enough ($f is better)");
                 unset($generalformats[$key]);
             }
             // check for conflicts
             if ($fobj->conflicts($cf)) {
-                debugging("unsetting $key $cf because it conflicts with $f");
+                //debugging("unsetting $key $cf because it conflicts with $f");
                 unset($generalformats[$key]);
             }
         }
@@ -715,6 +718,13 @@ function portfolio_format_object($name) {
     return new $formats[$name];
 }
 
+function portfolio_format_is_subclass($format1, $format2) {
+    $formats = portfolio_supported_formats();
+    $f1 = portfolio_format_object($format1);
+    return ($f1 instanceof $formats[$format2]);
+
+}
+
 /**
 * helper function to return an instance of a plugin (with config loaded)
 *
index 9489d13c3854a6c7180891f3115e9e7421c64edb..fe8bb1e757ed55ea048655fb0001454336cd29af 100644 (file)
@@ -101,7 +101,8 @@ if (array_key_exists('portfolio', $formdata) && !empty($formdata['portfolio']))
     $formdata['id'] = $cm->id;
     require_once($CFG->libdir . '/portfoliolib.php');
     $button = new portfolio_add_button();
-    $button->set_callback_options('data_portfolio_caller', $formdata, '/mod/data/locallib.php');
+    $button->set_callback_options('data_full_portfolio_caller', $formdata, '/mod/data/locallib.php');
+    //todo ? allow more formats?
     if ($formdata['exporttype'] == 'csv') {
         $button->set_format_by_intended_file('csv'); // so we can do mime checking
     }
index 9c27e4189189565f9bfd7a50017b344220d49e1e..bbc14f120bf99316c877677f7f55db5871d82618 100644 (file)
@@ -61,10 +61,11 @@ class mod_data_export_form extends moodleform {
         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');
+            //@todo revisit this - maybe it should be a checkbox instead
             if ($portfoliooptions = portfolio_instance_select(
                 portfolio_instances(),
-                call_user_func(array('data_portfolio_caller', 'base_supported_formats')),
-                'data_portfolio_caller',
+                call_user_func(array('data_full_portfolio_caller', 'base_supported_formats')),
+                'data_full_portfolio_caller',
                 mimeinfo('type', 'export.csv'),
                 'instance',
                 true,
index fc3c85fad40b8373212bc761673879a44f37dbdb..e3d7394a803db5d5e4957a55e1aececba7c6126c 100755 (executable)
@@ -1252,9 +1252,14 @@ function data_print_template($template, $records, $data, $search='', $page=0, $r
                 || (data_isowner($record->id) && has_capability('mod/data:exportownentry', $context))))) {
             require_once($CFG->libdir . '/portfoliolib.php');
             $button = new portfolio_add_button();
-            $button->set_callback_options('data_portfolio_caller', array('id' => $cm->id, 'recordid' => $record->id), '/mod/data/locallib.php');
-            list($formats, $files) = data_portfolio_caller::formats($fields, $record);
-            $button->set_formats($formats);
+            $button->set_callback_options('data_entry_portfolio_caller', array('id' => $cm->id, 'recordid' => $record->id), '/mod/data/locallib.php');
+            if ($file = data_entry_portfolio_caller::is_single_file_export($fields, $record)) {
+                $button->set_format_by_file($file);
+            } else if ($files = data_entry_portfolio_caller::get_all_files($fields, $record)) {
+                $button->set_formats(PORTFOLIO_FORMAT_RICHHTML);
+            } else {
+                $button->set_formats(PORTFOLIO_FORMAT_PLAINHTML);
+            }
             $replacement[] = $button->to_html(PORTFOLIO_ADD_ICON_LINK);
         } else {
             $replacement[] = '';
index b8c34c1efee52d7c1fde718e8257539e93de5d6d..b7c9be369e1d164d6f13fda79988b30ab616f681 100644 (file)
@@ -15,6 +15,7 @@
 // You should have received a copy of the GNU General Public License
 // along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
 
+
 /**
  * @package   mod-data
  * @copyright 1999 onwards Martin Dougiamas  {@link http://moodle.com}
  */
 
 /**
- * @package   mod-data
- * @copyright 1999 onwards Martin Dougiamas  {@link http://moodle.com}
- * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ * class to handle exporting the full database
  */
+class data_full_portfolio_caller extends portfolio_module_caller_base {
 
-class data_portfolio_caller extends portfolio_module_caller_base {
-
-    /** @var int */
-    protected $recordid;
-    /** @var string */
-    protected $exporttype;
-    /** @var string */
+    /** field delimiter - used for csv */
     protected $delimiter_name;
 
-    /** @var object */
+    /** data object - represents row in database */
     private $data;
-    /**#@+ @var array */
+
+    /** selected fields to export */
     private $selectedfields;
+
+    /** array of field objects for each field */
     private $fields;
+
+    /** array of field types for each field - same keys as {@link $fields} */
     private $fieldtypes;
+
+    /** all the loaded data to export */
     private $exportdata;
+
+    /**
+     * callback arguments that are expected from the portfolio api
+     *
+     * @return array keyed on field name, value boolean required or not
+     */
+    public static function expected_callbackargs() {
+        return array(
+            'id'             => true,
+            'delimiter_name' => false, // @todo true?
+            //'exporttype'     => false, // @todo revisit this
+        );
+    }
+
+    /**
+     * @param array $callbackargs
+     */
+    public function __construct($callbackargs) {
+        parent::__construct($callbackargs);
+        if (empty($this->exporttype)) {
+            $this->exporttype = 'csv';
+        }
+        $this->selectedfields = array();
+        foreach ($callbackargs as $key => $value) {
+            if (strpos($key, 'field_') === 0) {
+                $this->selectedfields[] = substr($key, 6);
+            }
+        }
+    }
+
+    /**
+     * load up all the data required for this export
+     */
+    public function load_data() {
+        global $DB;
+        if (!$this->cm = get_coursemodule_from_id('data', $this->id)) {
+            throw new portfolio_caller_exception('invalidid', 'data');
+        }
+        $this->data = $DB->get_record('data', array('id' => $this->cm->instance));
+        $fieldrecords = $DB->get_records('data_fields', array('dataid'=>$this->cm->instance), 'id');
+        // populate objets for this databases fields
+        $this->fields = array();
+        foreach ($fieldrecords as $fieldrecord) {
+            $tmp = data_get_field($fieldrecord, $this->data);
+            $this->fields[] = $tmp;
+            $this->fieldtypes[]  = $tmp->type;
+        }
+        $this->exportdata = data_get_exportdata($this->cm->instance, $this->fields, $this->selectedfields);
+    }
+
+    /**
+     * @todo penny  later when we suport exporting to more than just csv, we may
+     * need to ask the user here if we have not already passed it
+     *
+     * @return bool
+     */
+    public function has_export_config() {
+        return false;
+    }
+
+    /**
+     * how long we expect this export to take
+     * @return one of PORTFOLIO_TIME_XX constant
+     */
+    public function expected_time() {
+        return portfolio_expected_time_db(count($this->exportdata));
+    }
+
+    /**
+     * calculate the sha1 of this export
+     *
+     * @return string
+     */
+    public function get_sha1() {
+        $str = '';
+        foreach ($this->exportdata as $data) {
+            if (is_array($data) || is_object($data)) {
+                $testkey = array_pop(array_keys($data));
+                if (is_array($data[$testkey]) || is_object($data[$testkey])) {
+                    foreach ($data as $d) {
+                        $str .= implode(',', (array)$d);
+                    }
+                } else {
+                    $str .= implode(',', (array)$data);
+                }
+            } else {
+                $str .= $data;
+            }
+        }
+        return sha1($str . ',' . $this->exporttype);
+    }
+
+    /**
+     * prepare the package for exporting off to the portfolio plugin
+     */
+    public function prepare_package() {
+        global $DB;
+        $count = count($this->exportdata);
+        $content = '';
+        $filename = '';
+        switch ($this->exporttype) {
+            case 'csv':
+                $content = data_export_csv($this->exportdata, $this->delimiter_name, $this->cm->name, $count, true);
+                $filename = clean_filename($this->cm->name . '.csv');
+                break;
+            case 'xls':
+                // todo why?
+                throw new portfolio_caller_exception('notimplemented', 'portfolio', '', 'xls');
+                $content = data_export_xls($this->exportdata, $this->cm->name, $count, true);
+                break;
+            case 'ods':
+                // todo why
+                throw new portfolio_caller_exception('notimplemented', 'portfolio', '', 'ods');
+                $content = data_export_ods($this->exportdata, $this->cm->name, $count, true);
+                break;
+            default:
+                throw new portfolio_caller_exception('notimplemented', 'portfolio', '', $this->exporttype);
+            break;
+        }
+        return $this->exporter->write_new_file(
+            $content,
+            $filename,
+            ($this->exporter->get('format') instanceof PORTFOLIO_FORMAT_RICH) // if we have associate files, this is a 'manifest'
+        );
+        // todo attachments?!
+    }
+
+    /**
+     * make sure the user can still export this database
+     * @return bool
+     */
+    public function check_permissions() {
+        return has_capability('mod/data:exportallentries', get_context_instance(CONTEXT_MODULE, $this->cm->id));
+    }
+
+    /**
+     * display name for showing in navigation
+     *  @return string
+     */
+    public static function display_name() {
+        return get_string('modulename', 'data');
+    }
+
+    /**
+     * perform any necessary __wakeup duties - load up the data field class definitions
+     * @return void
+     */
+    public function __wakeup() {
+        global $CFG;
+        if (empty($CFG)) {
+            return; // too early yet
+        }
+        foreach ($this->fieldtypes as $key => $field) {
+            require_once($CFG->dirroot . '/mod/data/field/' . $field .'/field.class.php');
+            $this->fields[$key] = unserialize(serialize($this->fields[$key]));
+        }
+    }
+
+    public static function base_supported_formats() {
+        return array(PORTFOLIO_FORMAT_SPREADSHEET);
+    }
+}
+
+
+
+/**
+ * class to handle the exporting of a single entry
+ */
+class data_entry_portfolio_caller extends portfolio_module_caller_base {
+
+    /** id of entry to export */
+    protected $recordid;
+
+    /** the mdl_data record for this entry */
+    private $data;
+
+    /** selected fields to export */
+    private $selectedfields;
+
+    /** array of field objects for each field */
+    private $fields;
+
+    /** array of field types for each field - same keys as {@link $fields} */
+    private $fieldtypes;
+
+    /** type of export - single or singlefile */
+    private $exportype;
+
     /**#@-*/
     /**#@+ @var object */
     private $singlerecord;
@@ -55,8 +244,6 @@ class data_portfolio_caller extends portfolio_module_caller_base {
         return array(
             'id'             => true,
             'recordid'       => false,
-            'delimiter_name' => false,
-            'exporttype'     => false,
         );
     }
     /**
@@ -64,9 +251,6 @@ class data_portfolio_caller extends portfolio_module_caller_base {
      */
     public function __construct($callbackargs) {
         parent::__construct($callbackargs);
-        if (empty($this->exporttype)) {
-            $this->exporttype = 'csv';
-        }
         $this->selectedfields = array();
         foreach ($callbackargs as $key => $value) {
             if (strpos($key, 'field_') === 0) {
@@ -93,30 +277,19 @@ class data_portfolio_caller extends portfolio_module_caller_base {
             $this->fieldtypes[]  = $tmp->type;
         }
 
-        if ($this->recordid) {
-            //user has selected to export one single entry rather than the whole thing
-            // which is completely different
-            $this->singlerecord = $DB->get_record('data_records', array('id' => $this->recordid));
-            $this->singlerecord->content = $DB->get_records('data_content', array('recordid' => $this->singlerecord->id));
-            $this->exporttype = 'single';
-
-            list($formats, $files) = self::formats($this->fields, $this->singlerecord);
-            if (count($files) == 1 && count($this->fields) == 1) {
-                $this->singlefile = $files[0];
-                $this->exporttype = 'singlefile';
-            } else if (count($files) > 0) {
-                $this->multifiles = $files;
-            }
+        $this->singlerecord = $DB->get_record('data_records', array('id' => $this->recordid));
+        $this->singlerecord->content = $DB->get_records('data_content', array('recordid' => $this->singlerecord->id));
+        $this->exporttype = 'single';
+
+        if ($singlefile = self::is_single_file_export($this->fields, $this->singlerecord)) {
+            $this->singlefile = $singlefile;
+            $this->exporttype = 'singlefile';
         } else {
-            // all records as csv or whatever
-            $this->exportdata = data_get_exportdata($this->cm->instance, $this->fields, $this->selectedfields);
+            $this->multifiles = self::get_all_files($this->fields, $this->singlerecord);
         }
     }
 
     /**
-     * @todo penny  later when we suport exporting to more than just csv, we may
-     * need to ask the user here if we have not already passed it
-     *
      * @return bool
      */
     public function has_export_config() {
@@ -128,25 +301,22 @@ class data_portfolio_caller extends portfolio_module_caller_base {
      * @return mixed
      */
     public function expected_time() {
-        if ($this->exporttype == 'single') {
-            return PORTFOLIO_TIME_LOW;
+        if ($this->multifiles || $this->singlefile) {
+            return $this->expected_time_file();
         }
-        return portfolio_expected_time_db(count($this->exportdata));
+        return PORTFOLIO_TIME_LOW;
     }
 
     /**
+     * sha1 of this export
      * @return string
      */
     public function get_sha1() {
         if ($this->exporttype == 'singlefile') {
             return $this->singlefile->get_contenthash();
         }
-        $loopdata = $this->exportdata;
-        if ($this->exporttype == 'single') {
-            $loopdata = $this->singlerecord;
-        }
         $str = '';
-        foreach ($loopdata as $data) {
+        foreach ($this->singlerecord as $data) {
             if (is_array($data) || is_object($data)) {
                 $testkey = array_pop(array_keys($data));
                 if (is_array($data[$testkey]) || is_object($data[$testkey])) {
@@ -162,12 +332,12 @@ class data_portfolio_caller extends portfolio_module_caller_base {
         }
         return sha1($str . ',' . $this->exporttype);
     }
+
     /**
-     * @global object
+     * do whatever necessary to get the package ready to be picked up by the portfolio plugin
      */
     public function prepare_package() {
         global $DB;
-        $count = count($this->exportdata);
         $content = '';
         $filename = '';
         switch ($this->exporttype) {
@@ -177,18 +347,6 @@ class data_portfolio_caller extends portfolio_module_caller_base {
                 $content = $this->exportsingle();
                 $filename = clean_filename($this->cm->name . '-entry.html');
                 break;
-            case 'csv':
-                $content = data_export_csv($this->exportdata, $this->delimiter_name, $this->cm->name, $count, true);
-                $filename = clean_filename($this->cm->name . '.csv');
-                break;
-            case 'xls':
-                throw new portfolio_caller_exception('notimplemented', 'portfolio', '', 'xls');
-                $content = data_export_xls($this->exportdata, $this->cm->name, $count, true);
-                break;
-            case 'ods':
-                throw new portfolio_caller_exception('notimplemented', 'portfolio', '', 'ods');
-                $content = data_export_ods($this->exportdata, $this->cm->name, $count, true);
-                break;
             default:
                 throw new portfolio_caller_exception('notimplemented', 'portfolio', '', $this->exporttype);
             break;
@@ -201,13 +359,18 @@ class data_portfolio_caller extends portfolio_module_caller_base {
     }
 
     /**
-     * @return bool
+     * make sure that the user can still export this entry
+     *
+     * @return boolean
      */
     public function check_permissions() {
-        return has_capability('mod/data:exportallentries', get_context_instance(CONTEXT_MODULE, $this->cm->id));
+        $c = get_context_instance(CONTEXT_MODULE, $this->cm->id);
+        return (has_capability('mod/data:exportentry', $c)
+            || ($this->singlerecord->userid == $this->exporter->get('user')->id && has_capability('mod/data:exportownentry', $c)));
     }
 
     /**
+     * nice display name for navigation
      *  @return string
      */
     public static function display_name() {
@@ -216,12 +379,12 @@ class data_portfolio_caller extends portfolio_module_caller_base {
 
     /**
      * @global object
-     * @return bool|void
+     * @return void
      */
     public function __wakeup() {
         global $CFG;
         if (empty($CFG)) {
-            return true; // too early yet
+            return; // too early yet
         }
         foreach ($this->fieldtypes as $key => $field) {
             require_once($CFG->dirroot . '/mod/data/field/' . $field .'/field.class.php');
@@ -286,29 +449,46 @@ class data_portfolio_caller extends portfolio_module_caller_base {
     }
 
     /**
-     * @param array $fields
-     * @param object $record
-     * @uses PORTFOLIO_FORMAT_PLAINHTML
-     * @uses PORTFOLIO_FORMAT_RICHHTML
-     * @return array
+     * helper function to retrieve the files used in this export
+     *
+     * @param array $fields the fields belonging to this data entry
+     * @param object $record the entry record
+     *
+     * @return array of $file records
      */
-    public static function formats($fields, $record) {
-        $formats = array(PORTFOLIO_FORMAT_PLAINHTML);
-        $includedfiles = array();
-        foreach ($fields as $singlefield) {
-            if (is_callable(array($singlefield, 'get_file'))) {
-                $includedfiles[] = $singlefield->get_file($record->id);
+    public static function get_all_files($fields, $record) {
+        static $files = array();
+        if (!array_key_exists($record->id, $files)) {
+            $files[$record->id] = array();
+            foreach ($fields as $singlefield) {
+                if (is_callable(array($singlefield, 'get_file'))) {
+                    $files[$record->id][] = $singlefield->get_file($record->id);
+                }
             }
         }
-        if (count($includedfiles) == 1 && count($fields) == 1) {
-            $formats= array(portfolio_format_from_mimetype($includedfiles[0]->get_mimetype()));
-        } else if (count($includedfiles) > 0) {
-            $formats = array(PORTFOLIO_FORMAT_RICHHTML);
+        return $files[$record->id];
+    }
+
+    /**
+     * tiny helper function to figure out if this is a single file export
+     *
+     * @param array $fields the fields belonging to this data entry
+     * @param object $record the entry record
+     *
+     * @return mixed stored_file or false
+     */
+    public static function is_single_file_export($fields, $record) {
+        $files = self::get_all_files($fields, $record);
+        //print_object($files);
+       // print_object($fields);
+        debugging("files count was " . count($files)  . " and fields count was " . count($fields));
+        if (count($files) == 1 && count($fields) == 1) {
+            return array_shift($files);
         }
-        return array($formats, $includedfiles);
+        return false;
     }
 
     public static function base_supported_formats() {
-        return array(PORTFOLIO_FORMAT_SPREADSHEET, PORTFOLIO_FORMAT_RICHHTML, PORTFOLIO_FORMAT_PLAINHTML);
+        return array(PORTFOLIO_FORMAT_RICHHTML, PORTFOLIO_FORMAT_PLAINHTML);
     }
 }
index ec0c9293f01918f79f617870e13817be98dee49b..379fb78504e773626cd0dca6a493b0b633320cca 100644 (file)
@@ -94,7 +94,7 @@ if (!empty($dataid)) {
         } else {
             $exporter->print_header('confirmcancel');
             echo $OUTPUT->box_start();
-            $yesbutton = new single_button(new moodle_url($CFG->wwwroot . '/portfolio/add.php', array('id' => $dataid, 'cancel' => 1, 'cancelsure' => 1, 'logreturn' => $logreturn)). get_string('yes'));
+            $yesbutton = new single_button(new moodle_url($CFG->wwwroot . '/portfolio/add.php', array('id' => $dataid, 'cancel' => 1, 'cancelsure' => 1, 'logreturn' => $logreturn)), get_string('yes'));
             $nobutton  = new single_button(new moodle_url($CFG->wwwroot . '/portfolio/add.php', array('id' => $dataid)), get_string('no'));
             if ($logreturn) {
                 $nobutton->url = $CFG->wwwroot . '/user/portfoliologs.php';