Merge branch 'MDL-47132' of git://github.com/timhunt/moodle
authorSam Hemelryk <sam@moodle.com>
Tue, 7 Oct 2014 23:01:42 +0000 (12:01 +1300)
committerSam Hemelryk <sam@moodle.com>
Tue, 7 Oct 2014 23:01:42 +0000 (12:01 +1300)
19 files changed:
mod/quiz/addrandom.php
mod/quiz/classes/output/edit_renderer.php
mod/quiz/classes/question/bank/add_action_column.php [new file with mode: 0644]
mod/quiz/classes/question/bank/custom_view.php [new file with mode: 0644]
mod/quiz/classes/question/bank/question_name_text_column.php [new file with mode: 0644]
mod/quiz/db/renamedclasses.php [new file with mode: 0644]
mod/quiz/edit.php
mod/quiz/edit_rest.php
mod/quiz/editlib.php [deleted file]
mod/quiz/locallib.php
mod/quiz/questionbank.ajax.php
mod/quiz/styles.css
mod/quiz/tests/attempt_walkthrough_from_csv_test.php
mod/quiz/tests/attempt_walkthrough_test.php
mod/quiz/tests/events_test.php
mod/quiz/tests/lib_test.php
mod/quiz/tests/repaginate_test.php
mod/quiz/tests/structure_test.php
mod/quiz/upgrade.txt

index 3f80896..658ecb8 100644 (file)
  */
 
 
-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) =
index 1d5ec62..a1c2606 100644 (file)
@@ -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 (file)
index 0000000..0e1d17c
--- /dev/null
@@ -0,0 +1,59 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * 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 (file)
index 0000000..f3db929
--- /dev/null
@@ -0,0 +1,239 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * 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 '<div class="modulespecificbuttonscontainer">';
+        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 "</div>\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 "<p style=\"text-align:center;\"><b>";
+        print_string('selectcategoryabove', 'question');
+        echo "</b></p>";
+        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 '<div class="categoryinfo"><div class="categorynamefieldcontainer">' .
+                $strcategory;
+        echo ': <span class="categorynamefield">';
+        echo shorten_text(strip_tags(format_string($category->name)), 60);
+        echo '</span></div><div class="categoryinfofieldcontainer">' .
+                '<span class="categoryinfofield">';
+        echo shorten_text(strip_tags(format_text($category->info, $category->infoformat,
+                $formatoptions, $this->course->id)), 200);
+        echo '</span></div></div>';
+    }
+
+    protected function display_options($recurse, $showhidden, $showquestiontext) {
+        debugging('display_options() is deprecated, see display_options_form() instead.', DEBUG_DEVELOPER);
+        echo '<form method="get" action="edit.php" id="displayoptions">';
+        echo "<fieldset class='invisiblefieldset'>";
+        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 '<noscript><div class="centerpara"><input type="submit" value="' .
+                get_string('go') . '" />';
+        echo '</div></noscript></fieldset></form>';
+    }
+
+    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 (file)
index 0000000..fa15f54
--- /dev/null
@@ -0,0 +1,60 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * 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 '<div>';
+        $labelfor = $this->label_for($question);
+        if ($labelfor) {
+            echo '<label for="' . $labelfor . '">';
+        }
+        echo quiz_question_tostring($question);
+        if ($labelfor) {
+            echo '</label>';
+        }
+        echo '</div>';
+    }
+
+    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 (file)
index 0000000..3cc07a1
--- /dev/null
@@ -0,0 +1,34 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * 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',
+);
index caa882a..6f9af09 100644 (file)
  */
 
 
-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
@@ -281,7 +282,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);
 
index 8d5e933..55b09fa 100644 (file)
@@ -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 (file)
index 871dc17..0000000
+++ /dev/null
@@ -1,460 +0,0 @@
-<?php
-// This file is part of Moodle - http://moodle.org/
-//
-// Moodle is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// Moodle is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
-
-
-/**
- * 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);
-    }
-}
-
-
-/**
- * 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 '<div>';
-        $labelfor = $this->label_for($question);
-        if ($labelfor) {
-            echo '<label for="' . $labelfor . '">';
-        }
-        echo quiz_question_tostring($question);
-        if ($labelfor) {
-            echo '</label>';
-        }
-        echo '</div>';
-    }
-
-    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 '<div class="modulespecificbuttonscontainer">';
-        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 "</div>\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 "<p style=\"text-align:center;\"><b>";
-        print_string('selectcategoryabove', 'question');
-        echo "</b></p>";
-        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 '<div class="categoryinfo"><div class="categorynamefieldcontainer">' .
-                $strcategory;
-        echo ': <span class="categorynamefield">';
-        echo shorten_text(strip_tags(format_string($category->name)), 60);
-        echo '</span></div><div class="categoryinfofieldcontainer">' .
-                '<span class="categoryinfofield">';
-        echo shorten_text(strip_tags(format_text($category->info, $category->infoformat,
-                $formatoptions, $this->course->id)), 200);
-        echo '</span></div></div>';
-    }
-
-    protected function display_options($recurse, $showhidden, $showquestiontext) {
-        debugging('display_options() is deprecated, see display_options_form() instead.', DEBUG_DEVELOPER);
-        echo '<form method="get" action="edit.php" id="displayoptions">';
-        echo "<fieldset class='invisiblefieldset'>";
-        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 '<noscript><div class="centerpara"><input type="submit" value="' .
-                get_string('go') . '" />';
-        echo '</div></noscript></fieldset></form>';
-    }
-
-    protected function create_new_question_form($category, $canadd) {
-        // Don't display this.
-    }
-}
index 993574a..6e8ac7b 100644 (file)
@@ -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);
+    }
+}
index 4055938..2f5018a 100644 (file)
@@ -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);
@@ -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.
index 901cd97..13eabcb 100644 (file)
@@ -701,8 +701,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 {
index 3f96fd9..25387db 100644 (file)
@@ -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');
 
 /**
index 2c0fabb..282e453 100644 (file)
@@ -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');
 
 /**
index 4ea32ec..2f92237 100644 (file)
@@ -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.
index 02703ac..cb08add 100644 (file)
@@ -26,9 +26,6 @@
 
 defined('MOODLE_INTERNAL') || die();
 
-global $CFG;
-require_once($CFG->dirroot . '/mod/quiz/editlib.php');
-
 
 /**
  * @copyright  2008 The Open University
index 3d664cf..06cda7d 100644 (file)
@@ -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');
 
index 26f60bb..0a1d84c 100644 (file)
@@ -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.
index 911e92c..0f38061 100644 (file)
@@ -2,6 +2,11 @@ This files describes API changes in the quiz code.
 
 === 2.8 ===
 
+* Classes that were 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
@@ -18,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.