Skip to content

Commit

Permalink
MDL-79863 qtype_ordering: Ensure qtype_ordering is compatible with PH…
Browse files Browse the repository at this point in the history
…P 8.2

Co-authored by: Mathew May <mathewm@hotmail.co.nz>
  • Loading branch information
ilyatregubov authored and Chocolate-lightning committed Apr 4, 2024
1 parent 63ed08c commit 272c897
Show file tree
Hide file tree
Showing 13 changed files with 74 additions and 88 deletions.
Expand Up @@ -72,7 +72,7 @@ public function export_for_template(\renderer_base $output): array {
if ($class = $question->get_ordering_layoutclass()) {
$data['layoutclass'] = $class;
}
if ($numberingstyle = $question->options->numberingstyle) {
if ($numberingstyle = $question->numberingstyle) {
$data['numberingstyle'] = $numberingstyle;
}

Expand Down
Expand Up @@ -52,9 +52,9 @@ public function export_for_template(\renderer_base $output): array {
$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.
Expand Down
10 changes: 5 additions & 5 deletions question/type/ordering/db/install.xml
Expand Up @@ -5,11 +5,11 @@
<FIELDS>
<FIELD NAME="id" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="true"/>
<FIELD NAME="questionid" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false"/>
<FIELD NAME="layouttype" TYPE="int" LENGTH="2" NOTNULL="true" DEFAULT="0" SEQUENCE="false"/>
<FIELD NAME="selecttype" TYPE="int" LENGTH="2" NOTNULL="true" DEFAULT="0" SEQUENCE="false"/>
<FIELD NAME="selectcount" TYPE="int" LENGTH="4" NOTNULL="true" DEFAULT="0" SEQUENCE="false"/>
<FIELD NAME="gradingtype" TYPE="int" LENGTH="2" NOTNULL="true" DEFAULT="0" SEQUENCE="false"/>
<FIELD NAME="showgrading" TYPE="int" LENGTH="2" NOTNULL="true" DEFAULT="0" SEQUENCE="false"/>
<FIELD NAME="layouttype" TYPE="int" LENGTH="2" NOTNULL="true" DEFAULT="0" SEQUENCE="false" COMMENT="Layout type - horizontal or vertical"/>
<FIELD NAME="selecttype" TYPE="int" LENGTH="2" NOTNULL="true" DEFAULT="0" SEQUENCE="false" COMMENT="Select type - all, random etc."/>
<FIELD NAME="selectcount" TYPE="int" LENGTH="4" NOTNULL="true" DEFAULT="0" SEQUENCE="false" COMMENT="The number to select."/>
<FIELD NAME="gradingtype" TYPE="int" LENGTH="2" NOTNULL="true" DEFAULT="0" SEQUENCE="false" COMMENT="Which grading strategy to use. One of the GRADING_... constants."/>
<FIELD NAME="showgrading" TYPE="int" LENGTH="2" NOTNULL="true" DEFAULT="0" SEQUENCE="false" COMMENT="Should details of the grading calculation be shown to students."/>
<FIELD NAME="numberingstyle" TYPE="char" LENGTH="10" NOTNULL="true" DEFAULT="none" SEQUENCE="false" COMMENT="Indicates whether and how choices should be numbered."/>
<FIELD NAME="correctfeedback" TYPE="text" NOTNULL="false" SEQUENCE="false"/>
<FIELD NAME="correctfeedbackformat" TYPE="int" LENGTH="2" NOTNULL="true" DEFAULT="0" SEQUENCE="false"/>
Expand Down
17 changes: 7 additions & 10 deletions question/type/ordering/question.php
Expand Up @@ -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;

Expand Down Expand Up @@ -134,12 +131,12 @@ public function start_attempt(question_attempt_step $step, $variant) {
$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);

Expand Down Expand Up @@ -408,7 +405,7 @@ public function grade_response(array $response) {
$countcorrect = 0;
$countanswers = 0;

$gradingtype = $this->options->gradingtype;
$gradingtype = $this->gradingtype;
switch ($gradingtype) {

case self::GRADING_ALL_OR_NOTHING:
Expand Down Expand Up @@ -593,7 +590,7 @@ public function update_current_response(array $response) {
* @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:
Expand Down Expand Up @@ -873,7 +870,7 @@ public static function get_numbering_styles(string $style = null): array|string
*/
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;
Expand Down Expand Up @@ -914,7 +911,7 @@ protected function get_fraction_maxscore_score_of_item(
array $correctresponse,
array $currentresponse
): array {
$gradingtype = $this->options->gradingtype;
$gradingtype = $this->gradingtype;

$score = 0;
$maxscore = null;
Expand Down Expand Up @@ -1044,7 +1041,7 @@ public function get_ordering_item_score(question_definition $question, int $posi

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] =
Expand Down
3 changes: 0 additions & 3 deletions question/type/ordering/questiontype.php
Expand Up @@ -77,9 +77,6 @@ protected function initialise_question_instance(question_definition $question, $
$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);
}

Expand Down
65 changes: 29 additions & 36 deletions question/type/ordering/renderer.php
Expand Up @@ -14,48 +14,37 @@
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.

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.
*
* @package qtype_ordering
* @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));
}
Expand All @@ -65,13 +54,13 @@ public function formulation_and_controls(question_attempt $qa, question_display_
* 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));
}
Expand All @@ -81,9 +70,10 @@ public function feedback(question_attempt $qa, question_display_options $options
*
* @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));
}
Expand All @@ -92,11 +82,10 @@ public function specific_grade_detail_feedback(question_attempt $qa): string {
* 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);
}

Expand All @@ -107,34 +96,38 @@ public function specific_feedback(question_attempt $qa) {
*
* @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 {
Expand Down
15 changes: 7 additions & 8 deletions question/type/ordering/tests/helper.php
Expand Up @@ -62,14 +62,13 @@ public function make_ordering_question_moodle(): qtype_ordering_question {
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;
}
Expand Down
4 changes: 2 additions & 2 deletions question/type/ordering/tests/output/correct_response_test.php
Expand Up @@ -50,8 +50,8 @@ public function test_export_for_template(array $currentresponse, string $layoutt

$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);
Expand Down
4 changes: 2 additions & 2 deletions question/type/ordering/tests/output/feedback_test.php
Expand Up @@ -77,7 +77,7 @@ public function test_export_for_template(array $answeritems, int $gradingtype, a
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.
Expand All @@ -86,7 +86,7 @@ public function test_export_for_template(array $answeritems, int $gradingtype, a
$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));
Expand Down
Expand Up @@ -52,7 +52,7 @@ public function test_export_for_template(array $answeritems, int $gradingtype, s
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();
Expand All @@ -66,7 +66,7 @@ public function test_export_for_template(array $answeritems, int $gradingtype, s
$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);
Expand Down
Expand Up @@ -54,7 +54,7 @@ public function test_export_for_template(array $answeritems, int $gradingtype, a
$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);
Expand Down
Expand Up @@ -53,10 +53,10 @@ public function test_export_for_template(array $answeritems, int $gradingtype, s
$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);
Expand Down

0 comments on commit 272c897

Please sign in to comment.