Merge branch 'wip-MDL-55333-master' of git://github.com/marinaglancy/moodle
This commit is contained in:
@@ -36,6 +36,23 @@ require_once($CFG->libdir . '/tablelib.php');
|
||||
*/
|
||||
class mod_feedback_responses_table extends table_sql {
|
||||
|
||||
/**
|
||||
* Maximum number of feedback questions to display in the "Show responses" table
|
||||
*/
|
||||
const PREVIEWCOLUNMNSLIMIT = 10;
|
||||
|
||||
/**
|
||||
* Maximum number of feedback questions answers to retrieve in one SQL query.
|
||||
* Mysql has a limit of 60, we leave 1 for joining with users table.
|
||||
*/
|
||||
const TABLEJOINLIMIT = 59;
|
||||
|
||||
/**
|
||||
* When additional queries are needed to retrieve more than TABLEJOINLIMIT questions answers, do it in chunks every x rows.
|
||||
* Value too small will mean too many DB queries, value too big may cause memory overflow.
|
||||
*/
|
||||
const ROWCHUNKSIZE = 100;
|
||||
|
||||
/** @var mod_feedback_structure */
|
||||
protected $feedbackstructure;
|
||||
|
||||
@@ -51,6 +68,10 @@ class mod_feedback_responses_table extends table_sql {
|
||||
/** @var string */
|
||||
protected $downloadparamname = 'download';
|
||||
|
||||
/** @var int number of columns that were not retrieved in the main SQL query
|
||||
* (no more than TABLEJOINLIMIT tables with values can be joined). */
|
||||
protected $hasmorecolumns = 0;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
@@ -237,13 +258,27 @@ class mod_feedback_responses_table extends table_sql {
|
||||
$tablecolumns = array_keys($this->columns);
|
||||
$tableheaders = $this->headers;
|
||||
|
||||
// Add all feedback response values.
|
||||
$items = $this->feedbackstructure->get_items(true);
|
||||
if (!$this->is_downloading()) {
|
||||
// In preview mode do not show all columns or the page becomes unreadable.
|
||||
// The information message will be displayed to the teacher that the rest of the data can be viewed when downloading.
|
||||
$items = array_slice($items, 0, self::PREVIEWCOLUNMNSLIMIT, true);
|
||||
}
|
||||
|
||||
$columnscount = 0;
|
||||
$this->hasmorecolumns = max(0, count($items) - self::TABLEJOINLIMIT);
|
||||
|
||||
// Add feedback response values.
|
||||
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;
|
||||
if ($columnscount++ < self::TABLEJOINLIMIT) {
|
||||
// Mysql has a limit on the number of tables in the join, so we only add limited number of columns here,
|
||||
// the rest will be added in {@link self::build_table()} and {@link self::build_table_chunk()} functions.
|
||||
$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);
|
||||
@@ -352,6 +387,11 @@ class mod_feedback_responses_table extends table_sql {
|
||||
echo $OUTPUT->box(get_string('nothingtodisplay'), 'generalbox nothingtodisplay');
|
||||
return;
|
||||
}
|
||||
|
||||
if (count($this->feedbackstructure->get_items(true)) > self::PREVIEWCOLUNMNSLIMIT) {
|
||||
echo $OUTPUT->notification(get_string('questionslimited', 'feedback', self::PREVIEWCOLUNMNSLIMIT), 'info');
|
||||
}
|
||||
|
||||
$this->out($this->showall ? $grandtotal : FEEDBACK_DEFAULT_PAGE_COUNT,
|
||||
$grandtotal > FEEDBACK_DEFAULT_PAGE_COUNT);
|
||||
|
||||
@@ -412,6 +452,89 @@ class mod_feedback_responses_table extends table_sql {
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Take the data returned from the db_query and go through all the rows
|
||||
* processing each col using either col_{columnname} method or other_cols
|
||||
* method or if other_cols returns NULL then put the data straight into the
|
||||
* table.
|
||||
*
|
||||
* This overwrites the parent method because full SQL query may fail on Mysql
|
||||
* because of the limit in the number of tables in the join. Therefore we only
|
||||
* join 59 tables in the main query and add the rest here.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function build_table() {
|
||||
if ($this->rawdata instanceof \Traversable && !$this->rawdata->valid()) {
|
||||
return;
|
||||
}
|
||||
if (!$this->rawdata) {
|
||||
return;
|
||||
}
|
||||
|
||||
$columnsgroups = [];
|
||||
if ($this->hasmorecolumns) {
|
||||
$items = $this->feedbackstructure->get_items(true);
|
||||
$notretrieveditems = array_slice($items, self::TABLEJOINLIMIT, $this->hasmorecolumns, true);
|
||||
$columnsgroups = array_chunk($notretrieveditems, self::TABLEJOINLIMIT, true);
|
||||
}
|
||||
|
||||
$chunk = [];
|
||||
foreach ($this->rawdata as $row) {
|
||||
if ($this->hasmorecolumns) {
|
||||
$chunk[$row->id] = $row;
|
||||
if (count($chunk) >= self::ROWCHUNKSIZE) {
|
||||
$this->build_table_chunk($chunk, $columnsgroups);
|
||||
$chunk = [];
|
||||
}
|
||||
} else {
|
||||
$this->add_data_keyed($this->format_row($row), $this->get_row_class($row));
|
||||
}
|
||||
}
|
||||
$this->build_table_chunk($chunk, $columnsgroups);
|
||||
|
||||
$this->rawdata->close();
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve additional columns. Database engine may have a limit on number of joins.
|
||||
*
|
||||
* @param array $rows Array of rows with already retrieved data, new values will be added to this array
|
||||
* @param array $columnsgroups array of arrays of columns. Each element has up to self::TABLEJOINLIMIT items. This
|
||||
* is easy to calculate but because we can call this method many times we calculate it once and pass by
|
||||
* reference for performance reasons
|
||||
*/
|
||||
protected function build_table_chunk(&$rows, &$columnsgroups) {
|
||||
global $DB;
|
||||
if (!$rows) {
|
||||
return;
|
||||
}
|
||||
|
||||
foreach ($columnsgroups as $columnsgroup) {
|
||||
$fields = 'c.id';
|
||||
$from = '{feedback_completed} c';
|
||||
$params = [];
|
||||
foreach ($columnsgroup as $nr => $item) {
|
||||
$fields .= ", v{$nr}.value AS val{$nr}";
|
||||
$from .= " LEFT OUTER JOIN {feedback_value} v{$nr} " .
|
||||
"ON v{$nr}.completed = c.id AND v{$nr}.item = :itemid{$nr}";
|
||||
$params["itemid{$nr}"] = $item->id;
|
||||
}
|
||||
list($idsql, $idparams) = $DB->get_in_or_equal(array_keys($rows), SQL_PARAMS_NAMED);
|
||||
$sql = "SELECT $fields FROM $from WHERE c.id ".$idsql;
|
||||
$results = $DB->get_records_sql($sql, $params + $idparams);
|
||||
foreach ($results as $result) {
|
||||
foreach ($result as $key => $value) {
|
||||
$rows[$result->id]->{$key} = $value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($rows as $row) {
|
||||
$this->add_data_keyed($this->format_row($row), $this->get_row_class($row));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns html code for displaying "Download" button if applicable.
|
||||
*/
|
||||
|
||||
@@ -212,6 +212,7 @@ $string['public'] = 'Public';
|
||||
$string['question'] = 'Question';
|
||||
$string['questionandsubmission'] = 'Question and submission settings';
|
||||
$string['questions'] = 'Questions';
|
||||
$string['questionslimited'] = 'Showing only {$a} first questions, view individual answers or download table data to view all.';
|
||||
$string['radio'] = 'Multiple choice - single answer';
|
||||
$string['radio_values'] = 'Responses';
|
||||
$string['ready_feedbacks'] = 'Ready feedbacks';
|
||||
|
||||
Reference in New Issue
Block a user