MDL-53638 mod_feedback: download responses

This commit is contained in:
Marina Glancy 2016-04-09 18:40:31 +08:00
parent 1e3de9d8ba
commit 3fdba72902
11 changed files with 371 additions and 489 deletions

View File

@ -59,14 +59,6 @@ require('tabs.php');
$mygroupid = groups_get_activity_group($cm, true);
groups_print_activity_menu($cm, $url);
if ( has_capability('mod/feedback:viewreports', $context) ) {
//button "export to excel"
echo $OUTPUT->container_start('form-buttons');
$aurl = new moodle_url('analysis_to_excel.php', array('sesskey'=>sesskey(), 'id'=>$id));
echo $OUTPUT->single_button($aurl, get_string('export_to_excel', 'feedback'));
echo $OUTPUT->container_end();
}
// Show the summary.
$summary = new mod_feedback\output\summary($feedbackstructure, $mygroupid);
echo $OUTPUT->render_from_template('mod_feedback/summary', $summary->export_for_template($OUTPUT));

View File

@ -30,7 +30,6 @@ $current_tab = 'analysis';
$id = required_param('id', PARAM_INT); //the POST dominated the GET
$courseitemfilter = optional_param('courseitemfilter', '0', PARAM_INT);
$courseitemfiltertyp = optional_param('courseitemfiltertyp', '0', PARAM_ALPHANUM);
$searchcourse = optional_param('searchcourse', '', PARAM_RAW);
$courseid = optional_param('courseid', false, PARAM_INT);
$url = new moodle_url('/mod/feedback/analysis_course.php', array('id'=>$id));
@ -44,9 +43,6 @@ if ($courseitemfilter !== '0') {
if ($courseitemfiltertyp !== '0') {
$url->param('courseitemfiltertyp', $courseitemfiltertyp);
}
if ($searchcourse !== '') {
$url->param('searchcourse', $searchcourse);
}
$PAGE->set_url($url);
list($course, $cm) = get_course_and_cm_from_cmid($id, 'feedback');
@ -62,6 +58,12 @@ if (!($feedback->publish_stats OR has_capability('mod/feedback:viewreports', $co
$feedbackstructure = new mod_feedback_structure($feedback, $PAGE->cm, $courseid);
// Process course select form.
$courseselectform = new mod_feedback_course_select_form($url, $feedbackstructure);
if ($data = $courseselectform->get_data()) {
redirect(new moodle_url($url, ['courseid' => $data->courseid]));
}
/// Print the page header
$strfeedbacks = get_string("modulenameplural", "feedback");
$strfeedback = get_string("modulename", "feedback");
@ -74,21 +76,12 @@ echo $OUTPUT->heading(format_string($feedback->name));
/// print the tabs
require('tabs.php');
//print the analysed items
if (has_capability('mod/feedback:viewreports', $context)) {
//button "export to excel"
echo $OUTPUT->container_start('form-buttons');
$aurl = new moodle_url('analysis_to_excel.php', array('sesskey' => sesskey(), 'id' => $id,
'coursefilter' => $courseid));
echo $OUTPUT->single_button($aurl, get_string('export_to_excel', 'feedback'));
echo $OUTPUT->container_end();
}
//get the groupid
//lstgroupid is the choosen id
$mygroupid = false;
$courseselectform->display();
// Show the summary.
$summary = new mod_feedback\output\summary($feedbackstructure);
echo $OUTPUT->render_from_template('mod_feedback/summary', $summary->export_for_template($OUTPUT));
@ -131,43 +124,6 @@ if ($courseitemfilter > 0) {
echo '</a></p>';
} else {
echo '<div class="mdl-align">';
echo '<form name="report" method="get" id="analysis-form">';
echo html_writer::label(get_string('search_course', 'feedback') . ': ', 'searchcourse');
echo '<input id="searchcourse" type="text" name="searchcourse" value="'.s($searchcourse).'"/> ';
echo '<input type="submit" value="'.get_string('search').'"/>';
echo '<input type="hidden" name="id" value="'.$id.'" />';
$sql = 'select DISTINCT c.id, c.shortname from {course} c, '.
'{feedback_value} fv, {feedback_item} fi '.
'where c.id = fv.course_id and fv.item = fi.id '.
'and fi.feedback = ? '.
'and
('.$DB->sql_like('c.shortname', '?', false).'
OR '.$DB->sql_like('c.fullname', '?', false).')';
$params = array($feedback->id, "%$searchcourse%", "%$searchcourse%");
if ($courses = $DB->get_records_sql_menu($sql, $params)) {
if (!$courseid) {
$courses = array('' => get_string('choosedots')) + $courses;
}
echo ' '. html_writer::label(get_string('filter_by_course', 'feedback'). ': ', 'coursefilterid');
echo html_writer::select($courses, 'courseid', $courseid,
null, array('id'=>'coursefilterid', 'class' => 'autosubmit'));
$PAGE->requires->yui_module('moodle-core-formautosubmit',
'M.core.init_formautosubmit',
array(array('selectid' => 'coursefilterid', 'nothing' => false))
);
}
if ($courseid) {
echo ' <a href="analysis_course.php?id=' . $id . '">';
echo get_string('show_all', 'feedback');
echo '</a>';
}
echo '</form>';
echo '</div>';
// Print the items in an analysed form.
foreach ($items as $item) {
echo '<table class="analysis">';

View File

@ -1,313 +0,0 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* prints an analysed excel-spreadsheet of the feedback
*
* @author Andreas Grabs
* @license http://www.gnu.org/copyleft/gpl.html GNU Public License
* @package mod_feedback
*/
require_once("../../config.php");
require_once("lib.php");
require_once("$CFG->libdir/excellib.class.php");
feedback_load_feedback_items();
$id = required_param('id', PARAM_INT); //the POST dominated the GET
$coursefilter = optional_param('coursefilter', '0', PARAM_INT);
$url = new moodle_url('/mod/feedback/analysis_to_excel.php', array('id'=>$id));
if ($coursefilter !== '0') {
$url->param('coursefilter', $coursefilter);
}
$PAGE->set_url($url);
$formdata = data_submitted();
if (! $cm = get_coursemodule_from_id('feedback', $id)) {
print_error('invalidcoursemodule');
}
if (! $course = $DB->get_record("course", array("id"=>$cm->course))) {
print_error('coursemisconf');
}
if (! $feedback = $DB->get_record("feedback", array("id"=>$cm->instance))) {
print_error('invalidcoursemodule');
}
$context = context_module::instance($cm->id);
require_login($course, true, $cm);
$feedbackstructure = new mod_feedback_structure($feedback, $PAGE->cm, $coursefilter);
require_capability('mod/feedback:viewreports', $context);
//buffering any output
//this prevents some output before the excel-header will be send
ob_start();
$fstring = new stdClass();
$fstring->bold = get_string('bold', 'feedback');
$fstring->page = get_string('page', 'feedback');
$fstring->of = get_string('of', 'feedback');
$fstring->modulenameplural = get_string('modulenameplural', 'feedback');
$fstring->questions = get_string('questions', 'feedback');
$fstring->itemlabel = get_string('item_label', 'feedback');
$fstring->question = get_string('question', 'feedback');
$fstring->responses = get_string('responses', 'feedback');
$fstring->idnumber = get_string('idnumber');
$fstring->username = get_string('username');
$fstring->fullname = get_string('fullnameuser');
$fstring->courseid = get_string('courseid', 'feedback');
$fstring->course = get_string('course');
$fstring->anonymous_user = get_string('anonymous_user', 'feedback');
ob_end_clean();
//get the questions (item-names)
$items = $feedbackstructure->get_items(true);
if (!$items) {
print_error('no_items_available_yet',
'feedback',
$CFG->wwwroot.'/mod/feedback/view.php?id='.$id);
exit;
}
$filename = "feedback.xls";
$mygroupid = groups_get_activity_group($cm);
// Creating a workbook
$workbook = new MoodleExcelWorkbook('-');
$workbook->send($filename);
//creating the needed formats
$xls_formats = new stdClass();
$xls_formats->head1 = $workbook->add_format(array(
'bold'=>1,
'size'=>12));
$xls_formats->head2 = $workbook->add_format(array(
'align'=>'left',
'bold'=>1,
'bottum'=>2));
$xls_formats->default = $workbook->add_format(array(
'align'=>'left',
'v_align'=>'top'));
$xls_formats->value_bold = $workbook->add_format(array(
'align'=>'left',
'bold'=>1,
'v_align'=>'top'));
$xls_formats->procent = $workbook->add_format(array(
'align'=>'left',
'bold'=>1,
'v_align'=>'top',
'num_format'=>'#,##0.00%'));
// Creating the worksheets
$sheetname = clean_param($feedback->name, PARAM_ALPHANUM);
error_reporting(0);
$worksheet1 = $workbook->add_worksheet(substr($sheetname, 0, 31));
$worksheet2 = $workbook->add_worksheet('detailed');
error_reporting($CFG->debug);
$worksheet1->hide_gridlines();
$worksheet1->set_column(0, 0, 10);
$worksheet1->set_column(1, 1, 30);
$worksheet1->set_column(2, 20, 15);
//writing the table header
$row_offset1 = 0;
$worksheet1->write_string($row_offset1, 0, userdate(time()), $xls_formats->head1);
////////////////////////////////////////////////////////////////////////
//print the analysed sheet
////////////////////////////////////////////////////////////////////////
//get the completeds
$completedscount = $feedbackstructure->count_completed_responses($mygroupid);
if ($completedscount > 0) {
//write the count of completeds
$row_offset1++;
$worksheet1->write_string($row_offset1,
0,
$fstring->modulenameplural.': '.strval($completedscount),
$xls_formats->head1);
}
if (is_array($items)) {
$row_offset1++;
$worksheet1->write_string($row_offset1,
0,
$fstring->questions.': '. strval(count($items)),
$xls_formats->head1);
}
$row_offset1 += 2;
$worksheet1->write_string($row_offset1, 0, $fstring->itemlabel, $xls_formats->head1);
$worksheet1->write_string($row_offset1, 1, $fstring->question, $xls_formats->head1);
$worksheet1->write_string($row_offset1, 2, $fstring->responses, $xls_formats->head1);
$row_offset1++;
if (empty($items)) {
$items=array();
}
foreach ($items as $item) {
//get the class of item-typ
$itemobj = feedback_get_item_class($item->typ);
$row_offset1 = $itemobj->excelprint_item($worksheet1,
$row_offset1,
$xls_formats,
$item,
$mygroupid,
$coursefilter);
}
////////////////////////////////////////////////////////////////////////
//print the detailed sheet
////////////////////////////////////////////////////////////////////////
//get the completeds
$completeds = feedback_get_completeds_group($feedback, $mygroupid, $coursefilter);
//important: for each completed you have to print each item, even if it is not filled out!!!
//therefor for each completed we have to iterate over all items of the feedback
//this is done by feedback_excelprint_detailed_items
$row_offset2 = 0;
//first we print the table-header
$row_offset2 = feedback_excelprint_detailed_head($worksheet2, $xls_formats, $items, $row_offset2);
if (is_array($completeds)) {
foreach ($completeds as $completed) {
$row_offset2 = feedback_excelprint_detailed_items($worksheet2,
$xls_formats,
$completed,
$items,
$row_offset2);
}
}
$workbook->close();
exit;
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
//functions
////////////////////////////////////////////////////////////////////////////////
function feedback_excelprint_detailed_head(&$worksheet, $xls_formats, $items, $row_offset) {
global $fstring, $feedback;
if (!$items) {
return;
}
$col_offset = 0;
$worksheet->write_string($row_offset + 1, $col_offset, $fstring->idnumber, $xls_formats->head2);
$col_offset++;
$worksheet->write_string($row_offset + 1, $col_offset, $fstring->username, $xls_formats->head2);
$col_offset++;
$worksheet->write_string($row_offset + 1, $col_offset, $fstring->fullname, $xls_formats->head2);
$col_offset++;
foreach ($items as $item) {
$worksheet->write_string($row_offset, $col_offset, $item->name, $xls_formats->head2);
$worksheet->write_string($row_offset + 1, $col_offset, $item->label, $xls_formats->head2);
$col_offset++;
}
$worksheet->write_string($row_offset + 1, $col_offset, $fstring->courseid, $xls_formats->head2);
$col_offset++;
$worksheet->write_string($row_offset + 1, $col_offset, $fstring->course, $xls_formats->head2);
$col_offset++;
return $row_offset + 2;
}
function feedback_excelprint_detailed_items(&$worksheet, $xls_formats,
$completed, $items, $row_offset) {
global $DB, $fstring;
if (!$items) {
return;
}
$col_offset = 0;
$courseid = 0;
$feedback = $DB->get_record('feedback', array('id'=>$completed->feedback));
//get the username
//anonymous users are separated automatically because the userid in the completed is "0"
if ($user = $DB->get_record('user', array('id'=>$completed->userid))) {
if ($completed->anonymous_response == FEEDBACK_ANONYMOUS_NO) {
$worksheet->write_string($row_offset, $col_offset, $user->idnumber, $xls_formats->head2);
$col_offset++;
$userfullname = fullname($user);
$worksheet->write_string($row_offset, $col_offset, $user->username, $xls_formats->head2);
$col_offset++;
} else {
$userfullname = $fstring->anonymous_user;
$worksheet->write_string($row_offset, $col_offset, '-', $xls_formats->head2);
$col_offset++;
$worksheet->write_string($row_offset, $col_offset, '-', $xls_formats->head2);
$col_offset++;
}
} else {
$userfullname = $fstring->anonymous_user;
$worksheet->write_string($row_offset, $col_offset, '-', $xls_formats->head2);
$col_offset++;
$worksheet->write_string($row_offset, $col_offset, '-', $xls_formats->head2);
$col_offset++;
}
$worksheet->write_string($row_offset, $col_offset, $userfullname, $xls_formats->head2);
$col_offset++;
foreach ($items as $item) {
$params = array('item' => $item->id, 'completed' => $completed->id);
$value = $DB->get_record('feedback_value', $params);
$itemobj = feedback_get_item_class($item->typ);
$printval = $itemobj->get_printval($item, $value);
$printval = trim($printval);
if (is_numeric($printval)) {
$worksheet->write_number($row_offset, $col_offset, $printval, $xls_formats->default);
} else if ($printval != '') {
$worksheet->write_string($row_offset, $col_offset, $printval, $xls_formats->default);
}
$printval = '';
$col_offset++;
$courseid = isset($value->course_id) ? $value->course_id : 0;
if ($courseid == 0) {
$courseid = $feedback->course;
}
}
$worksheet->write_number($row_offset, $col_offset, $courseid, $xls_formats->default);
$col_offset++;
if (isset($courseid) AND $course = $DB->get_record('course', array('id' => $courseid))) {
$coursecontext = context_course::instance($courseid);
$shortname = format_string($course->shortname, true, array('context' => $coursecontext));
$worksheet->write_string($row_offset, $col_offset, $shortname, $xls_formats->default);
}
return $row_offset + 1;
}

View File

@ -0,0 +1,83 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Contains class mod_feedback_course_map_form
*
* @package mod_feedback
* @copyright 2016 Marina Glancy
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
defined('MOODLE_INTERNAL') || die();
/**
* Form for mapping courses to the feedback
*
* @package mod_feedback
* @copyright 2016 Marina Glancy
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class mod_feedback_course_select_form extends moodleform {
/** @var moodle_url */
protected $action;
/** @var mod_feedback_structure $feedbackstructure */
protected $feedbackstructure;
/**
* Constructor
*
* @param string|moodle_url $action the action attribute for the form
* @param mod_feedback_structure $feedbackstructure
* @param bool $editable
*/
public function __construct($action, mod_feedback_structure $feedbackstructure, $editable = true) {
$this->action = new moodle_url($action, ['courseid' => null]);
$this->feedbackstructure = $feedbackstructure;
parent::__construct($action, null, 'post', '', ['id' => 'feedback_course_filter'], $editable);
}
/**
* Definition of the form
*/
public function definition() {
$mform = $this->_form;
$feedbackstructure = $this->feedbackstructure;
$mform->addElement('hidden', 'id');
$mform->setType('id', PARAM_INT);
if (!$this->_form->_freezeAll && ($courses = $feedbackstructure->get_completed_courses()) && count($courses) > 1) {
$elements = [];
$elements[] = $mform->createElement('autocomplete', 'courseid', get_string('filter_by_course', 'feedback'),
['' => get_string('fulllistofcourses')] + $courses);
$elements[] = $mform->createElement('submit', 'submitbutton', get_string('filter'));
if ($feedbackstructure->get_courseid()) {
$elements[] = $mform->createElement('static', 'showall', '',
html_writer::link($this->action, get_string('show_all', 'feedback')));
}
if (defined('BEHAT_SITE_RUNNING')) {
// TODO MDL-53734 remove this - behat does not recognise autocomplete element inside a group.
foreach ($elements as $element) {
$mform->addElement($element);
}
} else {
$mform->addGroup($elements, 'coursefilter', get_string('filter_by_course', 'feedback'), array(' '), false);
}
}
$this->set_data(['courseid' => $feedbackstructure->get_courseid(), 'id' => $feedbackstructure->get_cm()->id]);
}
}

View File

@ -36,48 +36,56 @@ class mod_feedback_responses_anon_table extends mod_feedback_responses_table {
/** @var string */
protected $showallparamname = 'ashowall';
/** @var string */
protected $downloadparamname = 'adownload';
/**
* Initialises table
*/
public function init() {
$this->uniqueid = 'feedback-showentry-anon-list-' . $this->cm->instance;
$cm = $this->feedbackstructure->get_cm();
$this->uniqueid = 'feedback-showentry-anon-list-' . $cm->instance;
// There potentially can be both tables with anonymouns and non-anonymous responses on
// the same page (for example when feedback anonymity was changed after some people
// already responded). In this case we need to distinguish tables' pagination parameters.
$this->request[TABLE_VAR_PAGE] = 'apage';
$tablecolumns = array('random_response', 'showresponse');
$tableheaders = array('', '');
$tablecolumns = ['random_response'];
$tableheaders = [get_string('response_nr', 'feedback')];
$context = context_module::instance($this->cm->id);
if (has_capability('mod/feedback:deletesubmissions', $context)) {
$tablecolumns[] = 'deleteentry';
$tableheaders[] = '';
if ($this->feedbackstructure->get_feedback()->course == SITEID && !$this->feedbackstructure->get_courseid()) {
$tablecolumns[] = 'courseid';
$tableheaders[] = get_string('course');
}
$this->define_columns($tablecolumns);
$this->define_headers($tableheaders);
$this->sortable(false, 'random_response');
$this->collapsible(false);
$this->set_attribute('id', 'showentryanonymtable');
$this->sortable(true, 'random_response');
$this->collapsible(true);
$this->set_attribute('id', 'showentryanontable');
$params = ['instance' => $this->cm->instance, 'anon' => FEEDBACK_ANONYMOUS_YES];
$params = ['instance' => $cm->instance,
'anon' => FEEDBACK_ANONYMOUS_YES,
'courseid' => $this->feedbackstructure->get_courseid()];
$fields = 'DISTINCT c.id, c.random_response';
$fields = 'c.id, c.random_response, c.courseid';
$from = '{feedback_completed} c';
$where = 'c.anonymous_response = :anon AND c.feedback = :instance';
if ($this->feedbackstructure->get_courseid()) {
$where .= ' AND c.courseid = :courseid';
}
$group = groups_get_activity_group($this->cm, true);
$group = groups_get_activity_group($this->feedbackstructure->get_cm(), true);
if ($group) {
$from .= ' JOIN {groups_members} g ON g.groupid = :group AND g.userid = c.userid';
$where .= ' AND c.userid IN (SELECT g.userid FROM {groups_members} g WHERE g.groupid = :group)';
$params['group'] = $group;
}
$this->set_sql($fields, $from, $where, $params);
$this->set_count_sql("SELECT COUNT(DISTINCT c.id) FROM $from WHERE $where", $params);
$this->set_count_sql("SELECT COUNT(c.id) FROM $from WHERE $where", $params);
}
/**
@ -95,22 +103,11 @@ class mod_feedback_responses_anon_table extends mod_feedback_responses_table {
* @return string
*/
public function col_random_response($row) {
return get_string('response_nr', 'feedback').': '. $row->random_response;
}
/**
* Prepares column showresponse for display
* @param stdClass $row
* @return string
*/
public function col_showresponse($row) {
return html_writer::link($this->get_link_single_entry($row), get_string('show_entry', 'feedback'));
}
/**
* Generate the HTML for the table preferences reset button.
*/
protected function render_reset_button() {
return '';
if ($this->is_downloading()) {
return $row->random_response;
} else {
return html_writer::link($this->get_link_single_entry($row),
get_string('response_nr', 'feedback').': '. $row->random_response);
}
}
}

View File

@ -36,8 +36,8 @@ require_once($CFG->libdir . '/tablelib.php');
*/
class mod_feedback_responses_table extends table_sql {
/** @var cm_info */
protected $cm;
/** @var mod_feedback_structure */
protected $feedbackstructure;
/** @var int */
protected $grandtotal = null;
@ -48,23 +48,34 @@ class mod_feedback_responses_table extends table_sql {
/** @var string */
protected $showallparamname = 'showall';
/** @var string */
protected $downloadparamname = 'download';
/**
* Constructor
*
* @param cm_info $cm
* @param mod_feedback_structure $feedbackstructure
*/
public function __construct(cm_info $cm) {
$this->cm = $cm;
public function __construct(mod_feedback_structure $feedbackstructure) {
$this->feedbackstructure = $feedbackstructure;
parent::__construct('feedback-showentry-list-' . $cm->instance);
parent::__construct('feedback-showentry-list-' . $feedbackstructure->get_cm()->instance);
$this->showall = optional_param($this->showallparamname, 0, PARAM_BOOL);
$this->define_baseurl(new moodle_url('/mod/feedback/show_entries.php',
['id' => $this->cm->id]));
['id' => $this->feedbackstructure->get_cm()->id]));
if ($courseid = $this->feedbackstructure->get_courseid()) {
$this->baseurl->param('courseid', $courseid);
}
if ($this->showall) {
$this->baseurl->param($this->showallparamname, $this->showall);
}
$this->is_downloadable(true);
$this->is_downloading(optional_param($this->downloadparamname, 0, PARAM_ALPHA),
'feedback_test');
$this->useridfield = 'userid';
$this->init();
}
@ -73,44 +84,85 @@ class mod_feedback_responses_table extends table_sql {
*/
protected function init() {
$tablecolumns = array('userpic', 'fullname', 'completed_timemodified');
$tableheaders = array(get_string('userpic'), get_string('fullnameuser'), get_string('date'));
$tablecolumns = array('userpic', 'fullname');
$tableheaders = array(get_string('userpic'), get_string('fullnameuser'));
$context = context_module::instance($this->cm->id);
if (has_capability('mod/feedback:deletesubmissions', $context)) {
$tablecolumns[] = 'deleteentry';
$tableheaders[] = '';
$extrafields = get_extra_user_fields($this->get_context());
$ufields = user_picture::fields('u', $extrafields, $this->useridfield);
$fields = 'c.id, c.timemodified as completed_timemodified, c.courseid, '.$ufields;
$from = '{feedback_completed} c '
. 'JOIN {user} u ON u.id = c.userid AND u.deleted = :notdeleted';
$where = 'c.anonymous_response = :anon
AND c.feedback = :instance';
if ($this->feedbackstructure->get_courseid()) {
$where .= ' AND c.courseid = :courseid';
}
if ($this->is_downloading()) {
// When downloading data:
// Remove 'userpic' from downloaded data.
array_shift($tablecolumns);
array_shift($tableheaders);
// Add all identity fields as separate columns.
foreach ($extrafields as $field) {
$fields .= ", u.{$field}";
$tablecolumns[] = $field;
$tableheaders[] = get_user_field_name($field);
}
}
if ($this->feedbackstructure->get_feedback()->course == SITEID && !$this->feedbackstructure->get_courseid()) {
$tablecolumns[] = 'courseid';
$tableheaders[] = get_string('course');
}
$tablecolumns[] = 'completed_timemodified';
$tableheaders[] = get_string('date');
$this->define_columns($tablecolumns);
$this->define_headers($tableheaders);
$this->sortable(true, 'lastname', SORT_ASC);
$this->collapsible(false);
$this->collapsible(true);
$this->set_attribute('id', 'showentrytable');
$params = array();
$params['anon'] = FEEDBACK_ANONYMOUS_NO;
$params['instance'] = $this->cm->instance;
$params['instance'] = $this->feedbackstructure->get_feedback()->id;
$params['notdeleted'] = 0;
$params['courseid'] = $this->feedbackstructure->get_courseid();
$ufields = user_picture::fields('u', null, 'userid');
$fields = 'DISTINCT c.id, c.timemodified as completed_timemodified, '.$ufields;
$from = '{user} u, {feedback_completed} c';
$where = 'anonymous_response = :anon
AND u.id = c.userid
AND c.feedback = :instance
AND u.deleted = :notdeleted';
$group = groups_get_activity_group($this->cm, true);
$group = groups_get_activity_group($this->feedbackstructure->get_cm(), true);
if ($group) {
$from .= ', {groups_members} g';
$where .= ' AND g.groupid = :group AND g.userid = c.userid';
$where .= ' AND c.userid IN (SELECT g.userid FROM {groups_members} g WHERE g.groupid = :group)';
$params['group'] = $group;
}
$this->set_sql($fields, $from, $where, $params);
$this->set_count_sql("SELECT COUNT(DISTINCT c.id) FROM $from WHERE $where", $params);
$this->set_count_sql("SELECT COUNT(c.id) FROM $from WHERE $where", $params);
}
/**
* Current context
* @return context_module
*/
protected function get_context() {
return context_module::instance($this->feedbackstructure->get_cm()->id);
}
/**
* Allows to set the display column value for all columns without "col_xxxxx" method.
* @param string $column column name
* @param stdClass $row current record result of SQL query
*/
public function other_cols($column, $row) {
if (preg_match('/^val(\d+)$/', $column, $matches)) {
$items = $this->feedbackstructure->get_items();
$itemobj = feedback_get_item_class($items[$matches[1]]->typ);
return trim($itemobj->get_printval($items[$matches[1]], (object) ['value' => $row->$column] ));
}
return $row->$column;
}
/**
@ -120,7 +172,8 @@ class mod_feedback_responses_table extends table_sql {
*/
public function col_userpic($row) {
global $OUTPUT;
return $OUTPUT->user_picture($row, array('courseid' => $this->cm->course));
$user = user_picture::unalias($row, [], $this->useridfield);
return $OUTPUT->user_picture($user, array('courseid' => $this->feedbackstructure->get_cm()->course));
}
/**
@ -129,11 +182,10 @@ class mod_feedback_responses_table extends table_sql {
* @return string
*/
public function col_deleteentry($row) {
$context = context_module::instance($this->cm->id);
if (has_capability('mod/feedback:deletesubmissions', $context)) {
$deleteentryurl = new moodle_url($this->baseurl, ['delete' => $row->id]);
return html_writer::link($deleteentryurl, get_string('delete_entry', 'feedback'));
}
global $OUTPUT;
$icon = $OUTPUT->render(new \pix_icon('t/delete', get_string('delete_entry', 'feedback')));
$deleteentryurl = new moodle_url($this->baseurl, ['delete' => $row->id]);
return html_writer::link($deleteentryurl, $icon);
}
/**
@ -142,7 +194,7 @@ class mod_feedback_responses_table extends table_sql {
* @return \moodle_url
*/
protected function get_link_single_entry($row) {
return new moodle_url($this->baseurl, ['userid' => $row->userid, 'showcompleted' => $row->id]);
return new moodle_url($this->baseurl, ['userid' => $row->{$this->useridfield}, 'showcompleted' => $row->id]);
}
/**
@ -151,8 +203,59 @@ class mod_feedback_responses_table extends table_sql {
* @return string
*/
public function col_completed_timemodified($student) {
return html_writer::link($this->get_link_single_entry($student),
userdate($student->completed_timemodified));
if ($this->is_downloading()) {
return userdate($student->completed_timemodified);
} else {
return html_writer::link($this->get_link_single_entry($student),
userdate($student->completed_timemodified));
}
}
/**
* Prepares column courseid for display
* @param array $row
* @return string
*/
public function col_courseid($row) {
$courses = $this->feedbackstructure->get_completed_courses();
$name = '';
if (isset($courses[$row->courseid])) {
$name = $courses[$row->courseid];
if (!$this->is_downloading()) {
$name = html_writer::link(course_get_url($row->courseid), $name);
}
}
return $name;
}
/**
* Adds common values to the table that do not change the number or order of entries and
* are only needed when outputting or downloading data.
*/
protected function add_all_values_to_output() {
$tablecolumns = array_keys($this->columns);
$tableheaders = $this->headers;
// Add all feedback response values.
$items = $this->feedbackstructure->get_items(true);
foreach ($items as $nr => $item) {
$this->sql->fields .= ", v{$nr}.value AS val{$nr}";
$this->sql->from .= " LEFT OUTER JOIN {feedback_value} v{$nr} " .
"ON v{$nr}.completed = c.id AND v{$nr}.item = :itemid{$nr}";
$this->sql->params["itemid{$nr}"] = $item->id;
$tablecolumns[] = "val{$nr}";
$itemobj = feedback_get_item_class($item->typ);
$tableheaders[] = $itemobj->get_display_name($item);
}
// Add 'Delete entry' column.
if (!$this->is_downloading() && has_capability('mod/feedback:deletesubmissions', $this->get_context())) {
$tablecolumns[] = 'deleteentry';
$tableheaders[] = '';
}
$this->define_columns($tablecolumns);
$this->define_headers($tableheaders);
}
/**
@ -165,21 +268,23 @@ class mod_feedback_responses_table extends table_sql {
public function query_db($pagesize, $useinitialsbar=true) {
global $DB;
$this->totalrows = $grandtotal = $this->get_total_responses_count();
$this->initialbars($useinitialsbar);
if (!$this->is_downloading()) {
$this->initialbars($useinitialsbar);
list($wsql, $wparams) = $this->get_sql_where();
if ($wsql) {
$this->countsql .= ' AND '.$wsql;
$this->countparams = array_merge($this->countparams, $wparams);
list($wsql, $wparams) = $this->get_sql_where();
if ($wsql) {
$this->countsql .= ' AND '.$wsql;
$this->countparams = array_merge($this->countparams, $wparams);
$this->sql->where .= ' AND '.$wsql;
$this->sql->params = array_merge($this->sql->params, $wparams);
$this->sql->where .= ' AND '.$wsql;
$this->sql->params = array_merge($this->sql->params, $wparams);
$this->totalrows = $DB->count_records_sql($this->countsql, $this->countparams);
}
$this->totalrows = $DB->count_records_sql($this->countsql, $this->countparams);
}
if ($this->totalrows > $pagesize) {
$this->pagesize($pagesize, $this->totalrows);
if ($this->totalrows > $pagesize) {
$this->pagesize($pagesize, $this->totalrows);
}
}
if ($sort = $this->get_sql_sort()) {
@ -191,7 +296,11 @@ class mod_feedback_responses_table extends table_sql {
WHERE {$this->sql->where}
{$sort}";
$this->rawdata = $DB->get_recordset_sql($sql, $this->sql->params, $this->get_page_start(), $this->get_page_size());
if (!$this->is_downloading()) {
$this->rawdata = $DB->get_recordset_sql($sql, $this->sql->params, $this->get_page_start(), $this->get_page_size());
} else {
$this->rawdata = $DB->get_recordset_sql($sql, $this->sql->params);
}
}
/**
@ -211,7 +320,7 @@ class mod_feedback_responses_table extends table_sql {
* @param array $columns an array of identifying names for columns. If
* columns are sorted then column names must correspond to a field in sql.
*/
function define_columns($columns) {
public function define_columns($columns) {
parent::define_columns($columns);
foreach ($this->columns as $column => $column) {
// Automatically assign classes to columns.
@ -219,12 +328,24 @@ class mod_feedback_responses_table extends table_sql {
}
}
/**
* Convenience method to call a number of methods for you to display the
* table.
* @param int $pagesize
* @param bool $useinitialsbar
* @param string $downloadhelpbutton
*/
public function out($pagesize, $useinitialsbar, $downloadhelpbutton='') {
$this->add_all_values_to_output();
parent::out($pagesize, $useinitialsbar, $downloadhelpbutton);
}
/**
* Displays the table
*/
public function display() {
global $OUTPUT;
groups_print_activity_menu($this->cm, $this->baseurl);
groups_print_activity_menu($this->feedbackstructure->get_cm(), $this->baseurl->out());
$grandtotal = $this->get_total_responses_count();
if (!$grandtotal) {
echo $OUTPUT->box(get_string('nothingtodisplay'), 'generalbox nothingtodisplay');
@ -280,4 +401,38 @@ class mod_feedback_responses_table extends table_sql {
$nextrow ? $this->get_link_single_entry($nextrow) : null,
];
}
/**
* Download the data.
*/
public function download() {
\core\session\manager::write_close();
$this->out($this->get_total_responses_count(), false);
exit;
}
/**
* Returns html code for displaying "Download" button if applicable.
*/
public function download_buttons() {
if ($this->is_downloadable() && !$this->is_downloading()) {
$elementid = $this->uniqueid . '_download';
$html = '<div class="mdl-align">';
$html .= '<form action="'. $this->baseurl .'" method="post" class="form-inline">';
if ($courseid = $this->feedbackstructure->get_courseid()) {
$html .= '<input type="hidden" name="courseid" value="' . s($courseid) . '">';
}
$html .= html_writer::tag('label', get_string('downloadresponseas', 'feedback'),
['for' => $elementid]);
$html .= html_writer::select($this->get_download_menu(),
$this->downloadparamname, $this->defaultdownloadformat, false, ['id' => $elementid]);
$html .= html_writer::empty_tag('input', ['type' => 'submit', 'value' => get_string('download')]);
$html .= '</form></div>';
return $html;
} else {
return '';
}
}
}

View File

@ -129,6 +129,7 @@ $string['checkbox'] = 'Multiple choice - multiple answers allowed (check boxes)'
$string['check_values'] = 'Possible responses';
$string['choosefile'] = 'Choose a file';
$string['chosen_feedback_response'] = 'chosen feedback response';
$string['downloadresponseas'] = 'Download all responses as:';
$string['importfromthisfile'] = 'Import from this file';
$string['import_questions'] = 'Import questions';
$string['import_successfully'] = 'Import successfully';

View File

@ -32,6 +32,7 @@ $id = required_param('id', PARAM_INT);
$userid = optional_param('userid', false, PARAM_INT);
$showcompleted = optional_param('showcompleted', false, PARAM_INT);
$deleteid = optional_param('delete', null, PARAM_INT);
$courseid = optional_param('courseid', null, PARAM_INT);
////////////////////////////////////////////////////////
//get the objects
@ -64,9 +65,24 @@ if ($deleteid) {
$feedbackstructure = new mod_feedback_completion($feedback, $cm, 0, true, $showcompleted, $userid);
} else {
// Viewing list of reponses.
$feedbackstructure = new mod_feedback_structure($feedback, $cm);
$feedbackstructure = new mod_feedback_structure($feedback, $cm, $courseid);
}
$responsestable = new mod_feedback_responses_table($feedbackstructure);
$anonresponsestable = new mod_feedback_responses_anon_table($feedbackstructure);
if ($responsestable->is_downloading()) {
$responsestable->download();
}
if ($anonresponsestable->is_downloading()) {
$anonresponsestable->download();
}
// Process course select form.
$courseselectform = new mod_feedback_course_select_form($baseurl, $feedbackstructure, $feedback->course == SITEID);
if ($data = $courseselectform->get_data()) {
redirect(new moodle_url($baseurl, ['courseid' => $data->courseid]));
}
// Print the page header.
navigation_node::override_active_url($baseurl);
$PAGE->set_heading($course->fullname);
@ -104,12 +120,9 @@ if ($deleteid) {
$feedbackstructure, 'feedback_viewresponse_form');
$form->display();
if ($userid) {
$responsestable = new mod_feedback_responses_table($cm);
} else {
$responsestable = new mod_feedback_responses_anon_table($cm);
}
list($prevresponseurl, $returnurl, $nextresponseurl) = $responsestable->get_reponse_navigation_links($completedrecord);
list($prevresponseurl, $returnurl, $nextresponseurl) = $userid ?
$responsestable->get_reponse_navigation_links($completedrecord) :
$anonresponsestable->get_reponse_navigation_links($completedrecord);
echo html_writer::start_div('response_navigation');
echo $prevresponseurl ? html_writer::link($prevresponseurl, get_string('prev'), ['class' => 'prev_response']) : '';
@ -118,9 +131,9 @@ if ($deleteid) {
echo html_writer::end_div();
} else {
// Print the list of responses.
$courseselectform->display();
// Show non-anonymous responses (always retrieve them even if current feedback is anonymous).
$responsestable = new mod_feedback_responses_table($cm);
$totalrows = $responsestable->get_total_responses_count();
if (!$feedbackstructure->is_anonymous() || $totalrows) {
echo $OUTPUT->heading(get_string('non_anonymous_entries', 'feedback', $totalrows), 4);
@ -129,7 +142,6 @@ if ($deleteid) {
// Show anonymous responses (always retrieve them even if current feedback is not anonymous).
$feedbackstructure->shuffle_anonym_responses();
$anonresponsestable = new mod_feedback_responses_anon_table($cm);
$totalrows = $anonresponsestable->get_total_responses_count();
if ($feedbackstructure->is_anonymous() || $totalrows) {
echo $OUTPUT->heading(get_string('anonymous_entries', 'feedback', $totalrows), 4);

View File

@ -45,44 +45,39 @@ if (!isset($current_tab)) {
$viewurl = new moodle_url('/mod/feedback/view.php', array('id' => $usedid));
$row[] = new tabobject('view', $viewurl->out(), get_string('overview', 'feedback'));
$urlparams = ['id' => $usedid];
if ($feedback->course == SITEID && $courseid) {
$urlparams['courseid'] = $courseid;
}
if (has_capability('mod/feedback:edititems', $context)) {
$editurl = new moodle_url('/mod/feedback/edit.php', array('id'=>$usedid, 'do_show'=>'edit'));
$editurl = new moodle_url('/mod/feedback/edit.php', $urlparams + ['do_show' => 'edit']);
$row[] = new tabobject('edit', $editurl->out(), get_string('edit_items', 'feedback'));
$templateurl = new moodle_url('/mod/feedback/edit.php', array('id'=>$usedid, 'do_show'=>'templates'));
$templateurl = new moodle_url('/mod/feedback/edit.php', $urlparams + ['do_show' => 'templates']);
$row[] = new tabobject('templates', $templateurl->out(), get_string('templates', 'feedback'));
}
if ($feedback->course == SITEID && has_capability('mod/feedback:mapcourse', $context)) {
$mapurl = new moodle_url('/mod/feedback/mapcourse.php', array('id' => $usedid));
$mapurl = new moodle_url('/mod/feedback/mapcourse.php', $urlparams);
$row[] = new tabobject('mapcourse', $mapurl->out(), get_string('mappedcourses', 'feedback'));
}
if (has_capability('mod/feedback:viewreports', $context)) {
if ($feedback->course == SITEID) {
$url_params = array('id' => $usedid, 'courseid' => $courseid);
$analysisurl = new moodle_url('/mod/feedback/analysis_course.php', $url_params);
$row[] = new tabobject('analysis',
$analysisurl->out(),
get_string('analysis', 'feedback'));
$analysisurl = new moodle_url('/mod/feedback/analysis_course.php', $urlparams);
} else {
$url_params = array('id' => $usedid);
$analysisurl = new moodle_url('/mod/feedback/analysis.php', $url_params);
$row[] = new tabobject('analysis',
$analysisurl->out(),
get_string('analysis', 'feedback'));
$analysisurl = new moodle_url('/mod/feedback/analysis.php', $urlparams);
}
$row[] = new tabobject('analysis', $analysisurl->out(), get_string('analysis', 'feedback'));
$url_params = array('id' => $usedid);
$reporturl = new moodle_url('/mod/feedback/show_entries.php', $url_params);
$reporturl = new moodle_url('/mod/feedback/show_entries.php', $urlparams);
$row[] = new tabobject('showentries',
$reporturl->out(),
get_string('show_entries', 'feedback'));
if ($feedback->anonymous == FEEDBACK_ANONYMOUS_NO AND $feedback->course != SITEID) {
$nonrespondenturl = new moodle_url('/mod/feedback/show_nonrespondents.php', array('id'=>$usedid));
$nonrespondenturl = new moodle_url('/mod/feedback/show_nonrespondents.php', $urlparams);
$row[] = new tabobject('nonrespondents',
$nonrespondenturl->out(),
get_string('show_nonrespondents', 'feedback'));

View File

@ -102,7 +102,7 @@ Feature: Anonymous feedback
And I follow "Show responses"
And I should not see "Username"
And I should see "Anonymous entries (2)"
And I click on "Show response" "link" in the "Response number: 1" "table_row"
And I follow "Response number: 1"
And I should not see "Username"
And I should see "Response number: 1 (Anonymous)"
And I log out
@ -164,7 +164,7 @@ Feature: Anonymous feedback
And I follow "Site feedback"
And I follow "Show responses"
And I should see "Anonymous entries (2)"
And I click on "Show response" "link" in the "Response number: 1" "table_row"
And I follow "Response number: 1"
And I should see "Response number: 1 (Anonymous)"
And I log out
@ -222,7 +222,7 @@ Feature: Anonymous feedback
And I follow "Show responses"
And I should not see "Username"
And I should see "Anonymous entries (2)"
And I click on "Show response" "link" in the "Response number: 1" "table_row"
And I follow "Response number: 1"
And I should not see "Username"
And I should see "Response number: 1 (Anonymous)"
And I should not see "Prev"

View File

@ -115,7 +115,7 @@ Feature: Mapping courses in a feedback
And I follow "Course feedback"
And I follow "Analysis"
And the field "Filter by course" matches value "Choose..."
And I should see "All courses" in the "#feedback_course_filter .fautocomplete .label" "css_element"
And I should see "1 (33.33 %)" in the "option a" "table_row"
And I should see "1 (33.33 %)" in the "option b" "table_row"
And I should see "1 (33.33 %)" in the "option c" "table_row"
@ -124,7 +124,9 @@ Feature: Mapping courses in a feedback
And I should see "2.50" in the "C1" "table_row"
And I should see "1.00" in the "Acceptance test site" "table_row"
And I follow "Back"
And I set the field "Filter by course" to "C1"
And I set the field "Filter by course" to "Course 1"
And I press "Filter"
And I should see "Course 1" in the "#feedback_course_filter .fautocomplete .label" "css_element"
And I should see "0" in the "option a" "table_row"
And I should see "1 (50.00 %)" in the "option b" "table_row"
And I should see "1 (50.00 %)" in the "option c" "table_row"
@ -194,7 +196,7 @@ Feature: Mapping courses in a feedback
And I am on site homepage
And I follow "Course feedback"
And I follow "Analysis"
And the field "Filter by course" matches value "Choose..."
And I should see "All courses" in the "#feedback_course_filter .fautocomplete .label" "css_element"
And I should see "0" in the "option a" "table_row"
And I should see "1 (33.33 %)" in the "option b" "table_row"
And I should see "2 (66.67 %)" in the "option c" "table_row"
@ -203,12 +205,14 @@ Feature: Mapping courses in a feedback
And I should see "3.00" in the "C3" "table_row"
And I should see "2.50" in the "C2" "table_row"
And I follow "Back"
And I set the field "Filter by course" to "C2"
And I set the field "Filter by course" to "Course 2"
And I press "Filter"
And I should see "0" in the "option a" "table_row"
And I should see "1 (50.00 %)" in the "option b" "table_row"
And I should see "1 (50.00 %)" in the "option c" "table_row"
And I should see "2 (100.00 %)" in the "option e" "table_row"
And I set the field "Filter by course" to "C3"
And I set the field "Filter by course" to "Course 3"
And I press "Filter"
And I should see "0" in the "option a" "table_row"
And I should see "0" in the "option b" "table_row"
And I should see "1 (100.00 %)" in the "option c" "table_row"