MDL-79876 qtype_ordering: Template to output the correct response

Part of: MDL-79863
Creates an exporter class and a template to output the correct
response to a given question attempt.
This commit is contained in:
Mihail Geshoski
2024-04-04 15:26:44 +08:00
committed by Mathew May
parent 6531fa70d7
commit bc2bfead5c
4 changed files with 274 additions and 38 deletions
@@ -0,0 +1,68 @@
<?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/>.
namespace qtype_ordering\output;
/**
* Renderable class for the description of the correct response to a given question attempt.
*
* @package qtype_ordering
* @copyright 2023 Mihail Geshoski <[email protected]>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class correct_response extends renderable_base {
/**
* Export the data for the mustache template.
*
* @param \renderer_base $output renderer to be used to render the action bar elements.
* @return array
*/
public function export_for_template(\renderer_base $output): array {
$data = [];
$question = $this->qa->get_question();
$correctresponse = $question->correctresponse;
$data['hascorrectresponse'] = !empty($correctresponse);
// Early return if a correct response does not exist.
if (!$data['hascorrectresponse']) {
return $data;
}
$step = $this->qa->get_last_step();
// The correct response should be displayed only for partially correct or incorrect answers.
$data['showcorrect'] = $step->get_state() == 'gradedpartial' || $step->get_state() == 'gradedwrong';
// Early return if the correct response should not be displayed.
if (!$data['showcorrect']) {
return $data;
}
$data['orderinglayoutclass'] = $question->get_ordering_layoutclass();
$data['correctanswers'] = [];
foreach ($correctresponse as $answerid) {
$answer = $question->answers[$answerid];
$answertext = $question->format_text($answer->answer, $answer->answerformat,
$this->qa, 'question', 'answer', $answerid);
$data['correctanswers'][] = [
'answertext' => $answertext
];
}
return $data;
}
}
+4 -38
View File
@@ -347,45 +347,11 @@ class qtype_ordering_renderer extends qtype_with_combined_feedback_renderer {
* @param question_attempt $qa the question attempt to display.
* @return string HTML fragment.
*/
public function correct_response(question_attempt $qa) {
global $DB;
public function correct_response(question_attempt $qa): string {
$correctresponse = new \qtype_ordering\output\correct_response($qa);
$output = '';
$showcorrect = false;
$question = $qa->get_question();
if (empty($question->correctresponse)) {
$output .= html_writer::tag('p', get_string('noresponsedetails', 'qtype_ordering'));
} else {
if ($step = $qa->get_last_step()) {
switch ($step->get_state()) {
case 'gradedright':
$showcorrect = false;
break;
case 'gradedpartial':
$showcorrect = true;
break;
case 'gradedwrong':
$showcorrect = true;
break;
}
}
}
if ($showcorrect) {
$sortableitem = $question->get_ordering_layoutclass();
$output .= html_writer::tag('p', get_string('correctorder', 'qtype_ordering'));
$output .= html_writer::start_tag('ol', array('class' => 'correctorder ' . $sortableitem));
$correctresponse = $question->correctresponse;
foreach ($correctresponse as $position => $answerid) {
$answer = $question->answers[$answerid];
$answertext = $question->format_text($answer->answer, $answer->answerformat,
$qa, 'question', 'answer', $answerid);
$output .= html_writer::tag('li', $answertext, array('class' => $sortableitem));
}
$output .= html_writer::end_tag('ol');
}
return $output;
return $this->output->render_from_template('qtype_ordering/correct_response',
$correctresponse->export_for_template($this->output));
}
// Custom methods.
@@ -0,0 +1,59 @@
{{!
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/>.
}}
{{!
@template qtype_ordering/correct_response
Renders the description of the correct response to a given question attempt.
Context variables required for this template:
* hascorrectresponse - Whether correct response exist.
* showcorrect - Whether to show the correct response.
* orderinglayoutclass - The ordering layout CSS class.
* correctanswers - An array containing the correct answers.
* answertext - The formatted answer text.
Example context (json):
{
"hascorrectresponse": true,
"showcorrect": "true",
"orderinglayoutclass": "vertical",
"correctanswers": [
{
"answertext": "Correct answer 1"
},
{
"answertext": "Correct answer 2"
}
]
}
}}
{{#hascorrectresponse}}
{{#showcorrect}}
<p>{{#str}} correctorder, qtype_ordering {{/str}}</p>
<ol class="correctorder {{orderinglayoutclass}}">
{{#correctanswers}}
<li class="{{orderinglayoutclass}}">
{{answertext}}
</li>
{{/correctanswers}}
</ol>
{{/showcorrect}}
{{/hascorrectresponse}}
{{^hascorrectresponse}}
<p>{{#str}} noresponsedetails, qtype_ordering {{/str}}</p>
{{/hascorrectresponse}}
@@ -0,0 +1,143 @@
<?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/>.
namespace qtype_ordering\output;
use advanced_testcase;
use test_question_maker;
use qtype_ordering_question;
use qtype_ordering_test_helper;
defined('MOODLE_INTERNAL') || die();
global $CFG;
require_once($CFG->dirroot . '/question/engine/tests/helpers.php');
/**
* A test class used to test correct_response.
*
* @package qtype_ordering
* @copyright 2023 Mihail Geshoski <[email protected]>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
* @covers \qtype_ordering\output\correct_response
*/
class correct_response_test extends advanced_testcase {
/**
* Test the exported data for the template that renders the correct response to a given question attempt.
*
* @dataProvider export_for_template_provider
* @param array $currentresponse The array of items representing the current response.
* @param string $layouttype The type of the layout.
* @param array $expected The expected exported data.
* @return void
* @covers ::export_for_template
*/
public function test_export_for_template(array $currentresponse, string $layouttype, array $expected): void {
global $PAGE;
$question = test_question_maker::make_question('ordering');
// Set the grading type and layout type options.
$question->options->gradingtype = qtype_ordering_question::GRADING_ABSOLUTE_POSITION;
$question->options->layouttype = $layouttype === 'horizontal' ? qtype_ordering_question::LAYOUT_HORIZONTAL :
qtype_ordering_question::LAYOUT_VERTICAL;
// Create a question attempt.
$qa = new \testable_question_attempt($question, 0);
// Create a question attempt step and add it to the question attemp.
$step = new \question_attempt_step();
$qa->add_step($step);
$question->start_attempt($qa->get_last_step(), 1);
// Get the grading state based on the correct response and the current response, and later set it in the question
// attempt step.
list($fraction, $state) = $question->grade_response(qtype_ordering_test_helper::get_response($question, $currentresponse));
$qa->get_last_step()->set_state($state);
$renderer = $PAGE->get_renderer('core');
$correctresponse = new correct_response($qa);
// Validate the exported data for the template.
$this->assertEquals($expected, $correctresponse->export_for_template($renderer));
}
/**
* Data provider for the test_export_for_template test.
*
* @return array
*/
public function export_for_template_provider(): array {
return [
'Correct question attempt.' => [
['Modular', 'Object', 'Oriented', 'Dynamic', 'Learning', 'Environment'],
'horizontal',
[
'hascorrectresponse' => true,
'showcorrect' => false,
]
],
'Partially correct question attempt (horizontal layout).' => [
['Modular', 'Object', 'Dynamic', 'Learning', 'Oriented', 'Environment'],
'horizontal',
[
'hascorrectresponse' => true,
'showcorrect' => true,
'orderinglayoutclass' => 'horizontal',
'correctanswers' => [
['answertext' => 'Modular'],
['answertext' => 'Object'],
['answertext' => 'Oriented'],
['answertext' => 'Dynamic'],
['answertext' => 'Learning'],
['answertext' => 'Environment'],
],
]
],
'Incorrect question attempt (horizontal layout).' => [
['Object', 'Dynamic', 'Modular', 'Learning', 'Environment', 'Oriented'],
'horizontal',
[
'hascorrectresponse' => true,
'showcorrect' => true,
'orderinglayoutclass' => 'horizontal',
'correctanswers' => [
['answertext' => 'Modular'],
['answertext' => 'Object'],
['answertext' => 'Oriented'],
['answertext' => 'Dynamic'],
['answertext' => 'Learning'],
['answertext' => 'Environment'],
],
]
],
'Incorrect question attempt (vertical layout).' => [
['Object', 'Dynamic', 'Modular', 'Learning', 'Environment', 'Oriented'],
'vertical',
[
'hascorrectresponse' => true,
'showcorrect' => true,
'orderinglayoutclass' => 'vertical',
'correctanswers' => [
['answertext' => 'Modular'],
['answertext' => 'Object'],
['answertext' => 'Oriented'],
['answertext' => 'Dynamic'],
['answertext' => 'Learning'],
['answertext' => 'Environment'],
],
]
],
];
}
}