Merge branch 'MDL-77299-master' of https://github.com/meirzamoodle/moodle

This commit is contained in:
Andrew Nicols 2023-03-01 11:14:36 +08:00
commit 2b4c86e251
34 changed files with 184 additions and 50 deletions

View File

@ -42,6 +42,9 @@ class restore_quiz_activity_structure_step extends restore_questions_activity_st
*/
protected $legacyshufflequestionsoption = false;
/** @var stdClass */
protected $oldquizlayout;
protected function define_structure() {
$paths = [];

View File

@ -63,6 +63,14 @@ abstract class attempts_report extends report_base {
/** @var boolean caches the results of {@see should_show_grades()}. */
protected $showgrades = null;
/**
* Can be used in subclasses to cache this information, but it will only get set if you set it.
* @example an example use in quiz_overview_report.
*
* @var bool
*/
protected $hasgroupstudents;
/**
* Initialise various aspects of this report.
*

View File

@ -84,6 +84,9 @@ abstract class attempts_report_table extends \table_sql {
/** @var string The toggle group name for the checkboxes in the checkbox column. */
protected $togglegroup = 'quiz-attempts';
/** @var string strftime format. */
protected $strtimeformat;
/**
* Constructor.
*

View File

@ -41,11 +41,6 @@ require_once($CFG->dirroot . '/mod/quiz/report/overview/overview_table.php');
*/
class quiz_overview_report extends attempts_report {
/**
* @var bool whether there are actually students to show, given the options.
*/
protected $hasgroupstudents;
/**
* @var array|null cached copy of qbank_helper::get_question_structure for use during regrades.
*/
@ -113,7 +108,6 @@ class quiz_overview_report extends attempts_report {
$allowedjoins = new \core\dml\sql_join();
}
$this->course = $course; // Hack to make this available in process_actions.
$this->process_actions($quiz, $cm, $currentgroup, $groupstudentsjoins, $allowedjoins, $options->get_url());
$hasquestions = quiz_has_questions($quiz->id);
@ -301,7 +295,12 @@ class quiz_overview_report extends attempts_report {
*/
protected function start_regrade($quiz, $cm) {
require_capability('mod/quiz:regrade', $this->context);
$this->print_header_and_tabs($cm, $this->course, $quiz, $this->mode);
$this->print_header_and_tabs(
$cm,
get_course($cm->course),
$quiz,
$this->mode
);
}
/**

View File

@ -84,6 +84,30 @@ class testable_mod_quiz_external extends mod_quiz_external {
*/
class external_test extends externallib_advanced_testcase {
/** @var \stdClass course record. */
protected $course;
/** @var \stdClass activity record. */
protected $quiz;
/** @var \context_module context instance. */
protected $context;
/** @var \stdClass */
protected $cm;
/** @var \stdClass user record. */
protected $student;
/** @var \stdClass user record. */
protected $teacher;
/** @var \stdClass user role record. */
protected $studentrole;
/** @var \stdClass user role record. */
protected $teacherrole;
/**
* Set up for every test
*/

View File

@ -36,6 +36,9 @@ require_once(__DIR__ . '/quiz_question_helper_test_trait.php');
class quiz_question_version_test extends \advanced_testcase {
use \quiz_question_helper_test_trait;
/** @var \stdClass user record. */
protected $student;
/**
* Called before every test.
*/

View File

@ -88,6 +88,13 @@ This files describes API changes in the quiz code.
- The file mod/quiz/report/statistics/statistics_graph.php - deprecated since 3.2
- quiz_print_overview - deprecated since 3.3
* For properties that were previously only declared dynamically, a few classes now include property declarations to support PHP 8.2.
The affected classes are:
- restore_quiz_activity_structure_step
- attempts_report_table
- attempts_report
- quiz_overview_report (Removing $hasgroupstudents, because the parent attempts_report class has the same variable.)
=== 4.1 ===
* quiz_has_question_use is now deprecated. Use mod_quiz\structure::has_use_capability istead.

View File

@ -40,6 +40,19 @@ require_once($CFG->dirroot . '/question/classes/external.php');
*/
class column_manager_test extends advanced_testcase {
/** @var \stdClass course record. */
protected $course;
/** @var \core_question\local\bank\view */
protected $questionbank;
/** @var array */
protected $columns;
/** @var \qbank_columnsortorder\column_manager */
protected $columnmanager;
/**
* Setup testcase.
*/

View File

@ -24,6 +24,9 @@
*/
class restore_qbank_customfields_plugin extends restore_qbank_plugin {
/** @var stdClass|null a fieldset object. */
protected $cachedcategory;
/**
* Returns the paths to be handled by the plugin at question level.
*

View File

@ -32,6 +32,12 @@ use qbank_editquestion\external\update_question_version_status;
*/
class update_question_version_status_test extends \advanced_testcase {
/** @var \stdClass course record. */
protected $course;
/** @var mixed. */
protected $user;
/**
* Called before every test.
*/

View File

@ -112,11 +112,11 @@ if ($param->delete) {
// Second pass, if we still have questions to move, setup the form.
if ($questionstomove) {
$categorycontext = context::instance_by_id($category->contextid);
$qcobject->moveform = new question_move_form($thispageurl,
$moveform = new question_move_form($thispageurl,
['contexts' => [$categorycontext], 'currentcat' => $param->delete]);
if ($qcobject->moveform->is_cancelled()) {
if ($moveform->is_cancelled()) {
redirect($thispageurl);
} else if ($formdata = $qcobject->moveform->get_data()) {
} else if ($formdata = $moveform->get_data()) {
list($tocategoryid, $tocontextid) = explode(',', $formdata->category);
$qcobject->move_questions_and_delete_category($formdata->delete, $tocategoryid);
$thispageurl->remove_params('cat', 'category');
@ -171,7 +171,11 @@ if ($param->edit !== null || $qcobject->catform->is_submitted()) {
// In this case, category id is in the 'id' hidden filed.
$qcobject->edit_single_category($param->edit ?? required_param('id', PARAM_INT));
} else if ($questionstomove) {
$qcobject->display_move_form($questionstomove, $category);
$vars = new stdClass();
$vars->name = $category->name;
$vars->count = $questionstomove;
echo $OUTPUT->box(get_string('categorymove', 'question', $vars), 'generalbox boxaligncenter');
$moveform->display();
} else {
// Display the user interface.
$qcobject->display_user_interface();

View File

@ -306,8 +306,14 @@ class question_category_object {
* @param int $questionsincategory
* @param object $category
* @throws \coding_exception
*
* @deprecated No longer used by internal code and not recommended since Moodle 4.2 MDL-77299.
*/
public function display_move_form($questionsincategory, $category): void {
debugging(
'display_move_form() is deprecated and no longer used by internal code.',
DEBUG_DEVELOPER
);
global $OUTPUT;
$vars = new stdClass();
$vars->name = $category->name;

View File

@ -31,6 +31,15 @@ require_once($CFG->dirroot . '/webservice/tests/helpers.php');
*/
class submit_tags_test extends \externallib_advanced_testcase {
/** @var \stdClass course record. */
protected $course;
/** @var \stdClass user record. */
protected $student;
/** @var \stdClass user role record. */
protected $studentrole;
/**
* Set up for every test
*/

View File

@ -59,6 +59,9 @@ class category_condition extends condition {
/** @var int The maximum displayed length of the category info. */
protected $maxinfolength;
/** @var \moodle_url The URL the form is submitted to. */
protected $baseurl;
/**
* Constructor
* @param string $cat categoryID,contextID as used with question_bank_view->display()

View File

@ -35,7 +35,10 @@ class tag_condition extends condition {
/** @var string SQL fragment to add to the where clause. */
protected $where;
/** @var string SQL fragment to add to the where clause. */
/** @var array Named SQL params to be used with the SQL WHERE snippet. */
protected $params;
/** @var array List of contexts to show tags from. */
protected $contexts;
/** @var array List of IDs for tags that have been selected in the form. */

View File

@ -647,12 +647,12 @@ class question_attempt_step_subquestion_adapter extends question_attempt_step {
/**
* Constructor.
* @param question_attempt_step $realqas the step to wrap. (Can be null if you
* @param question_attempt_step $realstep the step to wrap. (Can be null if you
* just want to call add/remove.prefix.)
* @param string $extraprefix the extra prefix that is used for date fields.
*/
public function __construct($realqas, $extraprefix) {
$this->realqas = $realqas;
public function __construct($realstep, $extraprefix) {
$this->realstep = $realstep;
$this->extraprefix = $extraprefix;
}
@ -704,7 +704,7 @@ class question_attempt_step_subquestion_adapter extends question_attempt_step {
}
public function get_state() {
return $this->realqas->get_state();
return $this->realstep->get_state();
}
public function set_state($state) {
@ -712,7 +712,7 @@ class question_attempt_step_subquestion_adapter extends question_attempt_step {
}
public function get_fraction() {
return $this->realqas->get_fraction();
return $this->realstep->get_fraction();
}
public function set_fraction($fraction) {
@ -720,51 +720,51 @@ class question_attempt_step_subquestion_adapter extends question_attempt_step {
}
public function get_user_id() {
return $this->realqas->get_user_id();
return $this->realstep->get_user_id();
}
public function get_timecreated() {
return $this->realqas->get_timecreated();
return $this->realstep->get_timecreated();
}
public function has_qt_var($name) {
return $this->realqas->has_qt_var($this->add_prefix($name));
return $this->realstep->has_qt_var($this->add_prefix($name));
}
public function get_qt_var($name) {
return $this->realqas->get_qt_var($this->add_prefix($name));
return $this->realstep->get_qt_var($this->add_prefix($name));
}
public function set_qt_var($name, $value) {
$this->realqas->set_qt_var($this->add_prefix($name), $value);
$this->realstep->set_qt_var($this->add_prefix($name), $value);
}
public function get_qt_data() {
return $this->filter_array($this->realqas->get_qt_data());
return $this->filter_array($this->realstep->get_qt_data());
}
public function has_behaviour_var($name) {
return $this->realqas->has_behaviour_var($this->add_prefix($name));
return $this->realstep->has_behaviour_var($this->add_prefix($name));
}
public function get_behaviour_var($name) {
return $this->realqas->get_behaviour_var($this->add_prefix($name));
return $this->realstep->get_behaviour_var($this->add_prefix($name));
}
public function set_behaviour_var($name, $value) {
return $this->realqas->set_behaviour_var($this->add_prefix($name), $value);
return $this->realstep->set_behaviour_var($this->add_prefix($name), $value);
}
public function get_behaviour_data() {
return $this->filter_array($this->realqas->get_behaviour_data());
return $this->filter_array($this->realstep->get_behaviour_data());
}
public function get_submitted_data() {
return $this->filter_array($this->realqas->get_submitted_data());
return $this->filter_array($this->realstep->get_submitted_data());
}
public function get_all_data() {
return $this->filter_array($this->realqas->get_all_data());
return $this->filter_array($this->realstep->get_all_data());
}
public function get_qt_files($name, $contextid) {

View File

@ -52,12 +52,6 @@ class questionattempt_test extends \advanced_testcase {
$this->qa = new question_attempt($this->question, $this->usageid);
}
protected function tearDown(): void {
$this->question = null;
$this->useageid = null;
$this->qa = null;
}
public function test_constructor_sets_maxmark() {
$qa = new question_attempt($this->question, $this->usageid);
$this->assertSame($this->question, $qa->get_question(false));

View File

@ -66,6 +66,8 @@ abstract class question_behaviour_attempt_updater {
protected $qsession;
/** @var array the question states for the session to be upgraded. */
protected $qstates;
/** @var stdClass */
protected $startstate;
/**
* @var int counts the question_steps as they are converted to
@ -336,6 +338,7 @@ abstract class question_behaviour_attempt_updater {
class qbehaviour_deferredfeedback_converter extends question_behaviour_attempt_updater {
protected function behaviour_name() {
return 'deferredfeedback';
}
@ -398,6 +401,7 @@ class qbehaviour_manualgraded_converter extends question_behaviour_attempt_updat
class qbehaviour_informationitem_converter extends question_behaviour_attempt_updater {
protected function behaviour_name() {
return 'informationitem';
}

View File

@ -45,6 +45,8 @@ class question_engine_attempt_upgrader {
protected $questionloader;
/** @var question_engine_assumption_logger */
protected $logger;
/** @var stdClass */
protected $qsession;
public function save_usage($preferredbehaviour, $attempt, $qas, $quizlayout) {
global $OUTPUT;
@ -280,6 +282,9 @@ class question_engine_upgrade_question_loader {
protected $cache = array();
protected $datasetcache = array();
/** @var base_logger */
protected $logger;
public function __construct($logger) {
$this->logger = $logger;
}

View File

@ -54,6 +54,8 @@ class qformat_default {
protected $importcontext = null;
/** @var bool $displayprogress Whether to display progress. */
public $displayprogress = true;
/** @var context[] */
public $contexts;
// functions to indicate import/export functionality
// override to return true if implemented
@ -166,7 +168,7 @@ class qformat_default {
/**
* set an array of contexts.
* @param array $contexts Moodle course variable
* @param context[] $contexts
*/
public function setContexts($contexts) {
$this->contexts = $contexts;

View File

@ -57,6 +57,8 @@ class qformat_blackboard_six extends qformat_blackboard_six_base {
const FILETYPE_QTI = 1;
/** @var int Blackboard question pool files were previously handled by the blackboard plugin. */
const FILETYPE_POOL = 2;
/** @var string temporary directory/folder. */
public $temp_dir;
/**
* Return the content of a file given by its path in the tempdir directory.

View File

@ -38,6 +38,15 @@ require_once($CFG->dirroot . '/question/engine/tests/helpers.php');
*/
class externallib_test extends externallib_advanced_testcase {
/** @var \stdClass course record. */
protected $course;
/** @var \stdClass user record. */
protected $student;
/** @var \stdClass user role record. */
protected $studentrole;
/**
* Set up for every test
*/

View File

@ -311,7 +311,6 @@ class qtype_calculated_variable_substituter {
// Prepare an array for {@link substitute_values()}.
$this->search = array();
$this->replace = array();
foreach ($values as $name => $value) {
if (!is_numeric($value)) {
$a = new stdClass();

View File

@ -131,12 +131,11 @@ class qtype_calculatedmulti_edit_form extends question_edit_form {
$addfieldsname = 'updatecategory';
$addstring = get_string('updatecategory', 'qtype_calculated');
$mform->registerNoSubmitButton($addfieldsname);
$this->editasmultichoice = 1;
$mform->insertElementBefore(
$mform->createElement('submit', $addfieldsname, $addstring), 'listcategory');
$mform->registerNoSubmitButton('createoptionbutton');
$mform->addElement('hidden', 'multichoice', $this->editasmultichoice);
$mform->addElement('hidden', 'multichoice', 1);
$mform->setType('multichoice', PARAM_INT);
$menu = array(get_string('answersingleno', 'qtype_multichoice'),

View File

@ -317,7 +317,6 @@ class qtype_calculatedsimple_edit_form extends qtype_calculated_edit_form {
get_string('findwildcards', 'qtype_calculatedsimple'));
$mform->registerNoSubmitButton('analyzequestion');
$mform->closeHeaderBefore('analyzequestion');
$this->wizarddisplay = optional_param('analyzequestion', false, PARAM_BOOL);
if ($this->maxnumber != -1) {
$this->noofitems = $this->maxnumber;
} else {

View File

@ -119,6 +119,9 @@ class qtype_ddimageortext_drop_zone {
/** @var array X and Y location of the drop zone */
public $xy;
/** @var string field name to use */
public $fieldname;
/**
* Create a drop zone object.
*

View File

@ -108,7 +108,6 @@ class qtype_ddtoimage_renderer_base extends qtype_with_combined_feedback_rendere
list($fieldname, $html) = $this->hidden_field_for_qt_var($qa, $varname, null,
['placeinput', 'place' . $placeno, 'group' . $place->group]);
$output .= $html;
$question->places[$placeno]->fieldname = $fieldname;
}
$output .= html_writer::end_div();

View File

@ -280,9 +280,9 @@ class question_test extends \advanced_testcase {
// Test the case in which we're in "no inline response" mode,
// in which the response is not required (as it's not provided).
$essay->reponserequired = 0;
$essay->responserequired = 0;
$essay->responseformat = 'noinline';
$essay->attachmensrequired = 1;
$essay->attachmentsrequired = 1;
$this->assertFalse($essay->is_complete_response(
array()));
@ -294,7 +294,7 @@ class question_test extends \advanced_testcase {
array('attachments' => $attachments[1])));
// Ensure that responserequired is ignored when we're in inline response mode.
$essay->reponserequired = 1;
$essay->responserequired = 1;
$this->assertTrue($essay->is_complete_response(
array('attachments' => $attachments[1])));
}

View File

@ -191,7 +191,7 @@ class question_test extends \advanced_testcase {
$match = \test_question_maker::make_question('match');
unset($match->stems[4]);
unset($match->stemsformat[4]);
unset($match->stemformat[4]);
unset($match->right[4]);
$match->apply_attempt_state($firststep);
@ -212,7 +212,7 @@ class question_test extends \advanced_testcase {
$match = \test_question_maker::make_question('match');
$match->stems[5] = "Snake";
$match->stemsformat[5] = FORMAT_HTML;
$match->stemformat[5] = FORMAT_HTML;
$match->choices[5] = "Reptile";
$match->right[5] = 5;
$match->apply_attempt_state($firststep);

View File

@ -58,7 +58,10 @@ class qtype_multianswer_edit_form extends question_edit_form {
public $reload = false;
/** @var qtype_numerical_answer_processor used when validating numerical answers. */
protected $ap = null;
/** @var bool */
public $regenerate;
/** @var array */
public $editas;
public function __construct($submiturl, $question, $category, $contexts, $formeditable = true) {
$this->regenerate = true;

View File

@ -428,7 +428,6 @@ class qtype_multianswer_test_helper extends question_test_helper {
$mc->shuffleanswers = 0;
$mc->answernumbering = 'none';
$mc->layout = qtype_multichoice_base::LAYOUT_VERTICAL;
$mc->single = 0;
$mc->answers = array(
16 => new question_answer(16, 'Apple', 0.3333333,
@ -461,7 +460,6 @@ class qtype_multianswer_test_helper extends question_test_helper {
$mc2->shuffleanswers = 0;
$mc2->answernumbering = 'none';
$mc2->layout = qtype_multichoice_base::LAYOUT_VERTICAL;
$mc2->single = 0;
$mc2->answers = array(
22 => new question_answer(22, 'Raddish', 0.5,

View File

@ -1405,7 +1405,7 @@ class question_type {
$question = new stdClass();
$question->courseid = $courseid;
$question->qtype = $this->qtype;
$question->qtype = $this->name();
return array($form, $question);
}

View File

@ -52,6 +52,8 @@ class qtype_randomsamatch_qe2_attempt_updater extends question_qtype_attempt_upd
protected $choiceorder;
/** @var array flipped version of the choiceorder array. */
protected $flippedchoiceorder;
/** @var array of right answer for each stem. */
protected $rightanswer;
public function question_summary() {
return ''; // Done later, after we know which shortanswer questions are used.

View File

@ -5,6 +5,28 @@ This files describes API changes for code that uses the question API.
1) The question/qengine.js has been deprecated. We create core_question/question_engine
and core/scroll_manager to replace it.
2) For properties that were previously only declared dynamically, a few classes now include property declarations to support PHP 8.2.
The affected classes are:
* restore_qbank_customfields_plugin
* category_condition
* tag_condition
* question_behaviour_attempt_updater
* question_engine_attempt_upgrader
* qformat_blackboard_six
* qtype_multianswer_edit_form
* qtype_ddimageortext_drop_zone
* qtype_randomsamatch_qe2_attempt_updater
* qformat_default
Some existing code and variables must be removed while working on this issue, including:
* Removed $replace in class qtype_calculated_variable_substituter
* Removed $wizarddisplay qtype_calculatedsimple_edit_form::definition_inner()
* Removed '$question->places[$placeno]->fieldname = $fieldname' in qtype_ddtoimage_renderer_base::formulation_and_controls()
* Removed $mc->single in qtype_multianswer_test_helper::make_multianswer_question_multiple()
3) display_move_form() in qbank_managecategories\question_category_object class is deprecated and moved the logic to
the question/bank/managecategories/category.php.
=== 4.1 ===
1) get_bulk_action_key() in core_question\local\bank\bulk_action_base class is deprecated and renamed to get_key().