PageRenderTime 55ms CodeModel.GetById 26ms RepoModel.GetById 0ms app.codeStats 0ms

/question/type/multichoice/renderer.php

https://github.com/mkassaei/Moodle-Question-Engine-2
PHP | 313 lines | 204 code | 53 blank | 56 comment | 22 complexity | c8042def009c139b0d1b388a6067acc1 MD5 | raw file
  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/>.
  16. /**
  17. * Multiple choice question renderer classes.
  18. *
  19. * @package qtype_multichoice
  20. * @copyright 2009 The Open University
  21. * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  22. */
  23. /**
  24. * Base class for generating the bits of output common to multiple choice
  25. * single and multiple questions.
  26. *
  27. * @copyright 2009 The Open University
  28. * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  29. */
  30. abstract class qtype_multichoice_renderer_base extends qtype_with_combined_feedback_renderer {
  31. abstract protected function get_input_type();
  32. abstract protected function get_input_name(question_attempt $qa, $value);
  33. abstract protected function get_input_value($value);
  34. abstract protected function get_input_id(question_attempt $qa, $value);
  35. abstract protected function is_choice_selected($response, $value);
  36. /**
  37. * Whether a choice should be considered right, wrong or partially right.
  38. * @param question_answer $ans representing one of the choices.
  39. * @return fload 1.0, 0.0 or something in between, respectively.
  40. */
  41. abstract protected function is_right(question_answer $ans);
  42. abstract protected function get_response(question_attempt $qa);
  43. abstract protected function prompt();
  44. public function formulation_and_controls(question_attempt $qa,
  45. question_display_options $options) {
  46. $question = $qa->get_question();
  47. $order = $question->get_order($qa);
  48. $response = $this->get_response($qa);
  49. $inputname = $qa->get_qt_field_name('answer');
  50. $inputattributes = array(
  51. 'type' => $this->get_input_type(),
  52. 'name' => $inputname,
  53. );
  54. if ($options->readonly) {
  55. $inputattributes['disabled'] = 'disabled';
  56. }
  57. $radiobuttons = array();
  58. $feedbackimg = array();
  59. $feedback = array();
  60. $classes = array();
  61. foreach ($order as $value => $ansid) {
  62. $ans = $question->answers[$ansid];
  63. $inputattributes['name'] = $this->get_input_name($qa, $value);
  64. $inputattributes['value'] = $this->get_input_value($value);
  65. $inputattributes['id'] = $this->get_input_id($qa, $value);
  66. $isselected = $this->is_choice_selected($response, $value);
  67. if ($isselected) {
  68. $inputattributes['checked'] = 'checked';
  69. } else {
  70. unset($inputattributes['checked']);
  71. }
  72. $hidden = '';
  73. if (!$options->readonly && $this->get_input_type() == 'checkbox') {
  74. $hidden = html_writer::empty_tag('input', array(
  75. 'type' => 'hidden',
  76. 'name' => $inputattributes['name'],
  77. 'value' => 0,
  78. ));
  79. }
  80. $radiobuttons[] = $hidden . html_writer::empty_tag('input', $inputattributes) .
  81. html_writer::tag('label', $this->number_in_style($value, $question->answernumbering) .
  82. $question->format_text($ans->answer), array('for' => $inputattributes['id']));
  83. // $options->suppresschoicefeedback is a hack specific to the
  84. // oumultiresponse question type. It would be good to refactor to
  85. // avoid refering to it here.
  86. if ($options->feedback && empty($options->suppresschoicefeedback) &&
  87. $isselected && trim($ans->feedback)) {
  88. $feedback[] = html_writer::tag('div',
  89. $question->format_text($ans->feedback),
  90. array('class' => 'specificfeedback'));
  91. } else {
  92. $feedback[] = '';
  93. }
  94. $class = 'r' . ($value % 2);
  95. if ($options->correctness && $isselected) {
  96. $feedbackimg[] = $this->feedback_image($this->is_right($ans));
  97. $class .= ' ' . $this->feedback_class($this->is_right($ans));
  98. } else {
  99. $feedbackimg[] = '';
  100. }
  101. $classes[] = $class;
  102. }
  103. $result = '';
  104. $result .= html_writer::tag('div', $question->format_questiontext(),
  105. array('class' => 'qtext'));
  106. $result .= html_writer::start_tag('div', array('class' => 'ablock'));
  107. $result .= html_writer::tag('div', $this->prompt(), array('class' => 'prompt'));
  108. $result .= html_writer::start_tag('div', array('class' => 'answer'));
  109. foreach ($radiobuttons as $key => $radio) {
  110. $result .= html_writer::tag('span', $radio . ' ' . $feedbackimg[$key] . $feedback[$key],
  111. array('class' => $classes[$key])) . "\n";
  112. }
  113. $result .= html_writer::end_tag('div'); // answer
  114. $result .= html_writer::end_tag('div'); // ablock
  115. if ($qa->get_state() == question_state::$invalid) {
  116. $result .= html_writer::nonempty_tag('div',
  117. $question->get_validation_error($qa->get_last_qt_data()),
  118. array('class' => 'validationerror'));
  119. }
  120. return $result;
  121. }
  122. protected function number_html($qnum) {
  123. return $qnum . '. ';
  124. }
  125. /**
  126. * @param int $num The number, starting at 0.
  127. * @param string $style The style to render the number in. One of the
  128. * options returned by {@link qtype_multichoice:;get_numbering_styles()}.
  129. * @return string the number $num in the requested style.
  130. */
  131. protected function number_in_style($num, $style) {
  132. switch($style) {
  133. case 'abc':
  134. $number = chr(ord('a') + $num);
  135. break;
  136. case 'ABCD':
  137. $number = chr(ord('A') + $num);
  138. break;
  139. case '123':
  140. $number = $num + 1;
  141. break;
  142. case 'iii':
  143. $number = question_utils::int_to_roman($num + 1);
  144. break;
  145. case 'IIII':
  146. $number = strtoupper(question_utils::int_to_roman($num + 1));
  147. break;
  148. case 'none':
  149. return '';
  150. default:
  151. return 'ERR';
  152. }
  153. return $this->number_html($number);
  154. }
  155. public function specific_feedback(question_attempt $qa) {
  156. return $this->combined_feedback($qa);
  157. }
  158. }
  159. /**
  160. * Subclass for generating the bits of output specific to multiple choice
  161. * single questions.
  162. *
  163. * @copyright 2009 The Open University
  164. * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  165. */
  166. class qtype_multichoice_single_renderer extends qtype_multichoice_renderer_base {
  167. protected function get_input_type() {
  168. return 'radio';
  169. }
  170. protected function get_input_name(question_attempt $qa, $value) {
  171. return $qa->get_qt_field_name('answer');
  172. }
  173. protected function get_input_value($value) {
  174. return $value;
  175. }
  176. protected function get_input_id(question_attempt $qa, $value) {
  177. return $qa->get_qt_field_name('answer' . $value);
  178. }
  179. protected function get_response(question_attempt $qa) {
  180. return $qa->get_last_qt_var('answer', -1);
  181. }
  182. protected function is_choice_selected($response, $value) {
  183. return $response == $value;
  184. }
  185. protected function is_right(question_answer $ans) {
  186. return $ans->fraction;
  187. }
  188. protected function prompt() {
  189. return get_string('selectone', 'qtype_multichoice');
  190. }
  191. public function correct_response(question_attempt $qa) {
  192. $question = $qa->get_question();
  193. foreach ($question->answers as $ans) {
  194. if (question_state::graded_state_for_fraction($ans->fraction) ==
  195. question_state::$gradedright) {
  196. return get_string('correctansweris', 'qtype_multichoice',
  197. $question->format_text($ans->answer));
  198. }
  199. }
  200. return '';
  201. }
  202. }
  203. /**
  204. * Subclass for generating the bits of output specific to multiple choice
  205. * multi=select questions.
  206. *
  207. * @copyright 2009 The Open University
  208. * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  209. */
  210. class qtype_multichoice_multi_renderer extends qtype_multichoice_renderer_base {
  211. protected function get_input_type() {
  212. return 'checkbox';
  213. }
  214. protected function get_input_name(question_attempt $qa, $value) {
  215. return $qa->get_qt_field_name('choice' . $value);
  216. }
  217. protected function get_input_value($value) {
  218. return 1;
  219. }
  220. protected function get_input_id(question_attempt $qa, $value) {
  221. return $this->get_input_name($qa, $value);
  222. }
  223. protected function get_response(question_attempt $qa) {
  224. return $qa->get_last_qt_data();
  225. }
  226. protected function is_choice_selected($response, $value) {
  227. return !empty($response['choice' . $value]);
  228. }
  229. protected function is_right(question_answer $ans) {
  230. if ($ans->fraction > 0) {
  231. return 1;
  232. } else {
  233. return 0;
  234. }
  235. }
  236. protected function prompt() {
  237. return get_string('selectmulti', 'qtype_multichoice');
  238. }
  239. public function correct_response(question_attempt $qa) {
  240. $question = $qa->get_question();
  241. $right = array();
  242. foreach ($question->answers as $ans) {
  243. if ($ans->fraction > 0) {
  244. $right[] = $question->format_text($ans->answer);
  245. }
  246. }
  247. if (!empty($right)) {
  248. return get_string('correctansweris', 'qtype_multichoice',
  249. implode(', ', $right));
  250. }
  251. return '';
  252. }
  253. protected function num_parts_correct(question_attempt $qa) {
  254. if ($qa->get_question()->get_num_selected_choices($qa->get_last_qt_data()) >
  255. $qa->get_question()->get_num_correct_choices()) {
  256. return get_string('toomanyselected', 'qtype_multichoice');
  257. }
  258. return parent::num_parts_correct($qa);
  259. }
  260. }