From 8aa5e0cf58f10dc2ccbd0810e839ef49bd60eae1 Mon Sep 17 00:00:00 2001 From: Tim Hunt Date: Thu, 2 Oct 2014 23:09:16 +0100 Subject: [PATCH 1/2] MDL-47132 quiz: move question bank extensions to classes/question/bank While doing this code clean-up, I noticed that the question bank pop-up was only showing the question name, whereas it should have been showing the question name and the start of the question text, so I fixed that. --- mod/quiz/classes/output/edit_renderer.php | 4 +- .../question/bank/add_action_column.php | 59 ++++ .../classes/question/bank/custom_view.php | 239 ++++++++++++++++ .../bank/question_name_text_column.php | 60 ++++ mod/quiz/db/renamedclasses.php | 34 +++ mod/quiz/edit.php | 2 +- mod/quiz/editlib.php | 258 ------------------ mod/quiz/questionbank.ajax.php | 2 +- mod/quiz/styles.css | 3 +- mod/quiz/upgrade.txt | 5 + 10 files changed, 403 insertions(+), 263 deletions(-) create mode 100644 mod/quiz/classes/question/bank/add_action_column.php create mode 100644 mod/quiz/classes/question/bank/custom_view.php create mode 100644 mod/quiz/classes/question/bank/question_name_text_column.php create mode 100644 mod/quiz/db/renamedclasses.php diff --git a/mod/quiz/classes/output/edit_renderer.php b/mod/quiz/classes/output/edit_renderer.php index 1d5ec6255dd..a1c2606f667 100644 --- a/mod/quiz/classes/output/edit_renderer.php +++ b/mod/quiz/classes/output/edit_renderer.php @@ -911,11 +911,11 @@ class edit_renderer extends \plugin_renderer_base { /** * Return the contents of the question bank, to be displayed in the question-bank pop-up. * - * @param \quiz_question_bank_view $questionbank the question bank view object. + * @param \mod_quiz\question\bank\custom_view $questionbank the question bank view object. * @param array $pagevars the variables from {@link \question_edit_setup()}. * @return string HTML to output / send back in response to an AJAX request. */ - public function question_bank_contents(\quiz_question_bank_view $questionbank, array $pagevars) { + public function question_bank_contents(\mod_quiz\question\bank\custom_view $questionbank, array $pagevars) { $qbank = $questionbank->render('editq', $pagevars['qpage'], $pagevars['qperpage'], $pagevars['cat'], $pagevars['recurse'], $pagevars['showhidden'], $pagevars['qbshowtext']); diff --git a/mod/quiz/classes/question/bank/add_action_column.php b/mod/quiz/classes/question/bank/add_action_column.php new file mode 100644 index 00000000000..0e1d17cdf20 --- /dev/null +++ b/mod/quiz/classes/question/bank/add_action_column.php @@ -0,0 +1,59 @@ +. + +/** + * A column type for the add this question to the quiz action. + * + * @package mod_quiz + * @category question + * @copyright 2009 Tim Hunt + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +namespace mod_quiz\question\bank; +defined('MOODLE_INTERNAL') || die(); + + +/** + * A column type for the add this question to the quiz action. + * + * @copyright 2009 Tim Hunt + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class add_action_column extends \core_question\bank\action_column_base { + /** @var string caches a lang string used repeatedly. */ + protected $stradd; + + public function init() { + parent::init(); + $this->stradd = get_string('addtoquiz', 'quiz'); + } + + public function get_name() { + return 'addtoquizaction'; + } + + protected function display_content($question, $rowclasses) { + if (!question_has_capability_on($question, 'use')) { + return; + } + $this->print_icon('t/add', $this->stradd, $this->qbank->add_to_quiz_url($question->id)); + } + + public function get_required_fields() { + return array('q.id'); + } +} diff --git a/mod/quiz/classes/question/bank/custom_view.php b/mod/quiz/classes/question/bank/custom_view.php new file mode 100644 index 00000000000..f3db9293fcd --- /dev/null +++ b/mod/quiz/classes/question/bank/custom_view.php @@ -0,0 +1,239 @@ +. + +/** + * Defines the custom question bank view used on the Edit quiz page. + * + * @package mod_quiz + * @category question + * @copyright 1999 onwards Martin Dougiamas and others {@link http://moodle.com} + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +namespace mod_quiz\question\bank; +defined('MOODLE_INTERNAL') || die(); + + +/** + * Subclass to customise the view of the question bank for the quiz editing screen. + * + * @copyright 2009 Tim Hunt + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class custom_view extends \core_question\bank\view { + /** @var bool whether the quiz this is used by has been attemptd. */ + protected $quizhasattempts = false; + /** @var \stdClass the quiz settings. */ + protected $quiz = false; + /** @var int The maximum displayed length of the category info. */ + const MAX_TEXT_LENGTH = 200; + + /** + * Constructor + * @param \question_edit_contexts $contexts + * @param \moodle_url $pageurl + * @param \stdClass $course course settings + * @param \stdClass $cm activity settings. + * @param \stdClass $quiz quiz settings. + */ + public function __construct($contexts, $pageurl, $course, $cm, $quiz) { + parent::__construct($contexts, $pageurl, $course, $cm); + $this->quiz = $quiz; + } + + protected function wanted_columns() { + global $CFG; + + if (empty($CFG->quizquestionbankcolumns)) { + $quizquestionbankcolumns = array( + 'add_action_column', + 'checkbox_column', + 'question_type_column', + 'question_name_text_column', + 'preview_action_column', + ); + } else { + $quizquestionbankcolumns = explode(',', $CFG->quizquestionbankcolumns); + } + + foreach ($quizquestionbankcolumns as $fullname) { + if (!class_exists($fullname)) { + if (class_exists('mod_quiz\\question\\bank\\' . $fullname)) { + $fullname = 'mod_quiz\\question\\bank\\' . $fullname; + } else if (class_exists('core_question\\bank\\' . $fullname)) { + $fullname = 'core_question\\bank\\' . $fullname; + } else if (class_exists('question_bank_' . $fullname)) { + debugging('Legacy question bank column class question_bank_' . + $fullname . ' should be renamed to mod_quiz\\question\\bank\\' . + $fullname, DEBUG_DEVELOPER); + $fullname = 'question_bank_' . $fullname; + } else { + throw new coding_exception("No such class exists: $fullname"); + } + } + $this->requiredcolumns[$fullname] = new $fullname($this); + } + return $this->requiredcolumns; + } + + /** + * Specify the column heading + * + * @return string Column name for the heading + */ + protected function heading_column() { + return 'mod_quiz\\question\\bank\\question_name_text_column'; + } + + protected function default_sort() { + return array( + 'core_question\\bank\\question_type_column' => 1, + 'mod_quiz\\question\\bank\\question_name_text_column' => 1, + ); + } + + /** + * Let the question bank display know whether the quiz has been attempted, + * hence whether some bits of UI, like the add this question to the quiz icon, + * should be displayed. + * @param bool $quizhasattempts whether the quiz has attempts. + */ + public function set_quiz_has_attempts($quizhasattempts) { + $this->quizhasattempts = $quizhasattempts; + if ($quizhasattempts && isset($this->visiblecolumns['addtoquizaction'])) { + unset($this->visiblecolumns['addtoquizaction']); + } + } + + public function preview_question_url($question) { + return quiz_question_preview_url($this->quiz, $question); + } + + public function add_to_quiz_url($questionid) { + global $CFG; + $params = $this->baseurl->params(); + $params['addquestion'] = $questionid; + $params['sesskey'] = sesskey(); + return new \moodle_url('/mod/quiz/edit.php', $params); + } + + /** + * Renders the html question bank (same as display, but returns the result). + * + * Note that you can only output this rendered result once per page, as + * it contains IDs which must be unique. + * + * @return string HTML code for the form + */ + public function render($tabname, $page, $perpage, $cat, $recurse, $showhidden, $showquestiontext) { + ob_start(); + $this->display($tabname, $page, $perpage, $cat, $recurse, $showhidden, $showquestiontext); + $out = ob_get_contents(); + ob_end_clean(); + return $out; + } + + /** + * Display the controls at the bottom of the list of questions. + * @param int $totalnumber Total number of questions that might be shown (if it was not for paging). + * @param bool $recurse Whether to include subcategories. + * @param \stdClass $category The question_category row from the database. + * @param \context $catcontext The context of the category being displayed. + * @param array $addcontexts contexts where the user is allowed to add new questions. + */ + protected function display_bottom_controls($totalnumber, $recurse, $category, \context $catcontext, array $addcontexts) { + $cmoptions = new \stdClass(); + $cmoptions->hasattempts = !empty($this->quizhasattempts); + + $canuseall = has_capability('moodle/question:useall', $catcontext); + + echo '
'; + if ($canuseall) { + + // Add selected questions to the quiz. + $params = array( + 'type' => 'submit', + 'name' => 'add', + 'value' => get_string('addselectedquestionstoquiz', 'quiz'), + ); + if ($cmoptions->hasattempts) { + $params['disabled'] = 'disabled'; + } + echo \html_writer::empty_tag('input', $params); + } + echo "
\n"; + } + + /** + * Prints a form to choose categories. + * @param string $categoryandcontext 'categoryID,contextID'. + * @deprecated since Moodle 2.6 MDL-40313. + * @see \core_question\bank\search\category_condition + * @todo MDL-41978 This will be deleted in Moodle 2.8 + */ + protected function print_choose_category_message($categoryandcontext) { + global $OUTPUT; + debugging('print_choose_category_message() is deprecated, ' . + 'please use \core_question\bank\search\category_condition instead.', DEBUG_DEVELOPER); + echo $OUTPUT->box_start('generalbox questionbank'); + $this->display_category_form($this->contexts->having_one_edit_tab_cap('edit'), + $this->baseurl, $categoryandcontext); + echo "

"; + print_string('selectcategoryabove', 'question'); + echo "

"; + echo $OUTPUT->box_end(); + } + + protected function display_options_form($showquestiontext, $scriptpath = '/mod/quiz/edit.php', + $showtextoption = false) { + // Overridden just to change the default values of the arguments. + parent::display_options_form($showquestiontext, $scriptpath, $showtextoption); + } + + protected function print_category_info($category) { + $formatoptions = new stdClass(); + $formatoptions->noclean = true; + $strcategory = get_string('category', 'quiz'); + echo '
' . + $strcategory; + echo ': '; + echo shorten_text(strip_tags(format_string($category->name)), 60); + echo '
' . + ''; + echo shorten_text(strip_tags(format_text($category->info, $category->infoformat, + $formatoptions, $this->course->id)), 200); + echo '
'; + } + + protected function display_options($recurse, $showhidden, $showquestiontext) { + debugging('display_options() is deprecated, see display_options_form() instead.', DEBUG_DEVELOPER); + echo '
'; + echo "
"; + echo \html_writer::input_hidden_params($this->baseurl, + array('recurse', 'showhidden', 'qbshowtext')); + $this->display_category_form_checkbox('recurse', $recurse, + get_string('includesubcategories', 'question')); + $this->display_category_form_checkbox('showhidden', $showhidden, + get_string('showhidden', 'question')); + echo '
'; + } + + protected function create_new_question_form($category, $canadd) { + // Don't display this. + } +} diff --git a/mod/quiz/classes/question/bank/question_name_text_column.php b/mod/quiz/classes/question/bank/question_name_text_column.php new file mode 100644 index 00000000000..fa15f54097d --- /dev/null +++ b/mod/quiz/classes/question/bank/question_name_text_column.php @@ -0,0 +1,60 @@ +. + +/** + * A column type for the name followed by the start of the question text. + * + * @package mod_quiz + * @category question + * @copyright 1999 onwards Martin Dougiamas and others {@link http://moodle.com} + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +namespace mod_quiz\question\bank; +defined('MOODLE_INTERNAL') || die(); + + +/** + * A column type for the name followed by the start of the question text. + * + * @copyright 2009 Tim Hunt + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class question_name_text_column extends \core_question\bank\question_name_column { + public function get_name() { + return 'questionnametext'; + } + + protected function display_content($question, $rowclasses) { + echo '
'; + $labelfor = $this->label_for($question); + if ($labelfor) { + echo ''; + } + echo '
'; + } + + public function get_required_fields() { + $fields = parent::get_required_fields(); + $fields[] = 'q.questiontext'; + $fields[] = 'q.questiontextformat'; + return $fields; + } +} diff --git a/mod/quiz/db/renamedclasses.php b/mod/quiz/db/renamedclasses.php new file mode 100644 index 00000000000..3cc07a1c1ff --- /dev/null +++ b/mod/quiz/db/renamedclasses.php @@ -0,0 +1,34 @@ +. + +/** + * Lists renamed classes so that the autoloader can make the old names still work. + * + * @package mod_quiz + * @copyright 2014 Tim Hunt + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +defined('MOODLE_INTERNAL') || die(); + +// Array 'old_class_name' => 'new\class_name'. +$renamedclasses = array( + + // Changed in Moodle 2.8. + 'quiz_question_bank_view' => 'mod_quiz\question\bank\custom_view', + 'question_bank_add_to_quiz_action_column' => 'mod_quiz\question\bank\add_action_column', + 'question_bank_question_name_text_column' => 'mod_quiz\question\bank\question_name_text_column', +); diff --git a/mod/quiz/edit.php b/mod/quiz/edit.php index 8b5726850ce..1c0e763ca45 100644 --- a/mod/quiz/edit.php +++ b/mod/quiz/edit.php @@ -281,7 +281,7 @@ if (optional_param('savechanges', false, PARAM_BOOL) && confirm_sesskey()) { } // Get the question bank view. -$questionbank = new quiz_question_bank_view($contexts, $thispageurl, $course, $cm, $quiz); +$questionbank = new mod_quiz\question\bank\custom_view($contexts, $thispageurl, $course, $cm, $quiz); $questionbank->set_quiz_has_attempts($quizhasattempts); $questionbank->process_actions($thispageurl, $cm); diff --git a/mod/quiz/editlib.php b/mod/quiz/editlib.php index 871dc174d24..0652481778d 100644 --- a/mod/quiz/editlib.php +++ b/mod/quiz/editlib.php @@ -200,261 +200,3 @@ function quiz_add_random_questions($quiz, $addonpage, $categoryid, $number, quiz_add_quiz_question($question->id, $quiz, $addonpage); } } - - -/** - * A column type for the add this question to the quiz. - * - * @copyright 2009 Tim Hunt - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ -class question_bank_add_to_quiz_action_column extends question_bank_action_column_base { - protected $stradd; - - public function init() { - parent::init(); - $this->stradd = get_string('addtoquiz', 'quiz'); - } - - public function get_name() { - return 'addtoquizaction'; - } - - protected function display_content($question, $rowclasses) { - if (!question_has_capability_on($question, 'use')) { - return; - } - $this->print_icon('t/add', $this->stradd, $this->qbank->add_to_quiz_url($question->id)); - } - - public function get_required_fields() { - return array('q.id'); - } -} - -/** - * A column type for the name followed by the start of the question text. - * - * @copyright 2009 Tim Hunt - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ -class question_bank_question_name_text_column extends question_bank_question_name_column { - public function get_name() { - return 'questionnametext'; - } - - protected function display_content($question, $rowclasses) { - echo '
'; - $labelfor = $this->label_for($question); - if ($labelfor) { - echo ''; - } - echo '
'; - } - - public function get_required_fields() { - $fields = parent::get_required_fields(); - $fields[] = 'q.questiontext'; - $fields[] = 'q.questiontextformat'; - return $fields; - } -} - -/** - * Subclass to customise the view of the question bank for the quiz editing screen. - * - * @copyright 2009 Tim Hunt - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ -class quiz_question_bank_view extends core_question\bank\view { - protected $quizhasattempts = false; - /** @var object the quiz settings. */ - protected $quiz = false; - /** @var int The maximum displayed length of the category info. */ - const MAX_TEXT_LENGTH = 200; - - /** - * Constructor - * @param question_edit_contexts $contexts - * @param moodle_url $pageurl - * @param object $course course settings - * @param object $cm activity settings. - * @param object $quiz quiz settings. - */ - public function __construct($contexts, $pageurl, $course, $cm, $quiz) { - parent::__construct($contexts, $pageurl, $course, $cm); - $this->quiz = $quiz; - } - - protected function wanted_columns() { - global $CFG; - - if (empty($CFG->quizquestionbankcolumns)) { - $quizquestionbankcolumns = array('add_to_quiz_action_column', 'checkbox_column', 'question_type_column', - 'question_name_column', 'preview_action_column'); - } else { - $quizquestionbankcolumns = explode(',', $CFG->quizquestionbankcolumns); - } - - foreach ($quizquestionbankcolumns as $fullname) { - if (! class_exists($fullname)) { - if (class_exists('question_bank_' . $fullname)) { - $fullname = 'question_bank_' . $fullname; - } else { - throw new coding_exception("No such class exists: $fullname"); - } - } - $this->requiredcolumns[$fullname] = new $fullname($this); - } - return $this->requiredcolumns; - } - - /** - * Specify the column heading - * - * @return string Column name for the heading - */ - protected function heading_column() { - return 'questionnametext'; - } - - protected function default_sort() { - return array('question_bank_question_type_column' => 1, 'question_bank_question_name_column' => 1); - } - - /** - * Let the question bank display know whether the quiz has been attempted, - * hence whether some bits of UI, like the add this question to the quiz icon, - * should be displayed. - * @param bool $quizhasattempts whether the quiz has attempts. - */ - public function set_quiz_has_attempts($quizhasattempts) { - $this->quizhasattempts = $quizhasattempts; - if ($quizhasattempts && isset($this->visiblecolumns['addtoquizaction'])) { - unset($this->visiblecolumns['addtoquizaction']); - } - } - - public function preview_question_url($question) { - return quiz_question_preview_url($this->quiz, $question); - } - - public function add_to_quiz_url($questionid) { - global $CFG; - $params = $this->baseurl->params(); - $params['addquestion'] = $questionid; - $params['sesskey'] = sesskey(); - return new moodle_url('/mod/quiz/edit.php', $params); - } - - /** - * Renders the html question bank (same as display, but returns the result). - * - * Note that you can only output this rendered result once per page, as - * it contains IDs which must be unique. - * - * @return string HTML code for the form - */ - public function render($tabname, $page, $perpage, $cat, $recurse, $showhidden, $showquestiontext) { - ob_start(); - $this->display($tabname, $page, $perpage, $cat, $recurse, $showhidden, $showquestiontext); - $out = ob_get_contents(); - ob_end_clean(); - return $out; - } - - /** - * Display the controls at the bottom of the list of questions. - * @param int $totalnumber Total number of questions that might be shown (if it was not for paging). - * @param bool $recurse Whether to include subcategories. - * @param stdClass $category The question_category row from the database. - * @param context $catcontext The context of the category being displayed. - * @param array $addcontexts contexts where the user is allowed to add new questions. - */ - protected function display_bottom_controls($totalnumber, $recurse, $category, \context $catcontext, array $addcontexts) { - $cmoptions = new \stdClass(); - $cmoptions->hasattempts = !empty($this->quizhasattempts); - - $canuseall = has_capability('moodle/question:useall', $catcontext); - - echo '
'; - if ($canuseall) { - - // Add selected questions to the quiz. - $params = array( - 'type' => 'submit', - 'name' => 'add', - 'value' => get_string('addselectedquestionstoquiz', 'quiz'), - ); - if ($cmoptions->hasattempts) { - $params['disabled'] = 'disabled'; - } - echo html_writer::empty_tag('input', $params); - } - echo "
\n"; - } - - /** - * prints a form to choose categories - * @param string $categoryandcontext 'categoryID,contextID'. - * @deprecated since Moodle 2.6 MDL-40313. - * @see \core_question\bank\search\category_condition - * @todo MDL-41978 This will be deleted in Moodle 2.8 - */ - protected function print_choose_category_message($categoryandcontext) { - global $OUTPUT; - debugging('print_choose_category_message() is deprecated, ' . - 'please use \core_question\bank\search\category_condition instead.', DEBUG_DEVELOPER); - echo $OUTPUT->box_start('generalbox questionbank'); - $this->display_category_form($this->contexts->having_one_edit_tab_cap('edit'), - $this->baseurl, $categoryandcontext); - echo "

"; - print_string('selectcategoryabove', 'question'); - echo "

"; - echo $OUTPUT->box_end(); - } - - protected function display_options_form($showquestiontext, $scriptpath = '/mod/quiz/edit.php', - $showtextoption = false) { - // Overridden just to change the default values of the arguments. - parent::display_options_form($showquestiontext, $scriptpath, $showtextoption); - } - - protected function print_category_info($category) { - $formatoptions = new stdClass(); - $formatoptions->noclean = true; - $strcategory = get_string('category', 'quiz'); - echo '
' . - $strcategory; - echo ': '; - echo shorten_text(strip_tags(format_string($category->name)), 60); - echo '
' . - ''; - echo shorten_text(strip_tags(format_text($category->info, $category->infoformat, - $formatoptions, $this->course->id)), 200); - echo '
'; - } - - protected function display_options($recurse, $showhidden, $showquestiontext) { - debugging('display_options() is deprecated, see display_options_form() instead.', DEBUG_DEVELOPER); - echo '
'; - echo "
"; - echo html_writer::input_hidden_params($this->baseurl, - array('recurse', 'showhidden', 'qbshowtext')); - $this->display_category_form_checkbox('recurse', $recurse, - get_string('includesubcategories', 'question')); - $this->display_category_form_checkbox('showhidden', $showhidden, - get_string('showhidden', 'question')); - echo '
'; - } - - protected function create_new_question_form($category, $canadd) { - // Don't display this. - } -} diff --git a/mod/quiz/questionbank.ajax.php b/mod/quiz/questionbank.ajax.php index 405593816c1..747ca0541df 100644 --- a/mod/quiz/questionbank.ajax.php +++ b/mod/quiz/questionbank.ajax.php @@ -37,7 +37,7 @@ $course = $DB->get_record('course', array('id' => $quiz->course), '*', MUST_EXIS require_capability('mod/quiz:manage', $contexts->lowest()); // Create quiz question bank view. -$questionbank = new quiz_question_bank_view($contexts, $thispageurl, $course, $cm, $quiz); +$questionbank = new mod_quiz\question\bank\custom_view($contexts, $thispageurl, $course, $cm, $quiz); $questionbank->set_quiz_has_attempts(quiz_has_attempts($quiz->id)); // Output. diff --git a/mod/quiz/styles.css b/mod/quiz/styles.css index 92e752fb2ce..d8af1d262ba 100644 --- a/mod/quiz/styles.css +++ b/mod/quiz/styles.css @@ -705,8 +705,9 @@ table.quizreviewsummary td.cell { #page-mod-quiz-edit ul.slots .activityinstance span.instancename img { margin-right: .2em; } +#page-mod-quiz-edit #categoryquestions .questionname, #page-mod-quiz-edit ul.slots li.activity div.activityinstance .questionname { - font-weight: bold; + font-weight: bold; color: #555; } #page-mod-quiz-edit ul.slots li.activity div.activityinstance .questiontext { diff --git a/mod/quiz/upgrade.txt b/mod/quiz/upgrade.txt index 911e92ca610..797cd4aaafe 100644 --- a/mod/quiz/upgrade.txt +++ b/mod/quiz/upgrade.txt @@ -2,6 +2,11 @@ This files describes API changes in the quiz code. === 2.8 === +* Classes that where defined in various lib files have been moved to the classes + folder to take advantage of auto-loading. This has involved renaming them. + see the list in mod/quiz/db/renamedclasses.php. + + * Major changes to the Edit quiz page. The goal of this work was to increase usability, and also clean up the page From 16fa272e29cb205de97b2c620afd637b8c45ef24 Mon Sep 17 00:00:00 2001 From: Tim Hunt Date: Thu, 2 Oct 2014 23:15:59 +0100 Subject: [PATCH 2/2] MDL-47132 quiz: move the remains of editlib.php to locallib.php --- mod/quiz/addrandom.php | 5 +- mod/quiz/edit.php | 5 +- mod/quiz/edit_rest.php | 3 +- mod/quiz/editlib.php | 202 ------------------ mod/quiz/locallib.php | 171 ++++++++++++++- mod/quiz/questionbank.ajax.php | 6 +- .../attempt_walkthrough_from_csv_test.php | 1 - mod/quiz/tests/attempt_walkthrough_test.php | 1 - mod/quiz/tests/events_test.php | 1 - mod/quiz/tests/lib_test.php | 3 - mod/quiz/tests/repaginate_test.php | 1 - mod/quiz/tests/structure_test.php | 1 - mod/quiz/upgrade.txt | 4 +- 13 files changed, 182 insertions(+), 222 deletions(-) delete mode 100644 mod/quiz/editlib.php diff --git a/mod/quiz/addrandom.php b/mod/quiz/addrandom.php index 3f808968073..658ecb86cf2 100644 --- a/mod/quiz/addrandom.php +++ b/mod/quiz/addrandom.php @@ -24,9 +24,10 @@ */ -require_once('../../config.php'); -require_once($CFG->dirroot . '/mod/quiz/editlib.php'); +require_once(__DIR__ . '/../../config.php'); +require_once($CFG->dirroot . '/mod/quiz/locallib.php'); require_once($CFG->dirroot . '/mod/quiz/addrandomform.php'); +require_once($CFG->dirroot . '/question/editlib.php'); require_once($CFG->dirroot . '/question/category_class.php'); list($thispageurl, $contexts, $cmid, $cm, $quiz, $pagevars) = diff --git a/mod/quiz/edit.php b/mod/quiz/edit.php index 1c0e763ca45..d7998e57fb9 100644 --- a/mod/quiz/edit.php +++ b/mod/quiz/edit.php @@ -41,9 +41,10 @@ */ -require_once('../../config.php'); -require_once($CFG->dirroot . '/mod/quiz/editlib.php'); +require_once(__DIR__ . '/../../config.php'); +require_once($CFG->dirroot . '/mod/quiz/locallib.php'); require_once($CFG->dirroot . '/mod/quiz/addrandomform.php'); +require_once($CFG->dirroot . '/question/editlib.php'); require_once($CFG->dirroot . '/question/category_class.php'); // These params are only passed from page request to request while we stay on diff --git a/mod/quiz/edit_rest.php b/mod/quiz/edit_rest.php index 8d5e933ecaf..55b09fa74f3 100644 --- a/mod/quiz/edit_rest.php +++ b/mod/quiz/edit_rest.php @@ -27,8 +27,7 @@ if (!defined('AJAX_SCRIPT')) { } require_once(__DIR__ . '/../../config.php'); -require_once($CFG->dirroot . '/course/lib.php'); -require_once($CFG->dirroot . '/mod/quiz/editlib.php'); +require_once($CFG->dirroot . '/mod/quiz/locallib.php'); // Initialise ALL the incoming parameters here, up front. $quizid = required_param('quizid', PARAM_INT); diff --git a/mod/quiz/editlib.php b/mod/quiz/editlib.php deleted file mode 100644 index 0652481778d..00000000000 --- a/mod/quiz/editlib.php +++ /dev/null @@ -1,202 +0,0 @@ -. - - -/** - * This contains functions that are called from within the quiz module only - * Functions that are also called by core Moodle are in {@link lib.php} - * This script also loads the code in {@link questionlib.php} which holds - * the module-indpendent code for handling questions and which in turn - * initialises all the questiontype classes. - * - * @package mod_quiz - * @copyright 1999 onwards Martin Dougiamas and others {@link http://moodle.com} - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - - -defined('MOODLE_INTERNAL') || die(); - -require_once($CFG->dirroot . '/mod/quiz/locallib.php'); - -/** - * Verify that the question exists, and the user has permission to use it. - * Does not return. Throws an exception if the question cannot be used. - * @param int $questionid The id of the question. - */ -function quiz_require_question_use($questionid) { - global $DB; - $question = $DB->get_record('question', array('id' => $questionid), '*', MUST_EXIST); - question_require_capability_on($question, 'use'); -} - -/** - * Verify that the question exists, and the user has permission to use it. - * @param object $quiz the quiz settings. - * @param int $slot which question in the quiz to test. - * @return bool whether the user can use this question. - */ -function quiz_has_question_use($quiz, $slot) { - global $DB; - $question = $DB->get_record_sql(" - SELECT q.* - FROM {quiz_slots} slot - JOIN {question} q ON q.id = slot.questionid - WHERE slot.quizid = ? AND slot.slot = ?", array($quiz->id, $slot)); - if (!$question) { - return false; - } - return question_has_capability_on($question, 'use'); -} - -/** - * Add a question to a quiz - * - * Adds a question to a quiz by updating $quiz as well as the - * quiz and quiz_slots tables. It also adds a page break if required. - * @param int $questionid The id of the question to be added - * @param object $quiz The extended quiz object as used by edit.php - * This is updated by this function - * @param int $page Which page in quiz to add the question on. If 0 (default), - * add at the end - * @param float $maxmark The maximum mark to set for this question. (Optional, - * defaults to question.defaultmark. - * @return bool false if the question was already in the quiz - */ -function quiz_add_quiz_question($questionid, $quiz, $page = 0, $maxmark = null) { - global $DB; - $slots = $DB->get_records('quiz_slots', array('quizid' => $quiz->id), - 'slot', 'questionid, slot, page, id'); - if (array_key_exists($questionid, $slots)) { - return false; - } - - $trans = $DB->start_delegated_transaction(); - - $maxpage = 1; - $numonlastpage = 0; - foreach ($slots as $slot) { - if ($slot->page > $maxpage) { - $maxpage = $slot->page; - $numonlastpage = 1; - } else { - $numonlastpage += 1; - } - } - - // Add the new question instance. - $slot = new stdClass(); - $slot->quizid = $quiz->id; - $slot->questionid = $questionid; - - if ($maxmark !== null) { - $slot->maxmark = $maxmark; - } else { - $slot->maxmark = $DB->get_field('question', 'defaultmark', array('id' => $questionid)); - } - - if (is_int($page) && $page >= 1) { - // Adding on a given page. - $lastslotbefore = 0; - foreach (array_reverse($slots) as $otherslot) { - if ($otherslot->page > $page) { - $DB->set_field('quiz_slots', 'slot', $otherslot->slot + 1, array('id' => $otherslot->id)); - } else { - $lastslotbefore = $otherslot->slot; - break; - } - } - $slot->slot = $lastslotbefore + 1; - $slot->page = min($page, $maxpage + 1); - - } else { - $lastslot = end($slots); - if ($lastslot) { - $slot->slot = $lastslot->slot + 1; - } else { - $slot->slot = 1; - } - if ($quiz->questionsperpage && $numonlastpage >= $quiz->questionsperpage) { - $slot->page = $maxpage + 1; - } else { - $slot->page = $maxpage; - } - } - - $DB->insert_record('quiz_slots', $slot); - $trans->allow_commit(); -} - -/** - * Add a random question to the quiz at a given point. - * @param object $quiz the quiz settings. - * @param int $addonpage the page on which to add the question. - * @param int $categoryid the question category to add the question from. - * @param int $number the number of random questions to add. - * @param bool $includesubcategories whether to include questoins from subcategories. - */ -function quiz_add_random_questions($quiz, $addonpage, $categoryid, $number, - $includesubcategories) { - global $DB; - - $category = $DB->get_record('question_categories', array('id' => $categoryid)); - if (!$category) { - print_error('invalidcategoryid', 'error'); - } - - $catcontext = context::instance_by_id($category->contextid); - require_capability('moodle/question:useall', $catcontext); - - // Find existing random questions in this category that are - // not used by any quiz. - if ($existingquestions = $DB->get_records_sql( - "SELECT q.id, q.qtype FROM {question} q - WHERE qtype = 'random' - AND category = ? - AND " . $DB->sql_compare_text('questiontext') . " = ? - AND NOT EXISTS ( - SELECT * - FROM {quiz_slots} - WHERE questionid = q.id) - ORDER BY id", array($category->id, ($includesubcategories ? '1' : '0')))) { - // Take as many of these as needed. - while (($existingquestion = array_shift($existingquestions)) && $number > 0) { - quiz_add_quiz_question($existingquestion->id, $quiz, $addonpage); - $number -= 1; - } - } - - if ($number <= 0) { - return; - } - - // More random questions are needed, create them. - for ($i = 0; $i < $number; $i += 1) { - $form = new stdClass(); - $form->questiontext = array('text' => ($includesubcategories ? '1' : '0'), 'format' => 0); - $form->category = $category->id . ',' . $category->contextid; - $form->defaultmark = 1; - $form->hidden = 1; - $form->stamp = make_unique_id_code(); // Set the unique code (not to be changed). - $question = new stdClass(); - $question->qtype = 'random'; - $question = question_bank::get_qtype('random')->save_question($question, $form); - if (!isset($question->id)) { - print_error('cannotinsertrandomquestion', 'quiz'); - } - quiz_add_quiz_question($question->id, $quiz, $addonpage); - } -} diff --git a/mod/quiz/locallib.php b/mod/quiz/locallib.php index 993574ab1e0..6e8ac7b4e1e 100644 --- a/mod/quiz/locallib.php +++ b/mod/quiz/locallib.php @@ -36,9 +36,9 @@ require_once($CFG->dirroot . '/mod/quiz/accessmanager.php'); require_once($CFG->dirroot . '/mod/quiz/accessmanager_form.php'); require_once($CFG->dirroot . '/mod/quiz/renderer.php'); require_once($CFG->dirroot . '/mod/quiz/attemptlib.php'); -require_once($CFG->dirroot . '/question/editlib.php'); require_once($CFG->libdir . '/eventslib.php'); require_once($CFG->libdir . '/filelib.php'); +require_once($CFG->libdir . '/questionlib.php'); /** @@ -1905,3 +1905,172 @@ function quiz_question_tostring($question, $showicon = false, $showquestiontext return $result; } + +/** + * Verify that the question exists, and the user has permission to use it. + * Does not return. Throws an exception if the question cannot be used. + * @param int $questionid The id of the question. + */ +function quiz_require_question_use($questionid) { + global $DB; + $question = $DB->get_record('question', array('id' => $questionid), '*', MUST_EXIST); + question_require_capability_on($question, 'use'); +} + +/** + * Verify that the question exists, and the user has permission to use it. + * @param object $quiz the quiz settings. + * @param int $slot which question in the quiz to test. + * @return bool whether the user can use this question. + */ +function quiz_has_question_use($quiz, $slot) { + global $DB; + $question = $DB->get_record_sql(" + SELECT q.* + FROM {quiz_slots} slot + JOIN {question} q ON q.id = slot.questionid + WHERE slot.quizid = ? AND slot.slot = ?", array($quiz->id, $slot)); + if (!$question) { + return false; + } + return question_has_capability_on($question, 'use'); +} + +/** + * Add a question to a quiz + * + * Adds a question to a quiz by updating $quiz as well as the + * quiz and quiz_slots tables. It also adds a page break if required. + * @param int $questionid The id of the question to be added + * @param object $quiz The extended quiz object as used by edit.php + * This is updated by this function + * @param int $page Which page in quiz to add the question on. If 0 (default), + * add at the end + * @param float $maxmark The maximum mark to set for this question. (Optional, + * defaults to question.defaultmark. + * @return bool false if the question was already in the quiz + */ +function quiz_add_quiz_question($questionid, $quiz, $page = 0, $maxmark = null) { + global $DB; + $slots = $DB->get_records('quiz_slots', array('quizid' => $quiz->id), + 'slot', 'questionid, slot, page, id'); + if (array_key_exists($questionid, $slots)) { + return false; + } + + $trans = $DB->start_delegated_transaction(); + + $maxpage = 1; + $numonlastpage = 0; + foreach ($slots as $slot) { + if ($slot->page > $maxpage) { + $maxpage = $slot->page; + $numonlastpage = 1; + } else { + $numonlastpage += 1; + } + } + + // Add the new question instance. + $slot = new stdClass(); + $slot->quizid = $quiz->id; + $slot->questionid = $questionid; + + if ($maxmark !== null) { + $slot->maxmark = $maxmark; + } else { + $slot->maxmark = $DB->get_field('question', 'defaultmark', array('id' => $questionid)); + } + + if (is_int($page) && $page >= 1) { + // Adding on a given page. + $lastslotbefore = 0; + foreach (array_reverse($slots) as $otherslot) { + if ($otherslot->page > $page) { + $DB->set_field('quiz_slots', 'slot', $otherslot->slot + 1, array('id' => $otherslot->id)); + } else { + $lastslotbefore = $otherslot->slot; + break; + } + } + $slot->slot = $lastslotbefore + 1; + $slot->page = min($page, $maxpage + 1); + + } else { + $lastslot = end($slots); + if ($lastslot) { + $slot->slot = $lastslot->slot + 1; + } else { + $slot->slot = 1; + } + if ($quiz->questionsperpage && $numonlastpage >= $quiz->questionsperpage) { + $slot->page = $maxpage + 1; + } else { + $slot->page = $maxpage; + } + } + + $DB->insert_record('quiz_slots', $slot); + $trans->allow_commit(); +} + +/** + * Add a random question to the quiz at a given point. + * @param object $quiz the quiz settings. + * @param int $addonpage the page on which to add the question. + * @param int $categoryid the question category to add the question from. + * @param int $number the number of random questions to add. + * @param bool $includesubcategories whether to include questoins from subcategories. + */ +function quiz_add_random_questions($quiz, $addonpage, $categoryid, $number, + $includesubcategories) { + global $DB; + + $category = $DB->get_record('question_categories', array('id' => $categoryid)); + if (!$category) { + print_error('invalidcategoryid', 'error'); + } + + $catcontext = context::instance_by_id($category->contextid); + require_capability('moodle/question:useall', $catcontext); + + // Find existing random questions in this category that are + // not used by any quiz. + if ($existingquestions = $DB->get_records_sql( + "SELECT q.id, q.qtype FROM {question} q + WHERE qtype = 'random' + AND category = ? + AND " . $DB->sql_compare_text('questiontext') . " = ? + AND NOT EXISTS ( + SELECT * + FROM {quiz_slots} + WHERE questionid = q.id) + ORDER BY id", array($category->id, ($includesubcategories ? '1' : '0')))) { + // Take as many of these as needed. + while (($existingquestion = array_shift($existingquestions)) && $number > 0) { + quiz_add_quiz_question($existingquestion->id, $quiz, $addonpage); + $number -= 1; + } + } + + if ($number <= 0) { + return; + } + + // More random questions are needed, create them. + for ($i = 0; $i < $number; $i += 1) { + $form = new stdClass(); + $form->questiontext = array('text' => ($includesubcategories ? '1' : '0'), 'format' => 0); + $form->category = $category->id . ',' . $category->contextid; + $form->defaultmark = 1; + $form->hidden = 1; + $form->stamp = make_unique_id_code(); // Set the unique code (not to be changed). + $question = new stdClass(); + $question->qtype = 'random'; + $question = question_bank::get_qtype('random')->save_question($question, $form); + if (!isset($question->id)) { + print_error('cannotinsertrandomquestion', 'quiz'); + } + quiz_add_quiz_question($question->id, $quiz, $addonpage); + } +} diff --git a/mod/quiz/questionbank.ajax.php b/mod/quiz/questionbank.ajax.php index 747ca0541df..2f5018a650f 100644 --- a/mod/quiz/questionbank.ajax.php +++ b/mod/quiz/questionbank.ajax.php @@ -25,9 +25,9 @@ define('AJAX_SCRIPT', true); - -require_once('../../config.php'); -require_once($CFG->dirroot . '/mod/quiz/editlib.php'); +require_once(__DIR__ . '/../../config.php'); +require_once($CFG->dirroot . '/mod/quiz/locallib.php'); +require_once($CFG->dirroot . '/question/editlib.php'); list($thispageurl, $contexts, $cmid, $cm, $quiz, $pagevars) = question_edit_setup('editq', '/mod/quiz/edit.php', true); diff --git a/mod/quiz/tests/attempt_walkthrough_from_csv_test.php b/mod/quiz/tests/attempt_walkthrough_from_csv_test.php index 3f96fd90cba..25387dbcec8 100644 --- a/mod/quiz/tests/attempt_walkthrough_from_csv_test.php +++ b/mod/quiz/tests/attempt_walkthrough_from_csv_test.php @@ -27,7 +27,6 @@ defined('MOODLE_INTERNAL') || die(); global $CFG; -require_once($CFG->dirroot . '/mod/quiz/editlib.php'); require_once($CFG->dirroot . '/mod/quiz/locallib.php'); /** diff --git a/mod/quiz/tests/attempt_walkthrough_test.php b/mod/quiz/tests/attempt_walkthrough_test.php index 2c0fabbc8dd..282e453ded7 100644 --- a/mod/quiz/tests/attempt_walkthrough_test.php +++ b/mod/quiz/tests/attempt_walkthrough_test.php @@ -27,7 +27,6 @@ defined('MOODLE_INTERNAL') || die(); global $CFG; -require_once($CFG->dirroot . '/mod/quiz/editlib.php'); require_once($CFG->dirroot . '/mod/quiz/locallib.php'); /** diff --git a/mod/quiz/tests/events_test.php b/mod/quiz/tests/events_test.php index 4ea32eca833..2f92237dac9 100644 --- a/mod/quiz/tests/events_test.php +++ b/mod/quiz/tests/events_test.php @@ -27,7 +27,6 @@ defined('MOODLE_INTERNAL') || die(); global $CFG; require_once($CFG->dirroot . '/mod/quiz/attemptlib.php'); -require_once($CFG->dirroot . '/mod/quiz/editlib.php'); /** * Unit tests for quiz events. diff --git a/mod/quiz/tests/lib_test.php b/mod/quiz/tests/lib_test.php index 02703ac05b0..cb08add7681 100644 --- a/mod/quiz/tests/lib_test.php +++ b/mod/quiz/tests/lib_test.php @@ -26,9 +26,6 @@ defined('MOODLE_INTERNAL') || die(); -global $CFG; -require_once($CFG->dirroot . '/mod/quiz/editlib.php'); - /** * @copyright 2008 The Open University diff --git a/mod/quiz/tests/repaginate_test.php b/mod/quiz/tests/repaginate_test.php index 3d664cf2deb..06cda7d7db5 100644 --- a/mod/quiz/tests/repaginate_test.php +++ b/mod/quiz/tests/repaginate_test.php @@ -25,7 +25,6 @@ defined('MOODLE_INTERNAL') || die(); global $CFG; -require_once($CFG->dirroot . '/mod/quiz/editlib.php'); require_once($CFG->dirroot . '/mod/quiz/locallib.php'); require_once($CFG->dirroot . '/mod/quiz/classes/repaginate.php'); diff --git a/mod/quiz/tests/structure_test.php b/mod/quiz/tests/structure_test.php index 26f60bb03bc..0a1d84c8785 100644 --- a/mod/quiz/tests/structure_test.php +++ b/mod/quiz/tests/structure_test.php @@ -27,7 +27,6 @@ defined('MOODLE_INTERNAL') || die(); global $CFG; require_once($CFG->dirroot . '/mod/quiz/attemptlib.php'); -require_once($CFG->dirroot . '/mod/quiz/editlib.php'); /** * Unit tests for quiz events. diff --git a/mod/quiz/upgrade.txt b/mod/quiz/upgrade.txt index 797cd4aaafe..92c590fa263 100644 --- a/mod/quiz/upgrade.txt +++ b/mod/quiz/upgrade.txt @@ -23,8 +23,8 @@ This files describes API changes in the quiz code. two scripts get merged in future.) Also questionbank.ajax.php (which may, in future, be made more generic, and moved into the core question bank code.) - As a result of this, mod/quiz/editlib.php is now much shorter than it was. - (In future, expect the remaining code in here to move into mod/quiz/classes.) + As a result of this, mod/quiz/editlib.php has gone. (A few remaining functions + were moved to locallib.php.) Here is a list of all the old functions or classes that have changed. If you used any of these in custom code, you will need to update your code.