From a72c28a0a3ba38bc1e8fdcf420c88082633825c8 Mon Sep 17 00:00:00 2001 From: Emanoil Manoylov Date: Tue, 10 Feb 2026 13:40:28 +0000 Subject: [PATCH] Feedback warnings and errors on response page OU 975809 --- classes/privacy/provider.php | 2 +- drawchart.php | 1 + questionnaire.class.php | 36 +++++++---- tests/responsetypes_test.php | 118 +++++++++++++++++++++++++++++++++++ 4 files changed, 144 insertions(+), 13 deletions(-) diff --git a/classes/privacy/provider.php b/classes/privacy/provider.php index 49cfb0d8..04c0bd53 100644 --- a/classes/privacy/provider.php +++ b/classes/privacy/provider.php @@ -31,8 +31,8 @@ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ class provider implements - \core_privacy\local\request\core_userlist_provider, \core_privacy\local\metadata\provider, + \core_privacy\local\request\core_userlist_provider, \core_privacy\local\request\plugin\provider { /** * Returns meta data about this system. diff --git a/drawchart.php b/drawchart.php index da5e208d..f85af09c 100644 --- a/drawchart.php +++ b/drawchart.php @@ -288,6 +288,7 @@ function draw_chart( $maxlen = $labellen; } } + $output = []; foreach ($labels as $value) { $output[] = '"' . $value . '"'; } diff --git a/questionnaire.class.php b/questionnaire.class.php index d9cf9539..c5433527 100644 --- a/questionnaire.class.php +++ b/questionnaire.class.php @@ -133,16 +133,26 @@ public function get_delete_questions() { } } + /** + * Returns a survey record. + * + * @param int $id + * @return false|mixed|stdClass + * @throws dml_exception + */ + private function get_survey(int $id): mixed { + global $DB; + return $DB->get_record('questionnaire_survey', ['id' => $id]); + } + /** * Adding a survey record to the object. * @param int $sid * @param null $survey */ public function add_survey($sid = 0, $survey = null) { - global $DB; - if ($sid) { - $this->survey = $DB->get_record('questionnaire_survey', ['id' => $sid]); + $this->survey = $this->get_survey($sid); } else if (is_object($survey)) { $this->survey = clone($survey); } @@ -422,7 +432,7 @@ private function update_grades($userid) { * Function to view an entire responses data. * @param int $rid * @param string $referer - * @param string $resps + * @param array $resps * @param bool $compare * @param bool $isgroupmember * @param bool $allresponses @@ -432,7 +442,7 @@ private function update_grades($userid) { public function view_response( $rid, $referer = '', - $resps = '', + $resps = [], $compare = false, $isgroupmember = false, $allresponses = false, @@ -1865,6 +1875,7 @@ public function survey_update($sdata) { $errstr = get_string('warning', 'questionnaire') . ' [ : ]'; // TODO: notused! return(false); } + $this->survey = $this->get_survey($this->survey->id); } return($this->survey->id); @@ -3556,7 +3567,7 @@ public function generate_csv( '0', // 11: slider -> number. ]; - if (!$survey = $DB->get_record('questionnaire_survey', ['id' => $this->survey->id])) { + if (!$survey = $this->get_survey($this->survey->id)) { throw new \moodle_exception('surveynotexists', 'mod_questionnaire'); } @@ -4010,11 +4021,11 @@ public function move_question($moveqid, $movetopos) { */ public function response_analysis( $rid, - $resps, - $compare, - $isgroupmember, - $allresponses, - $currentgroupid, + $resps = [], + $compare = false, + $isgroupmember = false, + $allresponses = false, + $currentgroupid = 0, $filteredsections = null ) { global $DB, $CFG; @@ -4128,6 +4139,7 @@ public function response_analysis( $allscorepercent = round($alltotalscore / $nbparticipants / $maxtotalscore * 100); // No need to go further if feedback is global, i.e. only relying on total score. + $sectionlabel = ''; if ($this->survey->feedbacksections == 1) { $sectionid = $fbsectionsnb[0]; $sectionlabel = $fbsections[$sectionid]->sectionlabel; @@ -4214,7 +4226,7 @@ public function response_analysis( $oppositescore = ' | ' . $score[1] . '%'; $oppositeallscore = ' | ' . $allscore[1] . '%'; } - if ($this->survey->feedbackscores) { + if ($this->survey->feedbackscores && !empty($allscore)) { $table = $table ?? new html_table(); if ($compare) { $table->data[] = [$sectionlabel, $score[0] . '%' . $oppositescore, $allscore[0] . '%' . $oppositeallscore]; diff --git a/tests/responsetypes_test.php b/tests/responsetypes_test.php index 88995ff7..e3a5143c 100644 --- a/tests/responsetypes_test.php +++ b/tests/responsetypes_test.php @@ -486,4 +486,122 @@ public function test_create_old_response_boolean(): void { $this->assertEmpty($boolresponseresult1); $this->assertEmpty($boolresponseresult2); } + + /** + * Tests the questionnaire response_analysis method. + * + * @covers \questionnaire::response_analysis + */ + public function test_response_analysis(): void { + global $PAGE, $SESSION, $questionnaire; + + $this->resetAfterTest(); + + // Set settings etc. + set_config('usergraph', '1', 'questionnaire'); + $SESSION->questionnaire = new \stdClass(); + $SESSION->questionnaire->current_tab = 'myreport'; + + // Create questinnaire with one boolean response question. + $userid = 1; + $course = $this->getDataGenerator()->create_course(); + $generator = $this->getDataGenerator()->get_plugin_generator('mod_questionnaire'); + $questionnaire = $generator->create_test_questionnaire( + $course, + QUESYESNO, + ['content' => 'Enter yes or no', 'required' => 'y'] + ); + $question = reset($questionnaire->questions); + $generator->create_question_response($questionnaire, $question, 'y', $userid); + + $questionnaire->add_renderer($PAGE->get_renderer('mod_questionnaire')); + $questionnaire->add_page(new output\feedbackpage()); + + // Add feedback section. + $fbsection = feedback\section::new_section($questionnaire->sid, 'FB section 1'); + $feedback = new feedback\sectionfeedback(); + $feedback->sectionid = $fbsection->id; + $feedback->feedbacklabel = 'FB label 1'; + $feedback->feedbacktext = 'FB text 1'; + $feedback->maxscore = 101.0; + $feedback = feedback\sectionfeedback::new_sectionfeedback($feedback); + + $survey = clone($questionnaire->survey); + $survey->sid = $questionnaire->survey->id; + + // Test options for No Feedback. + $survey->feedbacksections = 0; + $survey->feedbackscores = 0; + $this->do_response_analysis($questionnaire, $survey, $feedback, $userid); + + // Test options for Global Feedback. + $survey->feedbacksections = 1; + // Check without scores and chart type. + $survey->feedbackscores = 0; + $survey->chart_type = ''; + $this->do_response_analysis($questionnaire, $survey, $feedback, $userid); + // Check with scores and chart type. + $survey->feedbackscores = 1; + $survey->chart_type = 'bipolar'; + $this->do_response_analysis($questionnaire, $survey, $feedback, $userid); + // Check with question. + $this->do_response_analysis($questionnaire, $survey, $feedback, $userid, $question, $fbsection); + + // Test options for Feedback sections. + $survey->feedbacksections = 2; + // Check without scores and chart type. + $survey->feedbackscores = 0; + $survey->chart_type = ''; + $this->do_response_analysis($questionnaire, $survey, $feedback, $userid); + // Check with scores and chart type. + $survey->feedbackscores = 1; + $survey->chart_type = 'hbar'; + $this->do_response_analysis($questionnaire, $survey, $feedback, $userid); + // Check with question. + $this->do_response_analysis($questionnaire, $survey, $feedback, $userid, $question, $fbsection); + } + + /** + * Runs and checks the response_analysis method. + * + * @param \questionnaire $questionnaire + * @param stdClass $survey + * @param feedback\sectionfeedback $feedback + * @param int $userid + * @param question\question $question + * @param feedback\section $fbsection + */ + private function do_response_analysis( + $questionnaire, + $survey, + $feedback, + $userid, + $question = null, + $fbsection = null + ): void { + $questionnaire->survey_update($survey); + + if ($fbsection != null) { + if ($question != null) { + // Add question to section score calculation. + $scorecalculation = [$question->id => 1]; + $fbsection->set_new_scorecalculation($scorecalculation); + } else { + // Clear section score calculation. + $fbsection->set_new_scorecalculation([]); + } + $fbsection->update(); + } + + // Get and check responses. + $resps = $questionnaire->get_responses($userid); + $this->assertCount(1, $resps, 'Questionnaire responses'); + $rids = array_keys($resps); + $rid = end($rids); + + // Get and check response analysis. + $feedbackmessages = $questionnaire->response_analysis($rid, $resps); + $this->assertNotEmpty($feedbackmessages); + $this->assertContains($feedback->feedbacktext, $feedbackmessages, 'Feedback message'); + } }