diff --git a/question/type/ordering/classes/output/formulation_and_controls.php b/question/type/ordering/classes/output/formulation_and_controls.php index 026ba198c32..736f03e841a 100644 --- a/question/type/ordering/classes/output/formulation_and_controls.php +++ b/question/type/ordering/classes/output/formulation_and_controls.php @@ -72,7 +72,7 @@ class formulation_and_controls extends renderable_base { if ($class = $question->get_ordering_layoutclass()) { $data['layoutclass'] = $class; } - if ($numberingstyle = $question->options->numberingstyle) { + if ($numberingstyle = $question->numberingstyle) { $data['numberingstyle'] = $numberingstyle; } diff --git a/question/type/ordering/classes/output/specific_grade_detail_feedback.php b/question/type/ordering/classes/output/specific_grade_detail_feedback.php index 2a9cc052cf3..7de9472d911 100644 --- a/question/type/ordering/classes/output/specific_grade_detail_feedback.php +++ b/question/type/ordering/classes/output/specific_grade_detail_feedback.php @@ -52,9 +52,9 @@ class specific_grade_detail_feedback extends renderable_base { $plugin = 'qtype_ordering'; // Show grading details if they are required. - if ($question->options->showgrading) { + if ($question->showgrading) { // Fetch grading type. - $gradingtype = $question->options->gradingtype; + $gradingtype = $question->gradingtype; $gradingtype = qtype_ordering_question::get_grading_types($gradingtype); // Format grading type, e.g. Grading type: Relative to next item, excluding last item. diff --git a/question/type/ordering/db/install.xml b/question/type/ordering/db/install.xml index 929712491d6..6183620dda0 100644 --- a/question/type/ordering/db/install.xml +++ b/question/type/ordering/db/install.xml @@ -5,11 +5,11 @@ - - - - - + + + + + diff --git a/question/type/ordering/question.php b/question/type/ordering/question.php index 4a362e6299e..6411cfb011d 100644 --- a/question/type/ordering/question.php +++ b/question/type/ordering/question.php @@ -102,9 +102,6 @@ class qtype_ordering_question extends question_graded_automatically { /** @var array Records from "question_answers" table */ public $answers; - /** @var stdClass Records from "qtype_ordering_options" table */ - public $options; - /** @var array of answerids in correct order */ public $correctresponse; @@ -134,12 +131,12 @@ class qtype_ordering_question extends question_graded_automatically { $countanswers = count($this->answers); // Sanitize "selecttype". - $selecttype = $this->options->selecttype; + $selecttype = $this->selecttype; $selecttype = max(0, $selecttype); $selecttype = min(2, $selecttype); // Sanitize "selectcount". - $selectcount = $this->options->selectcount; + $selectcount = $this->selectcount; $selectcount = max(3, $selectcount); $selectcount = min($countanswers, $selectcount); @@ -408,7 +405,7 @@ class qtype_ordering_question extends question_graded_automatically { $countcorrect = 0; $countanswers = 0; - $gradingtype = $this->options->gradingtype; + $gradingtype = $this->gradingtype; switch ($gradingtype) { case self::GRADING_ALL_OR_NOTHING: @@ -593,7 +590,7 @@ class qtype_ordering_question extends question_graded_automatically { * @return string */ public function get_ordering_layoutclass(): string { - switch ($this->options->layouttype) { + switch ($this->layouttype) { case self::LAYOUT_VERTICAL: return 'vertical'; case self::LAYOUT_HORIZONTAL: @@ -873,7 +870,7 @@ class qtype_ordering_question extends question_graded_automatically { */ public function get_num_parts_right(array $response): array { $this->update_current_response($response); - $gradingtype = $this->options->gradingtype; + $gradingtype = $this->gradingtype; $numright = 0; $numpartial = 0; @@ -914,7 +911,7 @@ class qtype_ordering_question extends question_graded_automatically { array $correctresponse, array $currentresponse ): array { - $gradingtype = $this->options->gradingtype; + $gradingtype = $this->gradingtype; $score = 0; $maxscore = null; @@ -1044,7 +1041,7 @@ class qtype_ordering_question extends question_graded_automatically { if (!isset($this->itemscores[$position])) { - [$correctresponse, $currentresponse] = $this->get_response_depend_on_grading_type($question->options->gradingtype); + [$correctresponse, $currentresponse] = $this->get_response_depend_on_grading_type($this->gradingtype); $percent = 0; // 100 * $fraction. [$fraction, $score, $maxscore] = diff --git a/question/type/ordering/questiontype.php b/question/type/ordering/questiontype.php index f34f11ad38c..9ecef0dd321 100644 --- a/question/type/ordering/questiontype.php +++ b/question/type/ordering/questiontype.php @@ -77,9 +77,6 @@ class qtype_ordering extends question_type { $question->answers[$answerid]->md5key = 'ordering_item_' . md5(($CFG->passwordsaltmain ?? '') . $answer->answer); } - $question->options = clone($questiondata->options); - unset($question->options->answers); - $this->initialise_combined_feedback($question, $questiondata, true); } diff --git a/question/type/ordering/renderer.php b/question/type/ordering/renderer.php index f7c7e13c3a8..99f422209e6 100644 --- a/question/type/ordering/renderer.php +++ b/question/type/ordering/renderer.php @@ -14,6 +14,12 @@ // You should have received a copy of the GNU General Public License // along with Moodle. If not, see . +use qtype_ordering\output\correct_response; +use qtype_ordering\output\feedback; +use qtype_ordering\output\formulation_and_controls; +use qtype_ordering\output\num_parts_correct; +use qtype_ordering\output\specific_grade_detail_feedback; + /** * Ordering question renderer class. * @@ -21,41 +27,24 @@ * @copyright 2013 Gordon Bateson (gordonbateson@gmail.com) * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ - -// Prevent direct access to this script. - -/** - * Generates the output for ordering questions - * - * @copyright 2013 Gordon Bateson - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ class qtype_ordering_renderer extends qtype_with_combined_feedback_renderer { - /** @var array of answerids in correct order */ - protected $correctinfo = null; - - /** @var array of answerids in order of current answer*/ - protected $currentinfo = null; - - /** @var array of scored for every item */ - protected $itemscores = array(); - - /** @var bool True if answer is 100% correct */ - protected $allcorrect = null; + // Disable coverage report for most of this file as each method is tested separately and as a while via Behat. + // @codeCoverageIgnoreStart /** * Generate the display of the formulation part of the question. This is the - * area that contains the quetsion text, and the controls for students to + * area that contains the question text, and the controls for students to * input their answers. Some question types also embed bits of feedback, for * example ticks and crosses, in this area. * * @param question_attempt $qa the question attempt to display. * @param question_display_options $options controls what should and should not be displayed. * @return string HTML fragment. + * @throws moodle_exception */ - public function formulation_and_controls(question_attempt $qa, question_display_options $options) { - $formulationandcontrols = new \qtype_ordering\output\formulation_and_controls($qa, $options); + public function formulation_and_controls(question_attempt $qa, question_display_options $options): string { + $formulationandcontrols = new formulation_and_controls($qa, $options); return $this->output->render_from_template('qtype_ordering/formulation_and_controls', $formulationandcontrols->export_for_template($this->output)); } @@ -65,13 +54,13 @@ class qtype_ordering_renderer extends qtype_with_combined_feedback_renderer { * area that contains the various forms of feedback. This function generates * the content of this area belonging to the question type. * - * @codeCoverageIgnore This is tested by the feedback exporter. * @param question_attempt $qa The question attempt to display. * @param question_display_options $options Controls what should and should not be displayed. * @return string HTML fragment. + * @throws moodle_exception */ - public function feedback(question_attempt $qa, question_display_options $options) { - $feedback = new \qtype_ordering\output\feedback($qa, $options); + public function feedback(question_attempt $qa, question_display_options $options): string { + $feedback = new feedback($qa, $options); return $this->output->render_from_template('qtype_ordering/feedback', $feedback->export_for_template($this->output)); } @@ -81,9 +70,10 @@ class qtype_ordering_renderer extends qtype_with_combined_feedback_renderer { * * @param question_attempt $qa The question attempt to display. * @return string Output grade detail of the response. + * @throws moodle_exception */ public function specific_grade_detail_feedback(question_attempt $qa): string { - $specificgradedetailfeedback = new \qtype_ordering\output\specific_grade_detail_feedback($qa); + $specificgradedetailfeedback = new specific_grade_detail_feedback($qa); return $this->output->render_from_template('qtype_ordering/specific_grade_detail_feedback', $specificgradedetailfeedback->export_for_template($this->output)); } @@ -92,11 +82,10 @@ class qtype_ordering_renderer extends qtype_with_combined_feedback_renderer { * Generate the specific feedback. This is feedback that varies according to * the response the student gave. * - * @codeCoverageIgnore This is tested by the feedback exporter. * @param question_attempt $qa The question attempt to display. * @return string HTML fragment. */ - public function specific_feedback(question_attempt $qa) { + public function specific_feedback(question_attempt $qa): string { return $this->combined_feedback($qa); } @@ -107,34 +96,38 @@ class qtype_ordering_renderer extends qtype_with_combined_feedback_renderer { * * @param question_attempt $qa the question attempt to display. * @return string HTML fragment. + * @throws moodle_exception */ public function correct_response(question_attempt $qa): string { - $correctresponse = new \qtype_ordering\output\correct_response($qa); + $correctresponse = new correct_response($qa); return $this->output->render_from_template('qtype_ordering/correct_response', $correctresponse->export_for_template($this->output)); } - // Custom methods. - /** * Generate a brief statement of how many sub-parts of this question the * student got correct|partial|incorrect. * * @param question_attempt $qa The question attempt to display. * @return string HTML fragment. + * @throws moodle_exception */ - protected function num_parts_correct(question_attempt $qa) { - $numpartscorrect = new \qtype_ordering\output\num_parts_correct($qa); + protected function num_parts_correct(question_attempt $qa): string { + $numpartscorrect = new num_parts_correct($qa); return $this->output->render_from_template('qtype_ordering/num_parts_correct', $numpartscorrect->export_for_template($this->output)); } + // Below this point, is code that will be included in the report as it isn't reported in isolation. + // @codeCoverageIgnoreEnd + /** * Return an appropriate icon (green tick, red cross, etc.) for a grade. + * Note: Strict typing the params here breaks code eval as the parent function is not strictly typed. * - * @param float $fraction grade on a scale 0..1. - * @param bool $selected whether to show a big or small icon. (Deprecated) + * @param float $fraction The fraction of the maximum grade that was awarded. + * @param bool $selected Deprecated: size option. * @return string html fragment. */ public function feedback_image($fraction, $selected = true): string { diff --git a/question/type/ordering/tests/helper.php b/question/type/ordering/tests/helper.php index b6565d08f0e..cdf71656dc3 100644 --- a/question/type/ordering/tests/helper.php +++ b/question/type/ordering/tests/helper.php @@ -62,14 +62,13 @@ class qtype_ordering_test_helper extends question_test_helper { 17 => $this->make_answer(17, 'Learning', FORMAT_HTML, 5, true), 18 => $this->make_answer(18, 'Environment', FORMAT_HTML, 6, true), ]; - $q->options = new stdClass(); - $q->options->layouttype = qtype_ordering_question::LAYOUT_HORIZONTAL; - $q->options->selecttype = qtype_ordering_question::SELECT_ALL; - $q->options->selectcount = 0; - $q->options->gradingtype = qtype_ordering_question::GRADING_RELATIVE_ALL_PREVIOUS_AND_NEXT; - $q->options->showgrading = true; - $q->options->numberingstyle = qtype_ordering_question::NUMBERING_STYLE_DEFAULT; - $q->options->shownumcorrect = 1; + $q->layouttype = qtype_ordering_question::LAYOUT_HORIZONTAL; + $q->selecttype = qtype_ordering_question::SELECT_ALL; + $q->selectcount = 0; + $q->gradingtype = qtype_ordering_question::GRADING_RELATIVE_ALL_PREVIOUS_AND_NEXT; + $q->showgrading = true; + $q->numberingstyle = qtype_ordering_question::NUMBERING_STYLE_DEFAULT; + $q->shownumcorrect = 1; return $q; } diff --git a/question/type/ordering/tests/output/correct_response_test.php b/question/type/ordering/tests/output/correct_response_test.php index b50c1939b79..fc9de85742a 100644 --- a/question/type/ordering/tests/output/correct_response_test.php +++ b/question/type/ordering/tests/output/correct_response_test.php @@ -50,8 +50,8 @@ class correct_response_test extends advanced_testcase { $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 : + $question->gradingtype = qtype_ordering_question::GRADING_ABSOLUTE_POSITION; + $question->layouttype = $layouttype === 'horizontal' ? qtype_ordering_question::LAYOUT_HORIZONTAL : qtype_ordering_question::LAYOUT_VERTICAL; // Create a question attempt. $qa = new \testable_question_attempt($question, 0); diff --git a/question/type/ordering/tests/output/feedback_test.php b/question/type/ordering/tests/output/feedback_test.php index f162603d545..6bf3a715d53 100644 --- a/question/type/ordering/tests/output/feedback_test.php +++ b/question/type/ordering/tests/output/feedback_test.php @@ -77,7 +77,7 @@ class feedback_test extends qbehaviour_walkthrough_test_base { new question_hint_ordering(13, 'This is the first hint.', FORMAT_HTML, true, false, true), new question_hint_ordering(14, 'This is the second hint.', FORMAT_HTML, false, false, false), ]; - $question->options->layouttype = $testoptions['rot'] === 'horizontal' ? qtype_ordering_question::LAYOUT_HORIZONTAL : + $question->layouttype = $testoptions['rot'] === 'horizontal' ? qtype_ordering_question::LAYOUT_HORIZONTAL : qtype_ordering_question::LAYOUT_VERTICAL; // If we need to access the attempt midway through, we need a flow where we don't grade instantly. @@ -86,7 +86,7 @@ class feedback_test extends qbehaviour_walkthrough_test_base { $step = new \question_attempt_step(); $qa->add_step($step); $qa->set_behaviour($question->make_behaviour($qa, 'interactive')); - $question->options->gradingtype = $gradingtype; + $question->gradingtype = $gradingtype; $question->start_attempt($step, 1); // Process a response and check the expected result. $keys = implode(',', array_keys($answeritems)); diff --git a/question/type/ordering/tests/output/formulation_and_controls_test.php b/question/type/ordering/tests/output/formulation_and_controls_test.php index 5dee6fc1fed..2efda6ad376 100644 --- a/question/type/ordering/tests/output/formulation_and_controls_test.php +++ b/question/type/ordering/tests/output/formulation_and_controls_test.php @@ -52,7 +52,7 @@ class formulation_and_controls_test extends advanced_testcase { global $PAGE; $question = test_question_maker::make_question('ordering'); - $question->options->layouttype = $layouttype === 'horizontal' ? qtype_ordering_question::LAYOUT_HORIZONTAL : + $question->layouttype = $layouttype === 'horizontal' ? qtype_ordering_question::LAYOUT_HORIZONTAL : qtype_ordering_question::LAYOUT_VERTICAL; $qa = new \testable_question_attempt($question, 0); $step = new \question_attempt_step(); @@ -66,7 +66,7 @@ class formulation_and_controls_test extends advanced_testcase { $options->rightanswer = question_display_options::VISIBLE; $options->manualcomment = question_display_options::VISIBLE; $options->history = question_display_options::VISIBLE; - $question->options->gradingtype = $gradingtype; + $question->gradingtype = $gradingtype; $keys = implode(',', array_keys($answeritems)); $values = array_values($answeritems); diff --git a/question/type/ordering/tests/output/num_parts_correct_test.php b/question/type/ordering/tests/output/num_parts_correct_test.php index 3e25131f5c8..3dd86428a22 100644 --- a/question/type/ordering/tests/output/num_parts_correct_test.php +++ b/question/type/ordering/tests/output/num_parts_correct_test.php @@ -54,7 +54,7 @@ class num_parts_correct_test extends advanced_testcase { $step = new \question_attempt_step(); $qa->add_step($step); $question->start_attempt($step, 1); - $question->options->gradingtype = $gradingtype; + $question->gradingtype = $gradingtype; $keys = implode(',', array_keys($answeritems)); $step->set_qt_var('_currentresponse', $keys); diff --git a/question/type/ordering/tests/output/specific_grade_detail_feedback_test.php b/question/type/ordering/tests/output/specific_grade_detail_feedback_test.php index d0e9da0c4fd..c56dc450656 100644 --- a/question/type/ordering/tests/output/specific_grade_detail_feedback_test.php +++ b/question/type/ordering/tests/output/specific_grade_detail_feedback_test.php @@ -53,10 +53,10 @@ class specific_grade_detail_feedback_test extends advanced_testcase { $this->resetAfterTest(); $question = test_question_maker::make_question('ordering'); // Options need to be set before starting the attempt otherwise they are not passed along. - $question->options->layouttype = $layouttype === 'horizontal' ? qtype_ordering_question::LAYOUT_HORIZONTAL : + $question->layouttype = $layouttype === 'horizontal' ? qtype_ordering_question::LAYOUT_HORIZONTAL : qtype_ordering_question::LAYOUT_VERTICAL; - $question->options->gradingtype = $gradingtype; - $question->options->selecttype = $selecttype; + $question->gradingtype = $gradingtype; + $question->selecttype = $selecttype; $qa = new \testable_question_attempt($question, 0); $step = new \question_attempt_step(); $qa->add_step($step); diff --git a/question/type/ordering/tests/question_test.php b/question/type/ordering/tests/question_test.php index 0e456435ce1..7b81bdea853 100644 --- a/question/type/ordering/tests/question_test.php +++ b/question/type/ordering/tests/question_test.php @@ -61,7 +61,7 @@ class question_test extends \advanced_testcase { /** @var qtype_ordering_question $question */ $question = test_question_maker::make_question('ordering'); // Zero grade on any error (no partial score at all, it is either 1 or 0). - $question->options->gradingtype = qtype_ordering_question::GRADING_ALL_OR_NOTHING; + $question->gradingtype = qtype_ordering_question::GRADING_ALL_OR_NOTHING; $question->start_attempt(new question_attempt_pending_step(), 1); $this->assertEquals( @@ -97,7 +97,7 @@ class question_test extends \advanced_testcase { /** @var qtype_ordering_question $question */ $question = test_question_maker::make_question('ordering'); // Counts items, placed into right absolute place. - $question->options->gradingtype = qtype_ordering_question::GRADING_ABSOLUTE_POSITION; + $question->gradingtype = qtype_ordering_question::GRADING_ABSOLUTE_POSITION; $question->start_attempt(new question_attempt_pending_step(), 1); // Every item is in the correct position. $this->assertEquals( @@ -163,7 +163,7 @@ class question_test extends \advanced_testcase { /** @var qtype_ordering_question $question */ $question = test_question_maker::make_question('ordering'); // Every sequential pair in right order is graded (last pair is excluded). - $question->options->gradingtype = qtype_ordering_question::GRADING_RELATIVE_NEXT_EXCLUDE_LAST; + $question->gradingtype = qtype_ordering_question::GRADING_RELATIVE_NEXT_EXCLUDE_LAST; $question->start_attempt(new question_attempt_pending_step(), 1); // Every item is in the correct position. @@ -212,7 +212,7 @@ class question_test extends \advanced_testcase { /** @var qtype_ordering_question $question */ $question = test_question_maker::make_question('ordering'); // Every sequential pair in right order is graded (last pair is included). - $question->options->gradingtype = qtype_ordering_question::GRADING_RELATIVE_NEXT_INCLUDE_LAST; + $question->gradingtype = qtype_ordering_question::GRADING_RELATIVE_NEXT_INCLUDE_LAST; $question->start_attempt(new question_attempt_pending_step(), 1); // Every item is in the correct position. $this->assertEquals( @@ -250,7 +250,7 @@ class question_test extends \advanced_testcase { /** @var qtype_ordering_question $question */ $question = test_question_maker::make_question('ordering'); // Single answers that are placed before and after each answer is graded if in right order. - $question->options->gradingtype = qtype_ordering_question::GRADING_RELATIVE_ONE_PREVIOUS_AND_NEXT; + $question->gradingtype = qtype_ordering_question::GRADING_RELATIVE_ONE_PREVIOUS_AND_NEXT; $question->start_attempt(new question_attempt_pending_step(), 1); // All items are in the correct position. $this->assertEquals( @@ -297,7 +297,7 @@ class question_test extends \advanced_testcase { /** @var qtype_ordering_question $question */ $question = test_question_maker::make_question('ordering'); // All answers that are placed before and after each answer is graded if in right order. - $question->options->gradingtype = qtype_ordering_question::GRADING_RELATIVE_ALL_PREVIOUS_AND_NEXT; + $question->gradingtype = qtype_ordering_question::GRADING_RELATIVE_ALL_PREVIOUS_AND_NEXT; $question->start_attempt(new question_attempt_pending_step(), 1); // All items are in the correct position. $this->assertEquals( @@ -353,7 +353,7 @@ class question_test extends \advanced_testcase { /** @var qtype_ordering_question $question */ $question = test_question_maker::make_question('ordering'); // Only longest ordered subset is graded. - $question->options->gradingtype = qtype_ordering_question::GRADING_LONGEST_ORDERED_SUBSET; + $question->gradingtype = qtype_ordering_question::GRADING_LONGEST_ORDERED_SUBSET; $question->start_attempt(new question_attempt_pending_step(), 1); // All items are in the correct position. $this->assertEquals( @@ -400,7 +400,7 @@ class question_test extends \advanced_testcase { /** @var qtype_ordering_question $question */ $question = test_question_maker::make_question('ordering'); // Only longest ordered and contiguous subset is graded. - $question->options->gradingtype = qtype_ordering_question::GRADING_LONGEST_CONTIGUOUS_SUBSET; + $question->gradingtype = qtype_ordering_question::GRADING_LONGEST_CONTIGUOUS_SUBSET; $question->start_attempt(new question_attempt_pending_step(), 1); // All items are in the correct position. $this->assertEquals( @@ -447,7 +447,7 @@ class question_test extends \advanced_testcase { /** @var qtype_ordering_question $question */ $question = test_question_maker::make_question('ordering'); // Items are graded relative to their position in the correct answer. - $question->options->gradingtype = qtype_ordering_question::GRADING_RELATIVE_TO_CORRECT; + $question->gradingtype = qtype_ordering_question::GRADING_RELATIVE_TO_CORRECT; $question->start_attempt(new question_attempt_pending_step(), 1); // All items are in the correct position. $this->assertEquals( @@ -579,13 +579,13 @@ class question_test extends \advanced_testcase { /** @var qtype_ordering_question $question */ $question = test_question_maker::make_question('ordering'); - if ($question->options->layouttype === 0) { + if ($question->layouttype === 0) { $this->assertEquals('vertical', $question->get_ordering_layoutclass()); - } else if ($question->options->layouttype === 1) { + } else if ($question->layouttype === 1) { $this->assertEquals('horizontal', $question->get_ordering_layoutclass()); } // Confirm that if an invalid layouttype is set, an empty string is returned. - $question->options->layouttype = 3; + $question->layouttype = 3; $error = $question->get_ordering_layoutclass(); $this->assertEquals('', $error); } @@ -697,7 +697,7 @@ class question_test extends \advanced_testcase { /** @var qtype_ordering_question $question */ $question = test_question_maker::make_question('ordering'); - $question->options->gradingtype = qtype_ordering_question::GRADING_RELATIVE_TO_CORRECT; + $question->gradingtype = qtype_ordering_question::GRADING_RELATIVE_TO_CORRECT; $question->start_attempt(new question_attempt_pending_step(), 1); $response = qtype_ordering_test_helper::get_response(