Rev 1 | AutorÃa | Comparar con el anterior | Ultima modificación | Ver Log |
<?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/>.use mod_quiz\local\reports\attempts_report_table;use mod_quiz\quiz_attempt;/*** This is a table subclass for displaying the quiz grades report.** @copyright 2008 Jamie Pratt* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later*/class quiz_overview_table extends attempts_report_table {/** @var array used to store information about which questoins have been regraded. */protected $regradedqs = [];/*** Constructor* @param stdClass $quiz* @param context $context* @param string $qmsubselect* @param quiz_overview_options $options* @param \core\dml\sql_join $groupstudentsjoins* @param \core\dml\sql_join $studentsjoins* @param array $questions* @param moodle_url $reporturl*/public function __construct($quiz, $context, $qmsubselect,quiz_overview_options $options, \core\dml\sql_join $groupstudentsjoins,\core\dml\sql_join $studentsjoins, $questions, $reporturl) {parent::__construct('mod-quiz-report-overview-report', $quiz , $context,$qmsubselect, $options, $groupstudentsjoins, $studentsjoins, $questions, $reporturl);}public function build_table() {global $DB;if (!$this->rawdata) {return;}$this->strtimeformat = str_replace(',', ' ', get_string('strftimedatetime'));parent::build_table();// End of adding the data from attempts. Now add averages at bottom.$this->add_separator();if (!empty($this->groupstudentsjoins->joins)) {$hasgroupstudents = $DB->record_exists_sql("SELECT 1FROM {user} u{$this->groupstudentsjoins->joins}WHERE {$this->groupstudentsjoins->wheres}", $this->groupstudentsjoins->params);if ($hasgroupstudents) {$this->add_average_row(get_string('groupavg', 'grades'), $this->groupstudentsjoins);}}if (!empty($this->studentsjoins->joins)) {$hasstudents = $DB->record_exists_sql("SELECT 1FROM {user} u{$this->studentsjoins->joins}WHERE {$this->studentsjoins->wheres}" , $this->studentsjoins->params);if ($hasstudents) {$this->add_average_row(get_string('overallaverage', 'grades'), $this->studentsjoins);}}}/*** Calculate the average overall and question scores for a set of attempts at the quiz.** @param string $label the title ot use for this row.* @param \core\dml\sql_join $usersjoins to indicate a set of users.* @return array of table cells that make up the average row.*/public function compute_average_row($label, \core\dml\sql_join $usersjoins) {global $DB;list($fields, $from, $where, $params) = $this->base_sql($usersjoins);$record = $DB->get_record_sql("SELECT AVG(quizaouter.sumgrades) AS grade, COUNT(quizaouter.sumgrades) AS numaveragedFROM {quiz_attempts} quizaouterJOIN (SELECT DISTINCT quiza.idFROM $fromWHERE $where) relevant_attempt_ids ON quizaouter.id = relevant_attempt_ids.id", $params);$record->grade = quiz_rescale_grade($record->grade, $this->quiz, false);if ($this->is_downloading()) {$namekey = 'lastname';} else {$namekey = 'fullname';}$averagerow = [$namekey => $label,'sumgrades' => $this->format_average($record),'feedbacktext' => strip_tags(quiz_report_feedback_for_grade($record->grade, $this->quiz->id, $this->context))];if ($this->options->slotmarks) {$dm = new question_engine_data_mapper();$qubaids = new qubaid_join("{quiz_attempts} quizaouterJOIN (SELECT DISTINCT quiza.idFROM $fromWHERE $where) relevant_attempt_ids ON quizaouter.id = relevant_attempt_ids.id",'quizaouter.uniqueid', '1 = 1', $params);$avggradebyq = $dm->load_average_marks($qubaids, array_keys($this->questions));$averagerow += $this->format_average_grade_for_questions($avggradebyq);}return $averagerow;}/*** Add an average grade row for a set of users.** @param string $label the title ot use for this row.* @param \core\dml\sql_join $usersjoins (joins, wheres, params) for the users to average over.*/protected function add_average_row($label, \core\dml\sql_join $usersjoins) {$averagerow = $this->compute_average_row($label, $usersjoins);$this->add_data_keyed($averagerow);}/*** Helper userd by {@link add_average_row()}.* @param array $gradeaverages the raw grades.* @return array the (partial) row of data.*/protected function format_average_grade_for_questions($gradeaverages) {$row = [];if (!$gradeaverages) {$gradeaverages = [];}foreach ($this->questions as $question) {if (isset($gradeaverages[$question->slot]) && $question->maxmark > 0) {$record = $gradeaverages[$question->slot];$record->grade = quiz_rescale_grade($record->averagefraction * $question->maxmark, $this->quiz, false);} else {$record = new stdClass();$record->grade = null;$record->numaveraged = 0;}$row['qsgrade' . $question->slot] = $this->format_average($record, true);}return $row;}/*** Format an entry in an average row.* @param stdClass $record with fields grade and numaveraged.* @param bool $question true if this is a question score, false if it is an overall score.* @return string HTML fragment for an average score (with number of things included in the average).*/protected function format_average($record, $question = false) {if (is_null($record->grade)) {$average = '-';} else if ($question) {$average = quiz_format_question_grade($this->quiz, $record->grade);} else {$average = quiz_format_grade($this->quiz, $record->grade);}if ($this->download) {return $average;} else if (is_null($record->numaveraged) || $record->numaveraged == 0) {return html_writer::tag('span', html_writer::tag('span',$average, ['class' => 'average']), ['class' => 'avgcell']);} else {return html_writer::tag('span', html_writer::tag('span',$average, ['class' => 'average']) . ' ' . html_writer::tag('span','(' . $record->numaveraged . ')', ['class' => 'count']),['class' => 'avgcell']);}}protected function submit_buttons() {global $PAGE, $OUTPUT;parent::submit_buttons();if (has_capability('mod/quiz:regrade', $this->context)) {$questionslots = [];foreach ($this->questions as $slot => $question) {$questionslots[] = ['slot' => $slot,'name' => get_string('questionno', 'question', $question->number),];}echo html_writer::empty_tag('input', ['type' => 'button','id' => 'regradeattempts','class' => 'btn btn-secondary me-1','name' => 'regradeattempts','value' => get_string('regrade_attempts', 'quiz_overview'),'data-slots' => json_encode($questionslots),// There is currently not a good way to render a help icon in a template, so put the required HTML here.'data-help-icon' => $OUTPUT->help_icon('regrade', 'quiz_overview'),]);$PAGE->requires->js_call_amd('quiz_overview/regrade_modal', 'init');}}public function col_sumgrades($attempt) {if ($attempt->state != quiz_attempt::FINISHED) {return '-';}$grade = quiz_rescale_grade($attempt->sumgrades, $this->quiz);if ($this->is_downloading()) {return $grade;}if (isset($this->regradedqs[$attempt->usageid])) {$newsumgrade = 0;$oldsumgrade = 0;foreach ($this->questions as $question) {if (isset($this->regradedqs[$attempt->usageid][$question->slot])) {$newsumgrade += $this->regradedqs[$attempt->usageid][$question->slot]->newfraction * $question->maxmark;$oldsumgrade += $this->regradedqs[$attempt->usageid][$question->slot]->oldfraction * $question->maxmark;} else {$newsumgrade += $this->lateststeps[$attempt->usageid][$question->slot]->fraction * $question->maxmark;$oldsumgrade += $this->lateststeps[$attempt->usageid][$question->slot]->fraction * $question->maxmark;}}$newsumgrade = quiz_rescale_grade($newsumgrade, $this->quiz);$oldsumgrade = quiz_rescale_grade($oldsumgrade, $this->quiz);$grade = html_writer::tag('del', $oldsumgrade) . '/' .html_writer::empty_tag('br') . $newsumgrade;}return html_writer::link(new moodle_url('/mod/quiz/review.php',['attempt' => $attempt->attempt]), $grade,['title' => get_string('reviewattempt', 'quiz')]);}/*** @param string $colname the name of the column.* @param stdClass $attempt the row of data - see the SQL in display() in* mod/quiz/report/overview/report.php to see what fields are present,* and what they are called.* @return string the contents of the cell.*/public function other_cols($colname, $attempt) {if (!preg_match('/^qsgrade(\d+)$/', $colname, $matches)) {return parent::other_cols($colname, $attempt);}$slot = $matches[1];$question = $this->questions[$slot];if (!isset($this->lateststeps[$attempt->usageid][$slot])) {return '-';}$stepdata = $this->lateststeps[$attempt->usageid][$slot];$state = question_state::get($stepdata->state);if ($question->maxmark == 0) {$grade = '-';} else if (is_null($stepdata->fraction)) {if ($state == question_state::$needsgrading) {$grade = get_string('requiresgrading', 'question');} else {$grade = '-';}} else {$grade = quiz_rescale_grade($stepdata->fraction * $question->maxmark, $this->quiz, 'question');}if ($this->is_downloading()) {return $grade;}if (isset($this->regradedqs[$attempt->usageid][$slot])) {$gradefromdb = $grade;$newgrade = quiz_rescale_grade($this->regradedqs[$attempt->usageid][$slot]->newfraction * $question->maxmark,$this->quiz, 'question');$oldgrade = quiz_rescale_grade($this->regradedqs[$attempt->usageid][$slot]->oldfraction * $question->maxmark,$this->quiz, 'question');$grade = html_writer::tag('del', $oldgrade) . '/' .html_writer::empty_tag('br') . $newgrade;}return $this->make_review_link($grade, $attempt, $slot);}public function col_regraded($attempt) {if ($attempt->regraded == '') {return '';} else if ($attempt->regraded == 0) {return get_string('needed', 'quiz_overview');} else if ($attempt->regraded == 1) {return get_string('done', 'quiz_overview');}}protected function update_sql_after_count($fields, $from, $where, $params) {$fields .= ", COALESCE((SELECT MAX(qqr.regraded)FROM {quiz_overview_regrades} qqrWHERE qqr.questionusageid = quiza.uniqueid), -1) AS regraded";if ($this->options->onlyregraded) {$where .= " AND COALESCE((SELECT MAX(qqr.regraded)FROM {quiz_overview_regrades} qqrWHERE qqr.questionusageid = quiza.uniqueid), -1) <> -1";}return [$fields, $from, $where, $params];}protected function requires_latest_steps_loaded() {return $this->options->slotmarks;}protected function is_latest_step_column($column) {if (preg_match('/^qsgrade([0-9]+)/', $column, $matches)) {return $matches[1];}return false;}protected function get_required_latest_state_fields($slot, $alias) {return "$alias.fraction * $alias.maxmark AS qsgrade$slot";}public function query_db($pagesize, $useinitialsbar = true) {parent::query_db($pagesize, $useinitialsbar);if ($this->options->slotmarks && has_capability('mod/quiz:regrade', $this->context)) {$this->regradedqs = $this->get_regraded_questions();}}/*** Get all the questions in all the attempts being displayed that need regrading.* @return array A two dimensional array $questionusageid => $slot => $regradeinfo.*/protected function get_regraded_questions() {global $DB;$qubaids = $this->get_qubaids_condition();$regradedqs = $DB->get_records_select('quiz_overview_regrades','questionusageid ' . $qubaids->usage_id_in(), $qubaids->usage_id_in_params());return quiz_report_index_by_keys($regradedqs, ['questionusageid', 'slot']);}}