Merge branch 'MDL-67513-m310' of https://github.com/NeillM/moodle into MOODLE_310_STABLE
[moodle.git] / question / type / match / renderer.php
1 <?php
2 // This file is part of Moodle - http://moodle.org/
3 //
4 // Moodle is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU General Public License as published by
6 // the Free Software Foundation, either version 3 of the License, or
7 // (at your option) any later version.
8 //
9 // Moodle is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 // GNU General Public License for more details.
13 //
14 // You should have received a copy of the GNU General Public License
15 // along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
17 /**
18  * Matching question renderer class.
19  *
20  * @package   qtype_match
21  * @copyright 2009 The Open University
22  * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
23  */
26 defined('MOODLE_INTERNAL') || die();
29 /**
30  * Generates the output for matching questions.
31  *
32  * @copyright 2009 The Open University
33  * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
34  */
35 class qtype_match_renderer extends qtype_with_combined_feedback_renderer {
37     public function formulation_and_controls(question_attempt $qa,
38             question_display_options $options) {
40         $question = $qa->get_question();
41         $stemorder = $question->get_stem_order();
42         $response = $qa->get_last_qt_data();
44         $choices = $this->format_choices($question);
46         $result = '';
47         $result .= html_writer::tag('div', $question->format_questiontext($qa),
48                 array('class' => 'qtext'));
50         $result .= html_writer::start_tag('div', array('class' => 'ablock'));
51         $result .= html_writer::start_tag('table', array('class' => 'answer'));
52         $result .= html_writer::start_tag('tbody');
54         $parity = 0;
55         $i = 1;
56         foreach ($stemorder as $key => $stemid) {
58             $result .= html_writer::start_tag('tr', array('class' => 'r' . $parity));
59             $fieldname = 'sub' . $key;
61             $result .= html_writer::tag('td', $this->format_stem_text($qa, $stemid),
62                     array('class' => 'text'));
64             $classes = 'control';
65             $feedbackimage = '';
67             if (array_key_exists($fieldname, $response)) {
68                 $selected = $response[$fieldname];
69             } else {
70                 $selected = 0;
71             }
73             $fraction = (int) ($selected && $selected == $question->get_right_choice_for($stemid));
75             if ($options->correctness && $selected) {
76                 $classes .= ' ' . $this->feedback_class($fraction);
77                 $feedbackimage = $this->feedback_image($fraction);
78             }
80             $result .= html_writer::tag('td',
81                     html_writer::label(get_string('answer', 'qtype_match', $i),
82                             'menu' . $qa->get_qt_field_name('sub' . $key), false,
83                             array('class' => 'accesshide')) .
84                     html_writer::select($choices, $qa->get_qt_field_name('sub' . $key), $selected,
85                             array('0' => 'choose'), array('disabled' => $options->readonly, 'class' => 'custom-select ml-1')) .
86                     ' ' . $feedbackimage, array('class' => $classes));
88             $result .= html_writer::end_tag('tr');
89             $parity = 1 - $parity;
90             $i++;
91         }
92         $result .= html_writer::end_tag('tbody');
93         $result .= html_writer::end_tag('table');
95         $result .= html_writer::end_tag('div'); // Closes <div class="ablock">.
97         if ($qa->get_state() == question_state::$invalid) {
98             $result .= html_writer::nonempty_tag('div',
99                     $question->get_validation_error($response),
100                     array('class' => 'validationerror'));
101         }
103         return $result;
104     }
106     public function specific_feedback(question_attempt $qa) {
107         return $this->combined_feedback($qa);
108     }
110     /**
111      * Format each question stem. Overwritten by randomsamatch renderer.
112      *
113      * @param question_attempt $qa
114      * @param integer $stemid stem index
115      * @return string
116      */
117     public function format_stem_text($qa, $stemid) {
118         $question = $qa->get_question();
119         return $question->format_text(
120                     $question->stems[$stemid], $question->stemformat[$stemid],
121                     $qa, 'qtype_match', 'subquestion', $stemid);
122     }
124     protected function format_choices($question) {
125         $choices = array();
126         foreach ($question->get_choice_order() as $key => $choiceid) {
127             $choices[$key] = format_string($question->choices[$choiceid]);
128         }
129         return $choices;
130     }
132     public function correct_response(question_attempt $qa) {
133         $question = $qa->get_question();
134         $stemorder = $question->get_stem_order();
136         $choices = $this->format_choices($question);
137         $right = array();
138         foreach ($stemorder as $key => $stemid) {
139             if (!isset($choices[$question->get_right_choice_for($stemid)])) {
140                 continue;
141             }
142             $right[] = $question->make_html_inline($this->format_stem_text($qa, $stemid)) . ' &#x2192; ' .
143                     $choices[$question->get_right_choice_for($stemid)];
144         }
146         if (!empty($right)) {
147             return get_string('correctansweris', 'qtype_match', implode(', ', $right));
148         }
149     }