MDL-37030 Assignment: Fix error on download all submissions.
[moodle.git] / mod / assign / assignmentplugin.php
1 <?php
2 // This file is part of Moodle - http://moodle.org/
3 //
4 // Moodle is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU General Public License as published by
6 // the Free Software Foundation, either version 3 of the License, or
7 // (at your option) any later version.
8 //
9 // Moodle is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 // GNU General Public License for more details.
13 //
14 // You should have received a copy of the GNU General Public License
15 // along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
17 /**
18  * This file contains the functions for assign_plugin abstract class
19  *
20  *
21  * @package   mod_assign
22  * @copyright 2012 NetSpot {@link http://www.netspot.com.au}
23  * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
24  */
26 defined('MOODLE_INTERNAL') || die();
28 /**
29  * Abstract class for assign_plugin (submission/feedback).
30  *
31  * @package   mod_assign
32  * @copyright 2012 NetSpot {@link http://www.netspot.com.au}
33  * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
34  */
35 abstract class assign_plugin {
37     /** @var assign $assignment the assignment record that contains the global settings for this assign instance */
38     protected $assignment;
39     /** @var string $type assignment plugin type */
40     private $type = '';
41     /** @var string $error error message */
42     private $error = '';
45     /**
46      * Constructor for the abstract plugin type class
47      *
48      * @param assign $assignment
49      * @param string $type
50      */
51     public final function __construct(assign $assignment, $type) {
52         $this->assignment = $assignment;
53         $this->type = $type;
54     }
56     /**
57      * Is this the first plugin in the list?
58      *
59      * @return bool
60      */
61     public final function is_first() {
62         $order = get_config($this->get_subtype() . '_' . $this->get_type(), 'sortorder');
64         if ($order == 0) {
65             return true;
66         }
67         return false;
68     }
70     /**
71      * Is this the last plugin in the list?
72      *
73      * @return bool
74      */
75     public final function is_last() {
76         if ((count(get_plugin_list($this->get_subtype()))-1) == get_config($this->get_subtype() . '_' . $this->get_type(), 'sortorder')) {
77             return true;
78         }
80         return false;
81     }
83     /**
84      * This function should be overridden to provide an array of elements that can be added to a moodle
85      * form for display in the settings page for the assignment.
86      * @param MoodleQuickForm $mform The form to add the elements to
87      * @return $array
88      */
89     public function get_settings(MoodleQuickForm $mform) {
90         return;
91     }
93     /**
94      * Allows the plugin to update the defaultvalues passed in to
95      * the settings form (needed to set up draft areas for editor
96      * and filemanager elements)
97      * @param array $defaultvalues
98      */
99     public function data_preprocessing(&$defaultvalues) {
100         return;
101     }
103     /**
104      * The assignment subtype is responsible for saving it's own settings as the database table for the
105      * standard type cannot be modified.
106      *
107      * @param stdClass $formdata - the data submitted from the form
108      * @return bool - on error the subtype should call set_error and return false.
109      */
110     public function save_settings(stdClass $formdata) {
111         return true;
112     }
114     /**
115      * Save the error message from the last error
116      *
117      * @param string $msg - the error description
118      */
119     protected final function set_error($msg) {
120         $this->error = $msg;
121     }
123     /**
124      * What was the last error?
125      *
126      *
127      * @return string
128      */
129     public final function get_error() {
130         return $this->error;
131     }
133     /**
134      * Should return the name of this plugin type.
135      *
136      * @return string - the name
137      */
138     public abstract function get_name();
140     /**
141      * Should return the subtype of this plugin.
142      *
143      * @return string - either 'assignsubmission' or 'feedback'
144      */
145     public abstract function get_subtype();
147     /**
148      * Should return the type of this plugin.
149      *
150      * @return string - the type
151      */
152     public final function get_type() {
153         return $this->type;
154     }
156     /**
157      * Get the installed version of this plugin
158      *
159      * @return string
160      */
161     public final function get_version() {
162         $version = get_config($this->get_subtype() . '_' . $this->get_type(), 'version');
163         if ($version) {
164             return $version;
165         } else {
166             return '';
167         }
168     }
170     /**
171      * Get the required moodle version for this plugin
172      *
173      * @return string
174      */
175     public final function get_requires() {
176         $requires = get_config($this->get_subtype() . '_' . $this->get_type(), 'requires');
177         if ($requires) {
178             return $requires;
179         } else {
180             return '';
181         }
182     }
184     /**
185      * Save any custom data for this form submission
186      *
187      * @param stdClass $submissionorgrade - assign_submission or assign_grade
188      *              For submission plugins this is the submission data, for feedback plugins it is the grade data
189      * @param stdClass $data - the data submitted from the form
190      * @return bool - on error the subtype should call set_error and return false.
191      */
192     public function save(stdClass $submissionorgrade, stdClass $data) {
193         return true;
194     }
196     /**
197      * Set this plugin to enabled
198      *
199      * @return bool
200      */
201     public final function enable() {
202         return $this->set_config('enabled', 1);
203     }
205     /**
206      * Set this plugin to disabled
207      *
208      * @return bool
209      */
210     public final function disable() {
211         return $this->set_config('enabled', 0);
212     }
214     /**
215      * Allows hiding this plugin from the submission/feedback screen if it is not enabled.
216      *
217      * @return bool - if false - this plugin will not accept submissions / feedback
218      */
219     public function is_enabled() {
220         return $this->get_config('enabled');
221     }
224     /**
225      * Get any additional fields for the submission/grading form for this assignment.
226      *
227      * @param mixed $submissionorgrade submission|grade - For submission plugins this is the submission data,
228      *                                                    for feedback plugins it is the grade data
229      * @param MoodleQuickForm $mform - This is the form
230      * @param stdClass $data - This is the form data that can be modified for example by a filemanager element
231      * @param int $userid - This is the userid for the current submission.
232      *                      This is passed separately as there may not yet be a submission or grade.
233      * @return boolean - true if we added anything to the form
234      */
235     public function get_form_elements_for_user($submissionorgrade, MoodleQuickForm $mform, stdClass $data, $userid) {
236         return $this->get_form_elements($submissionorgrade, $mform, $data);
237     }
239     /**
240      * Get any additional fields for the submission/grading form for this assignment.
241      * This function is retained for backwards compatibility - new plugins should override {@link get_form_elements_for_user()}.
242      *
243      * @param mixed $submissionorgrade submission|grade - For submission plugins this is the submission data, for feedback plugins it is the grade data
244      * @param MoodleQuickForm $mform - This is the form
245      * @param stdClass $data - This is the form data that can be modified for example by a filemanager element
246      * @return boolean - true if we added anything to the form
247      */
248     public function get_form_elements($submissionorgrade, MoodleQuickForm $mform, stdClass $data) {
249         return false;
250     }
252     /**
253      * Should not output anything - return the result as a string so it can be consumed by webservices.
254      *
255      * @param stdClass $submissionorgrade assign_submission or assign_grade
256      *                 For submission plugins this is the submission data, for feedback plugins it is the grade data
257      * @return string - return a string representation of the submission in full
258      */
259     public function view(stdClass $submissionorgrade) {
260         return '';
261     }
263     /**
264      * Get the numerical sort order for this plugin
265      *
266      * @return int
267      */
268     public final function get_sort_order() {
269         $order = get_config($this->get_subtype() . '_' . $this->get_type(), 'sortorder');
270         return $order?$order:0;
271     }
273     /**
274      * Is this plugin enaled?
275      *
276      * @return bool
277      */
278     public final function is_visible() {
279         $disabled = get_config($this->get_subtype() . '_' . $this->get_type(), 'disabled');
280         return !$disabled;
281     }
284     /**
285      * Has this plugin got a custom settings.php file?
286      *
287      * @return bool
288      */
289     public final function has_admin_settings() {
290         global $CFG;
292         return file_exists($CFG->dirroot . '/mod/assign/' . substr($this->get_subtype(), strlen('assign')) . '/' . $this->get_type() . '/settings.php');
293     }
295     /**
296      * Set a configuration value for this plugin
297      *
298      * @param string $name The config key
299      * @param string $value The config value
300      * @return bool
301      */
302     public final function set_config($name, $value) {
303         global $DB;
305         $current = $DB->get_record('assign_plugin_config', array('assignment'=>$this->assignment->get_instance()->id, 'subtype'=>$this->get_subtype(), 'plugin'=>$this->get_type(), 'name'=>$name), '*', IGNORE_MISSING);
307         if ($current) {
308             $current->value = $value;
309             return $DB->update_record('assign_plugin_config', $current);
310         } else {
311             $setting = new stdClass();
312             $setting->assignment = $this->assignment->get_instance()->id;
313             $setting->subtype = $this->get_subtype();
314             $setting->plugin = $this->get_type();
315             $setting->name = $name;
316             $setting->value = $value;
318             return $DB->insert_record('assign_plugin_config', $setting) > 0;
319         }
320     }
322     /**
323      * Get a configuration value for this plugin
324      *
325      * @param mixed $setting The config key (string) or null
326      * @return mixed string | false
327      */
328     public final function get_config($setting = null) {
329         global $DB;
331         if ($setting) {
332             if (!$this->assignment->has_instance()) {
333                 return false;
334             }
335             $assignment = $this->assignment->get_instance();
336             if ($assignment) {
337                 $result = $DB->get_record('assign_plugin_config', array('assignment'=>$assignment->id, 'subtype'=>$this->get_subtype(), 'plugin'=>$this->get_type(), 'name'=>$setting), '*', IGNORE_MISSING);
338                 if ($result) {
339                     return $result->value;
340                 }
341             }
342             return false;
343         }
344         $results = $DB->get_records('assign_plugin_config', array('assignment'=>$this->assignment->get_instance()->id, 'subtype'=>$this->get_subtype(), 'plugin'=>$this->get_type()));
346         $config = new stdClass();
347         if (is_array($results)) {
348             foreach ($results as $setting) {
349                 $name = $setting->name;
350                 $config->$name = $setting->value;
351             }
352         }
353         return $config;
354     }
356     /**
357      * Should not output anything - return the result as a string so it can be consumed by webservices.
358      *
359      * @param stdClass $submissionorgrade assign_submission or assign_grade
360      *                 For submission plugins this is the submission data, for feedback plugins it is the grade data
361      * @param bool $showviewlink Modifed to return whether or not to show a link to the full submission/feedback
362      * @return string - return a string representation of the submission in full
363      */
364     public function view_summary(stdClass $submissionorgrade, & $showviewlink) {
365         return '';
366     }
368     /**
369      * Given a field name and value should update the text for this field in the plugins submission or grade
370      *
371      * @param string $name Name of the field.
372      * @param string $value Updated text
373      * @param int $submissionorgradeid The id of the submission or grade
374      * @return bool - true if the value was updated
375      */
376     public function set_editor_text($name, $value, $submissionorgradeid) {
377         return false;
378     }
380     /**
381      * Given a field name and value should update the format for this field in the plugins submission or grade
382      *
383      * @param string $name Name of the field.
384      * @param int $format Updated format.
385      * @param int $submissionorgradeid The id of the submission or grade.
386      * @return bool - true if the value was updated
387      */
388     public function set_editor_format($name, $format, $submissionorgradeid) {
389         return false;
390     }
392     /**
393      * Return a list of the fields that can be exported or imported via text.
394      *
395      * @return array - The list of field names (strings) and descriptions. ($name => $description)
396      */
397     public function get_editor_fields() {
398         return array();
399     }
401     /**
402      * Given a field name, should return the text of an editor field that is part of
403      * this plugin. This is used when exporting to portfolio.
404      *
405      * @param string $name Name of the field.
406      * @param int $submissionorgradeid The id of the submission or grade
407      * @return string - The text for the editor field
408      */
409     public function get_editor_text($name, $submissionorgradeid) {
410         return '';
411     }
413     /**
414      * Produce a list of files suitable for export that represent this feedback or submission
415      *
416      * @param stdClass $submissionorgrade assign_submission or assign_grade
417      *                 For submission plugins this is the submission data, for feedback plugins it is the grade data
418      * @param stdClass $user The user record for the current submission.
419      *                         Needed for url rewriting if this is a group submission.
420      * @return array - return an array of files indexed by filename
421      */
422     public function get_files(stdClass $submissionorgrade, stdClass $user) {
423         return array();
424     }
426     /**
427      * Given a field name, should return the format of an editor field that is part of
428      * this plugin. This is used when exporting to portfolio.
429      *
430      * @param string $name Name of the field.
431      * @param int $submissionid The id of the submission
432      * @return int - The format for the editor field
433      */
434     public function get_editor_format($name, $submissionid) {
435         return 0;
436     }
438     /**
439      * Return true if this plugin can upgrade an old Moodle 2.2 assignment of this type
440      * and version.
441      *
442      * @param string $type The old assignment subtype
443      * @param int $version The old assignment version
444      * @return bool True if upgrade is possible
445      */
446     public function can_upgrade($type, $version) {
447         return false;
448     }
450     /**
451      * Upgrade the settings from the old assignment to the new one
452      *
453      * @param context $oldcontext The context for the old assignment module
454      * @param stdClass $oldassignment The data record for the old assignment
455      * @param string $log Record upgrade messages in the log
456      * @return bool true or false - false will trigger a rollback
457      */
458     public function upgrade_settings(context $oldcontext, stdClass $oldassignment, & $log) {
459         $log = $log . ' ' . get_string('upgradenotimplemented', 'mod_assign', array('type'=>$this->type, 'subtype'=>$this->get_subtype()));
460         return false;
461     }
463     /**
464      * Upgrade the submission from the old assignment to the new one
465      *
466      * @param context $oldcontext The data record for the old context
467      * @param stdClass $oldassignment The data record for the old assignment
468      * @param stdClass $oldsubmissionorgrade The data record for the old submission
469      * @param stdClass $submissionorgrade assign_submission or assign_grade The new submission or grade
470      * @param string $log Record upgrade messages in the log
471      * @return boolean true or false - false will trigger a rollback
472      */
473     public function upgrade(context $oldcontext, stdClass $oldassignment, stdClass $oldsubmissionorgrade, stdClass $submissionorgrade, & $log) {
474         $log = $log . ' ' . get_string('upgradenotimplemented', 'mod_assign', array('type'=>$this->type, 'subtype'=>$this->get_subtype()));
475         return false;
476     }
478     /**
479      * Formatting for log info
480      *
481      * @param stdClass $submissionorgrade assign_submission or assign_grade The new submission or grade
482      * @return string
483      */
484     public function format_for_log(stdClass $submissionorgrade) {
485         // format the info for each submission plugin add_to_log
486         return '';
487     }
489     /**
490      * The assignment has been deleted - remove the plugin specific data
491      *
492      * @return bool
493      */
494     public function delete_instance() {
495         return true;
496     }
498     /**
499      * Run cron for this plugin
500      */
501     public static function cron() {
502     }
504     /**
505      * Is this assignment plugin empty? (ie no submission or feedback)
506      * @param stdClass $submissionorgrade assign_submission or assign_grade
507      * @return bool
508      */
509     public function is_empty(stdClass $submissionorgrade) {
510         return true;
511     }
513     /**
514      * Get file areas returns a list of areas this plugin stores files
515      * @return array - An array of fileareas (keys) and descriptions (values)
516      */
517     public function get_file_areas() {
518         return array();
519     }
522     /**
523      * Default implementation of file_get_info for plugins.
524      * This is used by the filebrowser to browse a plugins file areas.
525      *
526      * This implementation should work for most plugins but can be overridden if required.
527      * @param file_browser $browser
528      * @param string $filearea
529      * @param int $itemid
530      * @param string $filepath
531      * @param string $filename
532      * @return file_info_stored
533      */
534     public function get_file_info($browser, $filearea, $itemid, $filepath, $filename) {
535         global $CFG, $DB, $USER;
536         $urlbase = $CFG->wwwroot.'/pluginfile.php';
538         // permission check on the itemid
540         if ($this->get_subtype() == 'assignsubmission') {
541             if ($itemid) {
542                 $record = $DB->get_record('assign_submission', array('id'=>$itemid), 'userid', IGNORE_MISSING);
543                 if (!$record) {
544                     return null;
545                 }
546                 if (!$this->assignment->can_view_submission($record->userid)) {
547                     return null;
548                 }
549             }
550         } else {
551             // not supported for feedback plugins
552             return null;
553         }
555         $fs = get_file_storage();
556         $filepath = is_null($filepath) ? '/' : $filepath;
557         $filename = is_null($filename) ? '.' : $filename;
558         if (!($storedfile = $fs->get_file($this->assignment->get_context()->id,
559                                           $this->get_subtype() . '_' . $this->get_type(),
560                                           $filearea,
561                                           $itemid,
562                                           $filepath,
563                                           $filename))) {
564             return null;
565         }
566         return new file_info_stored($browser,
567                                     $this->assignment->get_context(),
568                                     $storedfile,
569                                     $urlbase,
570                                     $filearea,
571                                     $itemid,
572                                     true,
573                                     true,
574                                     false);
575     }
577     /**
578      * This allows a plugin to render a page in the context of the assignment
579      *
580      * If the plugin creates a link to the assignment view.php page with
581      * The following required parameters:
582      *      id=coursemoduleid
583      *      plugin=type
584      *      pluginsubtype=assignfeedback|assignsubmission
585      *      pluginaction=customaction
586      *
587      * Then this function will be called to display the page with the pluginaction passed as action
588      * @param string $action The plugin specified action
589      * @return string
590      */
591     public function view_page($action) {
592         return '';
593     }
595     /**
596      * If this plugin should not include a column in the grading table or a row on the summary page
597      * then return false
598      *
599      * @return bool
600      */
601     public function has_user_summary() {
602         return true;
603     }