MDL-71679 mod_quiz: Updates for new qbank api

This implementation will introduct changes to
the mod_quiz to implement the new qbank api
for view. Major changes are introduced in
the custom view and also all the legacy points
to the old qbank are changed to qbank plugins
where needed. It also deprecated and deletes
classes and scripts which were kept not to
break mod_quiz for the new api implementation.
This commit is contained in:
Safat Shahin
2021-10-04 15:44:25 +11:00
parent 1a9bee69e6
commit f9fc355ec7
64 changed files with 286 additions and 5970 deletions
@@ -137,7 +137,7 @@ abstract class base extends area_base {
}
// Default to SITEID if courseid is null, i.e. system or category level questions.
$thiscourseid = ($componentinfo->courseid !== null) ? $componentinfo->courseid : SITEID;
return new \moodle_url('/question/question.php', ['courseid' => $thiscourseid, 'id' => $questionid]);
return new \moodle_url('/question/bank/editquestion/question.php', ['courseid' => $thiscourseid, 'id' => $questionid]);
}
/**
-17
View File
@@ -692,23 +692,6 @@ $CFG->admin = 'admin';
// $CFG->uninstallclionly = true;
//
//
// Customise question bank display
//
// The display of Moodle's question bank is made up of a number of columns.
// You can customise this display by giving a comma-separated list of column class
// names here. Each class must be a subclass of \core_question\bank\column_base.
// For example you might define a class like
// class \local_qbank_extensions\my_column extends \core_question\bank\column_base
// in a local plugin, then add it to the list here. At the time of writing,
// the default question bank display is equivalent to the following, but you might like
// to check the latest default in question/classes/bank/view.php before setting this.
//
// $CFG->questionbankcolumns = 'checkbox_column,question_type_column,'
// . 'question_name_idnumber_tags_column,edit_menu_column,'
// . 'tags_action_column,edit_action_column,copy_action_column,'
// . 'preview_action_column,delete_action_column,export_xml_action_column,'
// . 'creator_name_column,modifier_name_column';
//
// Forum summary report
//
// In order for the forum summary report to calculate word count and character count data, those details are now stored
+3 -3
View File
@@ -77,11 +77,11 @@ class question_created extends question_base {
public function get_url() {
if ($this->courseid) {
if ($this->contextlevel == CONTEXT_MODULE) {
return new \moodle_url('/question/preview.php', ['cmid' => $this->contextinstanceid, 'id' => $this->objectid]);
return new \moodle_url('/question/bank/previewquestion/preview.php', ['cmid' => $this->contextinstanceid, 'id' => $this->objectid]);
}
return new \moodle_url('/question/preview.php', ['courseid' => $this->courseid, 'id' => $this->objectid]);
return new \moodle_url('/question/bank/previewquestion/preview.php', ['courseid' => $this->courseid, 'id' => $this->objectid]);
}
// Lets try editing from the frontpage for contexts above course.
return new \moodle_url('/question/preview.php', ['courseid' => SITEID, 'id' => $this->objectid]);
return new \moodle_url('/question/bank/previewquestion/preview.php', ['courseid' => SITEID, 'id' => $this->objectid]);
}
}
+3 -2
View File
@@ -25,8 +25,6 @@
namespace core\plugininfo;
defined('MOODLE_INTERNAL') || die();
/**
* Base class for qbank plugins.
*
@@ -38,6 +36,9 @@ defined('MOODLE_INTERNAL') || die();
class qbank extends base {
public function is_uninstall_allowed(): bool {
if (in_array($this->name, \core_plugin_manager::standard_plugins_list('qbank'))) {
return false;
}
return true;
}
+36 -2
View File
@@ -35,17 +35,51 @@ defined('MOODLE_INTERNAL') || die();
// Like other files in the db directory this file uses an array.
// The old class name is the key, the new class name is the value.
// The array must be called $renamedclasses.
$renamedclasses = array(
$renamedclasses = [
// Since Moodle 3.7.
'core\\analytics\\target\\course_dropout' => 'core_course\\analytics\\target\\course_dropout',
'core\\analytics\\target\\course_competencies' => 'core_course\\analytics\\target\\course_competencies',
'core\\analytics\\target\\course_completion' => 'core_course\\analytics\\target\\course_completion',
'core\\analytics\\target\\course_gradetopass' => 'core_course\\analytics\\target\\course_gradetopass',
'core\\analytics\\target\\no_teaching' => 'core_course\\analytics\\target\\no_teaching',
// Since Moodle 4.0.
'format_base' => 'core_courseformat\\base',
'format_topics_renderer' => 'format_topics\\output\\renderer',
'format_section_renderer_base' => 'core_courseformat\\output\\section_renderer',
'format_singleactivity_renderer' => 'format_singleactivity\\output\\renderer',
'format_site_renderer' => 'core_courseformat\\output\\site_renderer',
'format_weeks_renderer' => 'format_weeks\\output\\renderer',
);
'core_question\\bank\\action_column_base' => 'core_question\\local\\bank\\action_column_base',
'core_question\\bank\\checkbox_column' => 'core_question\\local\\bank\\checkbox_column',
'core_question\\bank\\column_base' => 'core_question\\local\\bank\\column_base',
'core_question\\bank\\edit_menu_column' => 'core_question\\local\\bank\\edit_menu_column',
'core_question\\bank\\menu_action_column_base' => 'core_question\\local\\bank\\menu_action_column_base',
'core_question\\bank\\menuable_action' => 'core_question\\local\\bank\\menuable_action',
'core_question\\bank\\random_question_loader' => 'core_question\\local\\bank\\random_question_loader',
'core_question\\bank\\row_base' => 'core_question\\local\\bank\\row_base',
'core_question\\bank\\view' => 'core_question\\local\\bank\\view',
'core_question\\bank\\copy_action_column' => 'qbank_editquestion\\copy_action_column',
'core_question\\bank\\edit_action_column' => 'qbank_editquestion\\edit_action_column',
'core_question\\bank\\creator_name_column' => 'qbank_viewcreator\\creator_name_column',
'core_question\\bank\\modifier_name_column' => 'qbank_viewcreator\\modifier_name_column',
'core_question\\bank\\question_name_column' => 'qbank_viewquestionname\\viewquestionname_column_helper',
'core_question\\bank\\question_name_idnumber_tags_column' => 'qbank_viewquestionname\\question_name_idnumber_tags_column',
'core_question\\bank\\delete_action_column' => 'qbank_deletequestion\\delete_action_column',
'core_question\\bank\\export_xml_action_column' => 'qbank_exporttoxml\\export_xml_action_column',
'core_question\\bank\\preview_action_column' => 'qbank_previewquestion\\preview_action_column',
'core_question\\bank\\question_text_row' => 'qbank_viewquestiontext\\question_text_row',
'core_question\\bank\\question_type_column' => 'qbank_viewquestiontype\\question_type_column',
'core_question\\bank\\tags_action_column' => 'qbank_tagquestion\\tags_action_column',
'core_question\\output\\qbank_chooser' => 'qbank_editquestion\\qbank_chooser',
'core_question\\output\\qbank_chooser_item' => 'qbank_editquestion\\qbank_chooser_item',
'question_move_form' => 'qbank_managecategories\\form\\question_move_form',
'question_import_form' => 'qbank_importquestions\\form\\question_import_form',
'question_category_list' => 'qbank_managecategories\\question_category_list',
'question_category_list_item' => 'qbank_managecategories\\question_category_list_item',
'question_category_object' => 'qbank_managecategories\\question_category_object',
'category_form' => 'qbank_managecategories\\form\\category_form',
'export_form' => 'qbank_exportquestions\\form\\export_form',
'preview_options_form' => 'qbank_previewquestion\\form\\preview_options_form',
'question_preview_options' => 'qbank_previewquestion\\output\\question_preview_options',
'core_question\\form\\tags' => '\qbank_tagquestion\\form\\tags_form'
];
+18 -24
View File
@@ -759,14 +759,12 @@ function question_move_category_to_context($categoryid, $oldcontextid, $newconte
* @return moodle_url the URL.
* @deprecated since Moodle 4.0
* @see qbank_previewquestion\helper::question_preview_url()
* @todo MDL-71679 uncomment the debug messages after implementing the changes in mod_quiz.
* @todo Final deprecation on Moodle 4.4 MDL-72438
*/
function question_preview_url($questionid, $preferredbehaviour = null,
$maxmark = null, $displayoptions = null, $variant = null, $context = null) {
// Debugging message will be re-added after implementing the changes in mod_quiz.
// ...debugging('Function question_preview_url() has been deprecated and moved to qbank_previewquestion plugin,
// Please use qbank_previewquestion\helper::question_preview_url() instead.', DEBUG_DEVELOPER);.
debugging('Function question_preview_url() has been deprecated and moved to qbank_previewquestion plugin,
Please use qbank_previewquestion\helper::question_preview_url() instead.', DEBUG_DEVELOPER);
return \qbank_previewquestion\helper::question_preview_url($questionid, $preferredbehaviour = null,
$maxmark = null, $displayoptions = null, $variant = null, $context = null);
@@ -776,13 +774,11 @@ function question_preview_url($questionid, $preferredbehaviour = null,
* @return array that can be passed as $params to the {@link popup_action} constructor.
* @deprecated since Moodle 4.0
* @see qbank_previewquestion\helper::question_preview_popup_params()
* @todo MDL-71679 uncomment the debug messages after implementing the changes to mod_quiz.
* @todo Final deprecation on Moodle 4.4 MDL-72438
*/
function question_preview_popup_params() {
// Debugging message will be re-added after implementing the changes in mod_quiz.
// ...debugging('Function question_preview_popup_params() has been deprecated and moved to qbank_previewquestion plugin,
// Please use qbank_previewquestion\helper::question_preview_popup_params() instead.', DEBUG_DEVELOPER);.
debugging('Function question_preview_popup_params() has been deprecated and moved to qbank_previewquestion plugin,
Please use qbank_previewquestion\helper::question_preview_popup_params() instead.', DEBUG_DEVELOPER);
return \qbank_previewquestion\helper::question_preview_popup_params();
}
@@ -1656,18 +1652,9 @@ function question_extend_settings_navigation(navigation_node $navigationnode, $c
'title' => get_string('questions', 'question'),
'url' => new moodle_url($baseurl)
],
'categories' => [
'title' => get_string('categories', 'question'),
'url' => new moodle_url('/question/category.php')
],
'import' => [
'title' => get_string('import', 'question'),
'url' => new moodle_url('/question/import.php')
],
'export' => [
'title' => get_string('export', 'question'),
'url' => new moodle_url('/question/export.php')
]
'categories' => [],
'import' => [],
'export' => []
];
$plugins = \core_component::get_plugin_list_with_class('qbank', 'plugin_feature', 'plugin_feature.php');
@@ -1692,16 +1679,23 @@ function question_extend_settings_navigation(navigation_node $navigationnode, $c
];
}
}
}
// Mitigate the risk of regression.
foreach ($corenavigations as $node => $corenavigation) {
if (empty($corenavigation)) {
unset($corenavigations[$node]);
}
}
// Community/additional plugins have navigation node.
$pluginnavigations = [];
foreach ($plugins as $componentname => $plugin) {
$pluginentrypoin = new $plugin();
$pluginentrypointobject = $pluginentrypoin->get_navigation_node();
if (!\core\plugininfo\qbank::is_plugin_enabled($componentname)) {
unset($corenavigations[$key]);
$pluginentrypoint = new $plugin();
$pluginentrypointobject = $pluginentrypoint->get_navigation_node();
// Don't need the plugins without navigation node.
if ($pluginentrypointobject === null || !\core\plugininfo\qbank::is_plugin_enabled($componentname)) {
unset($plugins[$componentname]);
continue;
}
$pluginnavigations[$pluginentrypointobject->get_navigation_key()] = [
+5
View File
@@ -69,6 +69,11 @@ information provided here is intended especially for developers.
rendered. The default icon for "select" types has also changed to a dropdown caret ("t/expanded").
* The function message_send() in messagelib.php now returns false if there is an error sending the message to the
message processor (MDL-70046).
* Following methods are now deprecated in questionlib and moved to the new qbank_previewquestion plugin:
- question_preview_url() is moved to qbank_previewquestion\helper::question_preview_url()
- question_preview_popup_params() is moved to \qbank_previewquestion\helper::question_preview_popup_params()
Calling these functions in the question will point to the plugin.
The deprecated codes are removed from the questionlib for those two methods.
* The following functions are deprecated in questionlib.php and moved to the new location.
These are marked for final deprecation on 4.4:
- question_remove_stale_questions_from_category() =>
+1 -1
View File
@@ -2107,7 +2107,7 @@ class quiz_attempt {
} else {
$tagids = quiz_retrieve_slot_tag_ids($this->slots[$slot]->id);
$randomloader = new \core_question\bank\random_question_loader($qubaids, array());
$randomloader = new \core_question\local\bank\random_question_loader($qubaids, array());
$newqusetionid = $randomloader->get_next_question_id($questiondata->category,
(bool) $questiondata->questiontext, $tagids);
if ($newqusetionid === null) {
+5 -7
View File
@@ -651,7 +651,7 @@ class edit_renderer extends \plugin_renderer_base {
'addonpage' => $page, 'appendqnumstring' => 'addquestion');
$actions['addaquestion'] = new \action_menu_link_secondary(
new \moodle_url('/question/addquestion.php', $params),
new \moodle_url('/question/bank/editquestion/addquestion.php', $params),
new \pix_icon('t/add', $str->addaquestion, 'moodle', array('class' => 'iconsmall', 'title' => '')),
$str->addaquestion, array('class' => 'cm-edit-action addquestion', 'data-action' => 'addquestion')
);
@@ -722,7 +722,7 @@ class edit_renderer extends \plugin_renderer_base {
return html_writer::tag('form', html_writer::div($output),
array('class' => 'addnewquestion', 'method' => 'post',
'action' => new \moodle_url('/question/addquestion.php')));
'action' => new \moodle_url('/question/bank/editquestion/addquestion.php')));
}
/**
@@ -836,7 +836,7 @@ class edit_renderer extends \plugin_renderer_base {
$image = $this->pix_icon('t/preview', $strpreviewquestion);
$action = new \popup_action('click', $url, 'questionpreview',
question_preview_popup_params());
\qbank_previewquestion\helper::question_preview_popup_params());
return $this->action_link($url, $image . $strpreviewlabel, $action,
array('title' => $strpreviewquestion, 'class' => 'preview'));
@@ -946,7 +946,7 @@ class edit_renderer extends \plugin_renderer_base {
$output = '';
$question = $structure->get_question_in_slot($slot);
$editurl = new \moodle_url('/question/question.php', array(
$editurl = new \moodle_url('/question/bank/editquestion/question.php', array(
'returnurl' => $pageurl->out_as_local_url(),
'cmid' => $structure->get_cmid(), 'id' => $question->id));
@@ -1252,9 +1252,7 @@ class edit_renderer extends \plugin_renderer_base {
*/
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'],
$pagevars['qtagids']);
$qbank = $questionbank->render($pagevars, 'editq');
return html_writer::div(html_writer::div($qbank, 'bd'), 'questionbankformforpopup');
}
}
+1 -1
View File
@@ -32,5 +32,5 @@ defined('MOODLE_INTERNAL') || die();
* @copyright 2016 Frédéric Massart - FMCorz.net
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class question_chooser extends \core_question\output\qbank_chooser {
class question_chooser extends \qbank_editquestion\qbank_chooser {
}
@@ -14,30 +14,23 @@
// 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.
*
* @package mod_quiz
* @category question
* @copyright 2009 Tim Hunt
* @author 2021 Safat Shahin <[email protected]>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class add_action_column extends \core_question\bank\action_column_base {
class add_action_column extends \core_question\local\bank\action_column_base {
/** @var string caches a lang string used repeatedly. */
protected $stradd;
public function init() {
public function init(): void {
parent::init();
$this->stradd = get_string('addtoquiz', 'quiz');
}
+49 -119
View File
@@ -31,18 +31,22 @@ use coding_exception;
* Subclass to customise the view of the question bank for the quiz editing screen.
*
* @copyright 2009 Tim Hunt
* @author 2021 Safat Shahin <[email protected]>
* @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. */
class custom_view extends \core_question\local\bank\view {
/** @var bool $quizhasattempts whether the quiz this is used by has been attemptd. */
protected $quizhasattempts = false;
/** @var \stdClass the quiz settings. */
/** @var \stdClass $quiz the quiz settings. */
protected $quiz = false;
/** @var int The maximum displayed length of the category info. */
const MAX_TEXT_LENGTH = 200;
/**
* Constructor
* Constructor for custom_view.
* @param \question_edit_contexts $contexts
* @param \moodle_url $pageurl
* @param \stdClass $course course settings
@@ -54,76 +58,66 @@ class custom_view extends \core_question\bank\view {
$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);
}
protected function wanted_columns(): array {
$quizquestionbankcolumns = [
'mod_quiz\\question\\bank\\add_action_column',
'core_question\\local\\bank\\checkbox_column',
'qbank_viewquestiontype\\question_type_column',
'mod_quiz\\question\\bank\\question_name_text_column',
'qbank_previewquestion\\preview_action_column',
];
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('Invalid quiz question bank column', $fullname);
}
throw new coding_exception('Invalid quiz question bank column', $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() {
protected function heading_column(): string {
return 'mod_quiz\\question\\bank\\question_name_text_column';
}
protected function default_sort() {
return array(
'core_question\\bank\\question_type_column' => 1,
protected function default_sort(): array {
return [
'qbank_viewquestiontype\\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) {
public function set_quiz_has_attempts($quizhasattempts): void {
$this->quizhasattempts = $quizhasattempts;
if ($quizhasattempts && isset($this->visiblecolumns['addtoquizaction'])) {
unset($this->visiblecolumns['addtoquizaction']);
}
}
/**
* Question preview url.
*
* @param \stdClass $question
* @return \moodle_url
*/
public function preview_question_url($question) {
return quiz_question_preview_url($this->quiz, $question);
}
/**
* URL of add to quiz.
*
* @param $questionid
* @return \moodle_url
*/
public function add_to_quiz_url($questionid) {
global $CFG;
$params = $this->baseurl->params();
$params['addquestion'] = $questionid;
$params['sesskey'] = sesskey();
@@ -136,34 +130,26 @@ class custom_view extends \core_question\bank\view {
* Note that you can only output this rendered result once per page, as
* it contains IDs which must be unique.
*
* @param array $pagevars
* @param string $tabname
* @return string HTML code for the form
*/
public function render($tabname, $page, $perpage, $cat, $recurse, $showhidden,
$showquestiontext, $tagids = []) {
public function render($pagevars, $tabname): string {
ob_start();
$this->display($tabname, $page, $perpage, $cat, $recurse, $showhidden, $showquestiontext, $tagids);
$this->display($pagevars, $tabname);
$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) {
protected function display_bottom_controls($totalnumber, $recurse, $category, \context $catcontext, array $addcontexts): void {
$cmoptions = new \stdClass();
$cmoptions->hasattempts = !empty($this->quizhasattempts);
$canuseall = has_capability('moodle/question:useall', $catcontext);
echo '<div class="modulespecificbuttonscontainer">';
echo \html_writer::start_tag('div', ['class' => 'modulespecificbuttonscontainer']);
if ($canuseall) {
// Add selected questions to the quiz.
$params = array(
'type' => 'submit',
@@ -177,75 +163,19 @@ class custom_view extends \core_question\bank\view {
);
echo \html_writer::empty_tag('input', $params);
}
echo "</div>\n";
echo \html_writer::end_tag('div');
}
/**
* 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) {
protected function create_new_question_form($category, $canadd): void {
// Don't display this.
}
/**
* Override the base implementation in \core_question\bank\view
* Override the base implementation in \core_question\local\bank\view
* because we don't want to print the headers in the fragment
* for the modal.
*/
protected function display_question_bank_header() {
protected function display_question_bank_header(): void {
}
/**
@@ -256,7 +186,7 @@ class custom_view extends \core_question\bank\view {
* Unfortunately the best we can do is to look at the URL for
* those parameters (only marginally better really).
*/
protected function init_sort_from_params() {
protected function init_sort_from_params(): void {
$this->sort = [];
for ($i = 1; $i <= self::MAX_SORTS; $i++) {
if (!$sort = $this->baseurl->param('qbs' . $i)) {
@@ -272,8 +202,8 @@ class custom_view extends \core_question\bank\view {
}
}
// Deal with subsorts.
list($colname, $subsort) = $this->parse_subsort($sort);
$this->requiredcolumns[$colname] = $this->get_column_type($colname);
list($colname) = $this->parse_subsort($sort);
$this->get_column_type($colname);
$this->sort[$sort] = $order;
}
}
@@ -14,39 +14,35 @@
// 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 of the question name.
*
* @package core_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 name of the question name.
*
* @package mod_quiz
* @category question
* @copyright 2009 Tim Hunt
* @author 2021 Safat Shahin <[email protected]>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
* @todo MDL-72004 delete the class and add it to lib/db/renameclasses.php pointing to the plugin
*/
class question_name_column extends \core_question\bank\column_base {
class question_name_column extends \core_question\local\bank\column_base {
/**
* @var null $checkboxespresent
*/
protected $checkboxespresent = null;
public function get_name() {
public function get_name(): string {
return 'questionname';
}
protected function get_title() {
protected function get_title(): string {
return get_string('question');
}
protected function label_for($question) {
protected function label_for($question): string {
if (is_null($this->checkboxespresent)) {
$this->checkboxespresent = $this->qbank->has_column('core_question\bank\checkbox_column');
$this->checkboxespresent = $this->qbank->has_column('core_question\local\bank\checkbox_column');
}
if ($this->checkboxespresent) {
return 'checkq' . $question->id;
@@ -55,19 +51,19 @@ class question_name_column extends \core_question\bank\column_base {
}
}
protected function display_content($question, $rowclasses) {
protected function display_content($question, $rowclasses): void {
$labelfor = $this->label_for($question);
if ($labelfor) {
echo '<label for="' . $labelfor . '">';
echo \html_writer::start_tag('label', ['for' => $labelfor]);
}
echo format_string($question->name);
if ($labelfor) {
echo '</label>';
echo \html_writer::end_tag('label');
}
}
public function get_required_fields() {
return array('q.id', 'q.name');
public function get_required_fields(): array {
return ['q.id', 'q.name'];
}
public function is_sortable() {
@@ -14,44 +14,37 @@
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* 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.
*
* @package mod_quiz
* @category question
* @copyright 2009 Tim Hunt
* @author 2021 Safat Shahin <[email protected]>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class question_name_text_column extends question_name_column {
public function get_name() {
public function get_name(): string {
return 'questionnametext';
}
protected function display_content($question, $rowclasses) {
echo '<div>';
protected function display_content($question, $rowclasses): void {
echo \html_writer::start_tag('div');
$labelfor = $this->label_for($question);
if ($labelfor) {
echo '<label for="' . $labelfor . '">';
echo \html_writer::start_tag('label', ['for' => $labelfor]);
}
echo quiz_question_tostring($question, false, true, true, $question->tags);
if ($labelfor) {
echo '</label>';
echo \html_writer::end_tag('label');
}
echo '</div>';
echo \html_writer::end_tag('div');
}
public function get_required_fields() {
public function get_required_fields(): array {
$fields = parent::get_required_fields();
$fields[] = 'q.questiontext';
$fields[] = 'q.questiontextformat';
+1 -1
View File
@@ -171,7 +171,7 @@ if (optional_param('savechanges', false, PARAM_BOOL) && confirm_sesskey()) {
// Get the question bank view.
$questionbank = new mod_quiz\question\bank\custom_view($contexts, $thispageurl, $course, $cm, $quiz);
$questionbank->set_quiz_has_attempts($quizhasattempts);
$questionbank->process_actions($thispageurl, $cm);
$questionbank->process_actions();
// End of process commands =====================================================.
+3 -3
View File
@@ -199,7 +199,7 @@ function quiz_start_new_attempt($quizobj, $quba, $attempt, $attemptnumber, $time
$usedquestionids[$question->id] = 1;
}
}
$randomloader = new \core_question\bank\random_question_loader($qubaids, $usedquestionids);
$randomloader = new \core_question\local\bank\random_question_loader($qubaids, $usedquestionids);
foreach ($quizobj->get_questions() as $questiondata) {
$slot += 1;
@@ -1401,7 +1401,7 @@ function quiz_question_edit_button($cmid, $question, $returnurl, $contentafteric
$returnurl = $returnurl->out_as_local_url(false);
}
$questionparams = array('returnurl' => $returnurl, 'cmid' => $cmid, 'id' => $question->id);
$questionurl = new moodle_url("$CFG->wwwroot/question/question.php", $questionparams);
$questionurl = new moodle_url("$CFG->wwwroot/question/bank/editquestion/question.php", $questionparams);
return '<a title="' . $action . '" href="' . $questionurl->out() . '" class="questioneditbutton">' .
$OUTPUT->pix_icon($icon, $action) . $contentaftericon .
'</a>';
@@ -1429,7 +1429,7 @@ function quiz_question_preview_url($quiz, $question, $variant = null) {
}
// Work out the correcte preview URL.
return question_preview_url($question->id, $quiz->preferredbehaviour,
return \qbank_previewquestion\helper::question_preview_url($question->id, $quiz->preferredbehaviour,
$maxmark, $displayoptions, $variant);
}
+3 -4
View File
@@ -429,8 +429,7 @@ class behat_mod_quiz extends behat_question_base {
*/
public function i_should_see_on_quiz_page($questionname, $pagenumber) {
$xpath = "//li[contains(., '" . $this->escape($questionname) .
"')][./preceding-sibling::li[contains(@class, 'pagenumber')][1][contains(., 'Page " .
$pagenumber . "')]]";
"')][./preceding-sibling::li[contains(., 'Page " . $pagenumber . "')]]";
$this->execute('behat_general::should_exist', array($xpath, 'xpath_element'));
}
@@ -457,8 +456,8 @@ class behat_mod_quiz extends behat_question_base {
* @param string $secondquestionname the name of the question that should come immediately after it in order.
*/
public function i_should_see_before_on_the_edit_quiz_page($firstquestionname, $secondquestionname) {
$xpath = "//li[contains(@class, ' slot ') and contains(., '" . $this->escape($firstquestionname) .
"')]/following-sibling::li[contains(@class, ' slot ')][1]" .
$xpath = "//li[contains(., '" . $this->escape($firstquestionname) .
"')]/following-sibling::li" .
"[contains(., '" . $this->escape($secondquestionname) . "')]";
$this->execute('behat_general::should_exist', array($xpath, 'xpath_element'));
@@ -79,7 +79,7 @@ Feature: Adding questions to a quiz from the question bank
Then I should see "question 21 name" in the "categoryquestions" "table"
And I should see "question 22 name" in the "categoryquestions" "table"
And I should not see "question 01 name" in the "categoryquestions" "table"
And I click on "Show all 22" "link" in the ".pagingbottom" "css_element"
And I click on "Show all 22" "link" in the ".question-showall-text" "css_element"
And I should see "question 01 name" in the "categoryquestions" "table"
And I should see "question 22 name" in the "categoryquestions" "table"
@@ -63,7 +63,15 @@ class quiz_question_bank_view_testcase extends advanced_testcase {
// Generate the view.
$view = new mod_quiz\question\bank\custom_view($contexts, new moodle_url('/'), $course, $cm, $quiz);
ob_start();
$view->display('editq', 0, 20, $cat->id . ',' . $cat->contextid, false, false, false);
$pagevars = [
'qpage' => 0,
'qperpage' => 20,
'cat' => $cat->id . ',' . $context->id,
'recurse' => false,
'showhidden' => false,
'qbshowtext' => false
];
$view->display($pagevars, 'editq');
$html = ob_get_clean();
// Verify the output includes the expected question.
-93
View File
@@ -1,93 +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/>.
/**
* Shows a screen where the user can choose a question type, before being
* redirected to question.php
*
* @package moodlecore
* @subpackage questionbank
* @copyright 2009 Tim Hunt
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
require_once(__DIR__ . '/../config.php');
require_once(__DIR__ . '/editlib.php');
// Read URL parameters.
$categoryid = required_param('category', PARAM_INT);
$cmid = optional_param('cmid', 0, PARAM_INT);
$courseid = optional_param('courseid', 0, PARAM_INT);
$returnurl = optional_param('returnurl', 0, PARAM_LOCALURL);
$appendqnumstring = optional_param('appendqnumstring', '', PARAM_ALPHA);
$validationerror = optional_param('validationerror', false, PARAM_BOOL);
// Place to accumulate hidden params for the form we will print.
$hiddenparams = array('category' => $categoryid);
// Validate params.
if (!$category = $DB->get_record('question_categories', array('id' => $categoryid))) {
print_error('categorydoesnotexist', 'question', $returnurl);
}
if ($cmid) {
list($module, $cm) = get_module_from_cmid($cmid);
require_login($cm->course, false, $cm);
$thiscontext = context_module::instance($cmid);
$hiddenparams['cmid'] = $cmid;
} else if ($courseid) {
require_login($courseid, false);
$thiscontext = context_course::instance($courseid);
$module = null;
$cm = null;
$hiddenparams['courseid'] = $courseid;
} else {
print_error('missingcourseorcmid', 'question');
}
// Check permissions.
$categorycontext = context::instance_by_id($category->contextid);
require_capability('moodle/question:add', $categorycontext);
// Ensure other optional params get passed on to question.php.
if (!empty($returnurl)) {
$hiddenparams['returnurl'] = $returnurl;
}
if (!empty($appendqnumstring)) {
$hiddenparams['appendqnumstring'] = $appendqnumstring;
}
$PAGE->set_url('/question/addquestion.php', $hiddenparams);
if ($cmid) {
$questionbankurl = new moodle_url('/question/edit.php', array('cmid' => $cmid));
} else {
$questionbankurl = new moodle_url('/question/edit.php', array('courseid' => $courseid));
}
navigation_node::override_active_url($questionbankurl);
$chooseqtype = get_string('chooseqtypetoadd', 'question');
$PAGE->set_heading($COURSE->fullname);
$PAGE->navbar->add($chooseqtype);
$PAGE->set_title($chooseqtype);
// Display a form to choose the question type.
echo $OUTPUT->header();
echo $OUTPUT->notification(get_string('youmustselectaqtype', 'question'));
echo $OUTPUT->box_start('generalbox boxwidthnormal boxaligncenter', 'chooseqtypebox');
echo print_choose_qtype_to_add_form($hiddenparams, null, false);
echo $OUTPUT->box_end();
echo $OUTPUT->footer();
+2 -601
View File
@@ -21,608 +21,9 @@
* @subpackage questionbank
* @copyright 1999 onwards Martin Dougiamas {@link http://moodle.com}
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
defined('MOODLE_INTERNAL') || die();
// number of categories to display on page
define('QUESTION_PAGE_LENGTH', 25);
require_once($CFG->libdir . '/listlib.php');
require_once($CFG->dirroot . '/question/category_form.php');
require_once($CFG->dirroot . '/question/move_form.php');
/**
* Class representing a list of question categories
*
* @copyright 1999 onwards Martin Dougiamas {@link http://moodle.com}
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
* @deprecated since Moodle 4.0 MDL-71585
* @see \qbank_managecategories\question_category_list
* @todo deprecation on MDL-71679
*/
class question_category_list extends moodle_list {
public $table = "question_categories";
public $listitemclassname = 'question_category_list_item';
/**
* @var reference to list displayed below this one.
*/
public $nextlist = null;
/**
* @var reference to list displayed above this one.
*/
public $lastlist = null;
public $context = null;
public $sortby = 'parent, sortorder, name';
public function __construct($type='ul', $attributes='', $editable = false, $pageurl=null, $page = 0, $pageparamname = 'page', $itemsperpage = 20, $context = null){
debugging('Class question_category_list in \core_question\category_class is deprecated,
please use qbank_managecategories\question_category_list instead.', DEBUG_DEVELOPER);
parent::__construct('ul', '', $editable, $pageurl, $page, 'cpage', $itemsperpage);
$this->context = $context;
}
public function get_records() {
$this->records = get_categories_for_contexts($this->context->id, $this->sortby);
}
/**
* Returns the highest category id that the $item can have as its parent.
* Note: question categories cannot go higher than the TOP category.
*
* @param list_item $item The item which its top level parent is going to be returned.
* @return int
*/
public function get_top_level_parent_id($item) {
// Put the item at the highest level it can go.
$topcategory = question_get_top_category($item->item->contextid, true);
return $topcategory->id;
}
/**
* process any actions.
*
* @param integer $left id of item to move left
* @param integer $right id of item to move right
* @param integer $moveup id of item to move up
* @param integer $movedown id of item to move down
* @return void
* @throws coding_exception
*/
public function process_actions($left, $right, $moveup, $movedown) {
$category = new stdClass();
if (!empty($left)) {
// Moved Left (In to another category).
$category->id = $left;
$category->contextid = $this->context->id;
$event = \core\event\question_category_moved::create_from_question_category_instance($category);
$event->trigger();
} else if (!empty($right)) {
// Moved Right (Out of the current category).
$category->id = $right;
$category->contextid = $this->context->id;
$event = \core\event\question_category_moved::create_from_question_category_instance($category);
$event->trigger();
}
parent::process_actions($left, $right, $moveup, $movedown);
}
}
/**
* An item in a list of question categories.
*
* @copyright 1999 onwards Martin Dougiamas {@link http://moodle.com}
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
* @deprecated since Moodle 4.0 MDL-71585
* @see \qbank_managecategories\question_category_list_item
* @todo deprecation on MDL-71679
*/
class question_category_list_item extends list_item {
public function set_icon_html($first, $last, $lastitem){
debugging('Function set_icon_html() in \core_question\category_class is deprecated,
please use qbank_managecategories\question_category_list_item::set_icon_html() instead.', DEBUG_DEVELOPER);
global $CFG;
$category = $this->item;
$url = new moodle_url('/question/category.php', ($this->parentlist->pageurl->params() + array('edit'=>$category->id)));
$this->icons['edit']= $this->image_icon(get_string('editthiscategory', 'question'), $url, 'edit');
parent::set_icon_html($first, $last, $lastitem);
$toplevel = ($this->parentlist->parentitem === null);//this is a top level item
if (($this->parentlist->nextlist !== null) && $last && $toplevel && (count($this->parentlist->items)>1)){
$url = new moodle_url($this->parentlist->pageurl, array('movedowncontext'=>$this->id, 'tocontext'=>$this->parentlist->nextlist->context->id, 'sesskey'=>sesskey()));
$this->icons['down'] = $this->image_icon(
get_string('shareincontext', 'question', $this->parentlist->nextlist->context->get_context_name()), $url, 'down');
}
if (($this->parentlist->lastlist !== null) && $first && $toplevel && (count($this->parentlist->items)>1)){
$url = new moodle_url($this->parentlist->pageurl, array('moveupcontext'=>$this->id, 'tocontext'=>$this->parentlist->lastlist->context->id, 'sesskey'=>sesskey()));
$this->icons['up'] = $this->image_icon(
get_string('shareincontext', 'question', $this->parentlist->lastlist->context->get_context_name()), $url, 'up');
}
}
public function item_html($extraargs = array()){
global $CFG, $PAGE, $OUTPUT;
debugging('Function item_html() in \core_question\category_class is deprecated,
please use qbank_managecategories\question_category_list_item::item_html() instead.', DEBUG_DEVELOPER);
$str = $extraargs['str'];
$category = $this->item;
$editqestions = get_string('editquestions', 'question');
// Each section adds html to be displayed as part of this list item.
$nodeparent = $PAGE->settingsnav->find('questionbank', \navigation_node::TYPE_CONTAINER);
$questionbankurl = new moodle_url($nodeparent->action, $this->parentlist->pageurl->params());
$questionbankurl->param('cat', $category->id . ',' . $category->contextid);
$item = '';
$text = format_string($category->name, true, ['context' => $this->parentlist->context]);
if ($category->idnumber !== null && $category->idnumber !== '') {
$text .= ' ' . html_writer::span(
html_writer::span(get_string('idnumber', 'question'), 'accesshide') .
' ' . $category->idnumber, 'badge badge-primary');
}
$text .= ' (' . $category->questioncount . ')';
$item .= html_writer::tag('b', html_writer::link($questionbankurl, $text,
['title' => $editqestions]) . ' ');
$item .= format_text($category->info, $category->infoformat,
array('context' => $this->parentlist->context, 'noclean' => true));
// Don't allow delete if this is the top category, or the last editable category in this context.
if ($category->parent && !question_is_only_child_of_top_category_in_context($category->id)) {
$deleteurl = new moodle_url($this->parentlist->pageurl, array('delete' => $this->id, 'sesskey' => sesskey()));
$item .= html_writer::link($deleteurl,
$OUTPUT->pix_icon('t/delete', $str->delete),
array('title' => $str->delete));
}
return $item;
}
}
/**
* Class for performing operations on question categories.
*
* @copyright 1999 onwards Martin Dougiamas {@link http://moodle.com}
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
* @deprecated since Moodle 4.0 MDL-71585
* @see \qbank_managecategories\question_category_object
* @todo deprecation on MDL-71679
*/
class question_category_object {
/**
* @var array common language strings.
*/
public $str;
/**
* @var array nested lists to display categories.
*/
public $editlists = array();
public $tab;
public $tabsize = 3;
/**
* @var moodle_url Object representing url for this page
*/
public $pageurl;
/**
* @var question_category_edit_form Object representing form for adding / editing categories.
*/
public $catform;
/**
* Constructor.
*
* @param int $page page number
* @param moodle_url $pageurl base URL of the display categories page. Used for redirects.
* @param context[] $contexts contexts where the current user can edit categories.
* @param int $currentcat id of the category to be edited. 0 if none.
* @param int|null $defaultcategory id of the current category. null if none.
* @param int $todelete id of the category to delete. 0 if none.
* @param context[] $addcontexts contexts where the current user can add questions.
*/
public function __construct($page, $pageurl, $contexts, $currentcat, $defaultcategory, $todelete, $addcontexts) {
debugging('Class question_category_list in \core_question\category_class is deprecated,
please use qbank_managecategories\question_category_object instead.', DEBUG_DEVELOPER);
$this->tab = str_repeat('&nbsp;', $this->tabsize);
$this->str = new stdClass();
$this->str->course = get_string('course');
$this->str->category = get_string('category', 'question');
$this->str->categoryinfo = get_string('categoryinfo', 'question');
$this->str->questions = get_string('questions', 'question');
$this->str->add = get_string('add');
$this->str->delete = get_string('delete');
$this->str->moveup = get_string('moveup');
$this->str->movedown = get_string('movedown');
$this->str->edit = get_string('editthiscategory', 'question');
$this->str->hide = get_string('hide');
$this->str->order = get_string('order');
$this->str->parent = get_string('parent', 'question');
$this->str->add = get_string('add');
$this->str->action = get_string('action');
$this->str->top = get_string('top');
$this->str->addcategory = get_string('addcategory', 'question');
$this->str->editcategory = get_string('editcategory', 'question');
$this->str->cancel = get_string('cancel');
$this->str->editcategories = get_string('editcategories', 'question');
$this->str->page = get_string('page');
$this->pageurl = $pageurl;
$this->initialize($page, $contexts, $currentcat, $defaultcategory, $todelete, $addcontexts);
}
/**
* Old syntax of class constructor. Deprecated in PHP7.
*
* @deprecated since Moodle 3.1
*/
public function question_category_object($page, $pageurl, $contexts, $currentcat, $defaultcategory, $todelete, $addcontexts) {
debugging('Use of class name as constructor is deprecated', DEBUG_DEVELOPER);
self::__construct($page, $pageurl, $contexts, $currentcat, $defaultcategory, $todelete, $addcontexts);
}
/**
* Initializes this classes general category-related variables
*/
public function initialize($page, $contexts, $currentcat, $defaultcategory, $todelete, $addcontexts) {
$lastlist = null;
foreach ($contexts as $context){
$this->editlists[$context->id] = new question_category_list('ul', '', true, $this->pageurl, $page, 'cpage', QUESTION_PAGE_LENGTH, $context);
$this->editlists[$context->id]->lastlist =& $lastlist;
if ($lastlist!== null){
$lastlist->nextlist =& $this->editlists[$context->id];
}
$lastlist =& $this->editlists[$context->id];
}
$count = 1;
$paged = false;
foreach ($this->editlists as $key => $list){
list($paged, $count) = $this->editlists[$key]->list_from_records($paged, $count);
}
$this->catform = new question_category_edit_form($this->pageurl, compact('contexts', 'currentcat'));
if (!$currentcat){
$this->catform->set_data(array('parent'=>$defaultcategory));
}
}
/**
* Displays the user interface
*
*/
public function display_user_interface() {
/// Interface for editing existing categories
$this->output_edit_lists();
echo '<br />';
/// Interface for adding a new category:
$this->output_new_table();
echo '<br />';
}
/**
* Outputs a table to allow entry of a new category
*/
public function output_new_table() {
$this->catform->display();
}
/**
* Outputs a list to allow editing/rearranging of existing categories
*
* $this->initialize() must have already been called
*
*/
public function output_edit_lists() {
global $OUTPUT;
echo $OUTPUT->heading_with_help(get_string('editcategories', 'question'), 'editcategories', 'question');
foreach ($this->editlists as $context => $list){
$listhtml = $list->to_html(0, array('str'=>$this->str));
if ($listhtml){
echo $OUTPUT->box_start('boxwidthwide boxaligncenter generalbox questioncategories contextlevel' . $list->context->contextlevel);
$fullcontext = context::instance_by_id($context);
echo $OUTPUT->heading(get_string('questioncatsfor', 'question', $fullcontext->get_context_name()), 3);
echo $listhtml;
echo $OUTPUT->box_end();
}
}
echo $list->display_page_numbers();
}
/**
* gets all the courseids for the given categories
*
* @param array categories contains category objects in a tree representation
* @return array courseids flat array in form categoryid=>courseid
*/
public function get_course_ids($categories) {
$courseids = array();
foreach ($categories as $key=>$cat) {
$courseids[$key] = $cat->course;
if (!empty($cat->children)) {
$courseids = array_merge($courseids, $this->get_course_ids($cat->children));
}
}
return $courseids;
}
public function edit_single_category($categoryid) {
/// Interface for adding a new category
global $DB;
/// Interface for editing existing categories
$category = $DB->get_record("question_categories", array("id" => $categoryid));
if (empty($category)) {
print_error('invalidcategory', '', '', $categoryid);
} else if ($category->parent == 0) {
print_error('cannotedittopcat', 'question', '', $categoryid);
} else {
$category->parent = "{$category->parent},{$category->contextid}";
$category->submitbutton = get_string('savechanges');
$category->categoryheader = $this->str->edit;
$this->catform->set_data($category);
$this->catform->display();
}
}
/**
* Sets the viable parents
*
* Viable parents are any except for the category itself, or any of it's descendants
* The parentstrings parameter is passed by reference and changed by this function.
*
* @param array parentstrings a list of parentstrings
* @param object category
*/
public function set_viable_parents(&$parentstrings, $category) {
unset($parentstrings[$category->id]);
if (isset($category->children)) {
foreach ($category->children as $child) {
$this->set_viable_parents($parentstrings, $child);
}
}
}
/**
* Gets question categories
*
* @param int parent - if given, restrict records to those with this parent id.
* @param string sort - [[sortfield [,sortfield]] {ASC|DESC}]
* @return array categories
*/
public function get_question_categories($parent=null, $sort="sortorder ASC") {
global $COURSE, $DB;
if (is_null($parent)) {
$categories = $DB->get_records('question_categories', array('course' => $COURSE->id), $sort);
} else {
$select = "parent = ? AND course = ?";
$categories = $DB->get_records_select('question_categories', $select, array($parent, $COURSE->id), $sort);
}
return $categories;
}
/**
* Deletes an existing question category
*
* @param int deletecat id of category to delete
*/
public function delete_category($categoryid) {
global $CFG, $DB;
question_can_delete_cat($categoryid);
if (!$category = $DB->get_record("question_categories", array("id" => $categoryid))) { // security
print_error('unknowcategory');
}
/// Send the children categories to live with their grandparent
$DB->set_field("question_categories", "parent", $category->parent, array("parent" => $category->id));
/// Finally delete the category itself
$DB->delete_records("question_categories", array("id" => $category->id));
// Log the deletion of this category.
$event = \core\event\question_category_deleted::create_from_question_category_instance($category);
$event->add_record_snapshot('question_categories', $category);
$event->trigger();
}
public function move_questions_and_delete_category($oldcat, $newcat){
question_can_delete_cat($oldcat);
$this->move_questions($oldcat, $newcat);
$this->delete_category($oldcat);
}
public function display_move_form($questionsincategory, $category){
global $OUTPUT;
$vars = new stdClass();
$vars->name = $category->name;
$vars->count = $questionsincategory;
echo $OUTPUT->box(get_string('categorymove', 'question', $vars), 'generalbox boxaligncenter');
$this->moveform->display();
}
public function move_questions($oldcat, $newcat){
global $DB;
$questionids = $DB->get_records_select_menu('question',
'category = ? AND (parent = 0 OR parent = id)', array($oldcat), '', 'id,1');
question_move_questions_to_category(array_keys($questionids), $newcat);
}
/**
* Create a new category.
*
* Data is expected to come from question_category_edit_form.
*
* By default redirects on success, unless $return is true.
*
* @param string $newparent 'categoryid,contextid' of the parent category.
* @param string $newcategory the name.
* @param string $newinfo the description.
* @param bool $return if true, return rather than redirecting.
* @param int|string $newinfoformat description format. One of the FORMAT_ constants.
* @param null $idnumber the idnumber. '' is converted to null.
* @return bool|int New category id if successful, else false.
*/
public function add_category($newparent, $newcategory, $newinfo, $return = false, $newinfoformat = FORMAT_HTML,
$idnumber = null) {
global $DB;
if (empty($newcategory)) {
print_error('categorynamecantbeblank', 'question');
}
list($parentid, $contextid) = explode(',', $newparent);
//moodle_form makes sure select element output is legal no need for further cleaning
require_capability('moodle/question:managecategory', context::instance_by_id($contextid));
if ($parentid) {
if(!($DB->get_field('question_categories', 'contextid', array('id' => $parentid)) == $contextid)) {
print_error('cannotinsertquestioncatecontext', 'question', '', array('cat'=>$newcategory, 'ctx'=>$contextid));
}
}
if ((string) $idnumber === '') {
$idnumber = null;
} else if (!empty($contextid)) {
// While this check already exists in the form validation, this is a backstop preventing unnecessary errors.
if ($DB->record_exists('question_categories',
['idnumber' => $idnumber, 'contextid' => $contextid])) {
$idnumber = null;
}
}
$cat = new stdClass();
$cat->parent = $parentid;
$cat->contextid = $contextid;
$cat->name = $newcategory;
$cat->info = $newinfo;
$cat->infoformat = $newinfoformat;
$cat->sortorder = 999;
$cat->stamp = make_unique_id_code();
$cat->idnumber = $idnumber;
$categoryid = $DB->insert_record("question_categories", $cat);
// Log the creation of this category.
$category = new stdClass();
$category->id = $categoryid;
$category->contextid = $contextid;
$event = \core\event\question_category_created::create_from_question_category_instance($category);
$event->trigger();
if ($return) {
return $categoryid;
} else {
redirect($this->pageurl);//always redirect after successful action
}
}
/**
* Updates an existing category with given params.
*
* Warning! parameter order and meaning confusingly different from add_category in some ways!
*
* @param int $updateid id of the category to update.
* @param int $newparent 'categoryid,contextid' of the parent category to set.
* @param string $newname category name.
* @param string $newinfo category description.
* @param int|string $newinfoformat description format. One of the FORMAT_ constants.
* @param int $idnumber the idnumber. '' is converted to null.
* @param bool $redirect if true, will redirect once the DB is updated (default).
*/
public function update_category($updateid, $newparent, $newname, $newinfo, $newinfoformat = FORMAT_HTML,
$idnumber = null, $redirect = true) {
global $CFG, $DB;
if (empty($newname)) {
print_error('categorynamecantbeblank', 'question');
}
// Get the record we are updating.
$oldcat = $DB->get_record('question_categories', array('id' => $updateid));
$lastcategoryinthiscontext = question_is_only_child_of_top_category_in_context($updateid);
if (!empty($newparent) && !$lastcategoryinthiscontext) {
list($parentid, $tocontextid) = explode(',', $newparent);
} else {
$parentid = $oldcat->parent;
$tocontextid = $oldcat->contextid;
}
// Check permissions.
$fromcontext = context::instance_by_id($oldcat->contextid);
require_capability('moodle/question:managecategory', $fromcontext);
// If moving to another context, check permissions some more, and confirm contextid,stamp uniqueness.
$newstamprequired = false;
if ($oldcat->contextid != $tocontextid) {
$tocontext = context::instance_by_id($tocontextid);
require_capability('moodle/question:managecategory', $tocontext);
// Confirm stamp uniqueness in the new context. If the stamp already exists, generate a new one.
if ($DB->record_exists('question_categories', array('contextid' => $tocontextid, 'stamp' => $oldcat->stamp))) {
$newstamprequired = true;
}
}
if ((string) $idnumber === '') {
$idnumber = null;
} else if (!empty($tocontextid)) {
// While this check already exists in the form validation, this is a backstop preventing unnecessary errors.
if ($DB->record_exists_select('question_categories',
'idnumber = ? AND contextid = ? AND id <> ?',
[$idnumber, $tocontextid, $updateid])) {
$idnumber = null;
}
}
// Update the category record.
$cat = new stdClass();
$cat->id = $updateid;
$cat->name = $newname;
$cat->info = $newinfo;
$cat->infoformat = $newinfoformat;
$cat->parent = $parentid;
$cat->contextid = $tocontextid;
$cat->idnumber = $idnumber;
if ($newstamprequired) {
$cat->stamp = make_unique_id_code();
}
$DB->update_record('question_categories', $cat);
// Log the update of this category.
$event = \core\event\question_category_updated::create_from_question_category_instance($cat);
$event->trigger();
// If the category name has changed, rename any random questions in that category.
if ($oldcat->name != $cat->name) {
$where = "qtype = 'random' AND category = ? AND " . $DB->sql_compare_text('questiontext') . " = ?";
$randomqtype = question_bank::get_qtype('random');
$randomqname = $randomqtype->question_name($cat, false);
$DB->set_field_select('question', 'name', $randomqname, $where, array($cat->id, '0'));
$randomqname = $randomqtype->question_name($cat, true);
$DB->set_field_select('question', 'name', $randomqname, $where, array($cat->id, '1'));
}
if ($oldcat->contextid != $tocontextid) {
// Moving to a new context. Must move files belonging to questions.
question_move_category_to_context($cat->id, $oldcat->contextid, $tocontextid);
}
// Cat param depends on the context id, so update it.
$this->pageurl->param('cat', $updateid . ',' . $tocontextid);
if ($redirect) {
redirect($this->pageurl); // Always redirect after successful action.
}
}
}
* @todo Final deprecation on Moodle 4.4 MDL-72438
*/
+1 -96
View File
@@ -21,102 +21,7 @@
* @subpackage questionbank
* @copyright 2007 Jamie Pratt [email protected]
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
defined('MOODLE_INTERNAL') || die();
require_once($CFG->libdir.'/formslib.php');
/**
* Form for editing qusetions categories (name, description, etc.)
*
* @copyright 2007 Jamie Pratt [email protected]
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
* @deprecated since Moodle 4.0 MDL-71585
* @see qbank_managecategories\form\category_form
* @todo Final deprecation on Moodle 4.4 MDL-72438
*/
class question_category_edit_form extends moodleform {
protected function definition() {
debugging('Class question_export_form in \core_question\category_form is deprecated,
please use core_question\bank\managecategories\form\category_form instead.', DEBUG_DEVELOPER);
$mform = $this->_form;
$contexts = $this->_customdata['contexts'];
$currentcat = $this->_customdata['currentcat'];
$mform->addElement('header', 'categoryheader', get_string('addcategory', 'question'));
$mform->addElement('questioncategory', 'parent', get_string('parentcategory', 'question'),
array('contexts' => $contexts, 'top' => true, 'currentcat' => $currentcat, 'nochildrenof' => $currentcat));
$mform->setType('parent', PARAM_SEQUENCE);
if (question_is_only_child_of_top_category_in_context($currentcat)) {
$mform->hardFreeze('parent');
}
$mform->addHelpButton('parent', 'parentcategory', 'question');
$mform->addElement('text', 'name', get_string('name'),'maxlength="254" size="50"');
$mform->setDefault('name', '');
$mform->addRule('name', get_string('categorynamecantbeblank', 'question'), 'required', null, 'client');
$mform->setType('name', PARAM_TEXT);
$mform->addElement('editor', 'info', get_string('categoryinfo', 'question'),
array('rows' => 10), array('noclean' => 1));
$mform->setDefault('info', '');
$mform->setType('info', PARAM_RAW);
$mform->addElement('text', 'idnumber', get_string('idnumber', 'question'), 'maxlength="100" size="10"');
$mform->addHelpButton('idnumber', 'idnumber', 'question');
$mform->setType('idnumber', PARAM_RAW);
$this->add_action_buttons(false, get_string('addcategory', 'question'));
$mform->addElement('hidden', 'id', 0);
$mform->setType('id', PARAM_INT);
}
public function set_data($current) {
if (is_object($current)) {
$current = (array) $current;
}
if (!empty($current['info'])) {
$current['info'] = array('text' => $current['info'],
'infoformat' => $current['infoformat']);
} else {
$current['info'] = array('text' => '', 'infoformat' => FORMAT_HTML);
}
parent::set_data($current);
}
/**
* Validation.
*
* @param array $data
* @param array $files
* @return array the errors that were found
*/
public function validation($data, $files) {
global $DB;
$errors = parent::validation($data, $files);
// Add field validation check for duplicate idnumber.
list($parentid, $contextid) = explode(',', $data['parent']);
if (((string) $data['idnumber'] !== '') && !empty($contextid)) {
$conditions = 'contextid = ? AND idnumber = ?';
$params = [$contextid, $data['idnumber']];
if (!empty($data['id'])) {
$conditions .= ' AND id <> ?';
$params[] = $data['id'];
}
if ($DB->record_exists_select('question_categories', $conditions, $params)) {
$errors['idnumber'] = get_string('idnumbertaken', 'error');
}
}
return $errors;
}
}
@@ -1,61 +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/>.
/**
* A base class for actions that are an icon that lets you manipulate the question in some way.
*
* @package core_question
* @copyright 2009 Tim Hunt
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace core_question\bank;
defined('MOODLE_INTERNAL') || die();
/**
* A base class for actions that are an icon that lets you manipulate the question in some way.
*
* @copyright 2009 Tim Hunt
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
* @todo MDL-72004 delete the class and add it to lib/db/renameclasses.php pointing to core_question/local/bank
*/
abstract class action_column_base extends column_base {
protected function get_title() {
return '&#160;';
}
public function get_extra_classes() {
return array('iconcol');
}
protected function print_icon($icon, $title, $url) {
global $OUTPUT;
echo '<a title="' . $title . '" href="' . $url . '">' . $OUTPUT->pix_icon($icon, $title) . '</a>';
}
public function get_extra_joins() {
return array('qc' => 'JOIN {question_categories} qc ON qc.id = q.category');
}
public function get_required_fields() {
// Createdby is required for permission checks.
// Qtype so we can easily avoid applying actions to question types that
// are no longer installed.
return ['q.id', 'q.qtype', 'q.createdby', 'qc.contextid'];
}
}
-78
View File
@@ -1,78 +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/>.
/**
* A column with a checkbox for each question with name q{questionid}.
*
* @package core_question
* @copyright 2009 Tim Hunt
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace core_question\bank;
defined('MOODLE_INTERNAL') || die();
use core\output\checkbox_toggleall;
/**
* A column with a checkbox for each question with name q{questionid}.
*
* @copyright 2009 Tim Hunt
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
* @todo MDL-72004 delete the class and add it to lib/db/renameclasses.php pointing to core_question/local/bank
*/
class checkbox_column extends column_base {
public function get_name() {
return 'checkbox';
}
protected function get_title() {
global $OUTPUT;
$mastercheckbox = new checkbox_toggleall('qbank', true, [
'id' => 'qbheadercheckbox',
'name' => 'qbheadercheckbox',
'value' => '1',
'label' => get_string('selectall'),
'labelclasses' => 'accesshide',
]);
return $OUTPUT->render($mastercheckbox);
}
protected function get_title_tip() {
return get_string('selectquestionsforbulk', 'question');
}
protected function display_content($question, $rowclasses) {
global $OUTPUT;
$checkbox = new checkbox_toggleall('qbank', false, [
'id' => "checkq{$question->id}",
'name' => "q{$question->id}",
'value' => '1',
'label' => get_string('select'),
'labelclasses' => 'accesshide',
]);
echo $OUTPUT->render($checkbox);
}
public function get_required_fields() {
return array('q.id');
}
}
-369
View File
@@ -1,369 +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/>.
/**
* Base class for representing a column in a {@see question_bank_view}.
*
* @package core_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 core_question\bank;
defined('MOODLE_INTERNAL') || die();
/**
* Base class for representing a column in a {@see question_bank_view}.
*
* @copyright 2009 Tim Hunt
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
* @todo MDL-72004 delete the class and add it to lib/db/renameclasses.php pointing to core_question/local/bank
*/
abstract class column_base {
/**
* @var view $qbank the question bank view we are helping to render.
*/
protected $qbank;
/** @var bool determine whether the column is td or th. */
protected $isheading = false;
/**
* Constructor for the question bank view we are helping to render.
* @param view $qbank
*/
public function __construct($qbank) {
$this->qbank = $qbank;
$this->init();
}
/**
* A chance for subclasses to initialise themselves, for example to load lang strings,
* without having to override the constructor.
*/
protected function init() {
}
/**
* Set the column as heading
*/
public function set_as_heading() {
$this->isheading = true;
}
public function is_extra_row() {
return false;
}
/**
* Check if the row has an extra preference to view/hide.
*/
public function has_preference(): bool {
return false;
}
/**
* Get if the preference key of the row.
*/
public function get_preference_key(): string {
return '';
}
/**
* Get if the preference of the row.
*/
public function get_preference(): bool {
return false;
}
/**
* Output the column header cell.
*/
public function display_header() {
echo '<th class="header ' . $this->get_classes() . '" scope="col">';
$sortable = $this->is_sortable();
$name = get_class($this);
$title = $this->get_title();
$tip = $this->get_title_tip();
if (is_array($sortable)) {
if ($title) {
echo '<div class="title">' . $title . '</div>';
}
$links = array();
foreach ($sortable as $subsort => $details) {
$links[] = $this->make_sort_link($name . '-' . $subsort,
$details['title'], isset($details['tip']) ? $details['tip'] : '', !empty($details['reverse']));
}
echo '<div class="sorters">' . implode(' / ', $links) . '</div>';
} else if ($sortable) {
echo $this->make_sort_link($name, $title, $tip);
} else {
if ($tip) {
echo '<span title="' . $tip . '">';
}
echo $title;
if ($tip) {
echo '</span>';
}
}
echo "</th>\n";
}
/**
* Title for this column. Not used if is_sortable returns an array.
*/
protected abstract function get_title();
/**
* @return string a fuller version of the name. Use this when get_title() returns
* something very short, and you want a longer version as a tool tip.
*/
protected function get_title_tip() {
return '';
}
/**
* Get a link that changes the sort order, and indicates the current sort state.
* @param string $sort the column to sort on.
* @param string $title the link text.
* @param string $tip the link tool-tip text. If empty, defaults to title.
* @param bool $defaultreverse whether the default sort order for this column is descending, rather than ascending.
* @return string HTML fragment.
*/
protected function make_sort_link($sort, $title, $tip, $defaultreverse = false) {
$currentsort = $this->qbank->get_primary_sort_order($sort);
$newsortreverse = $defaultreverse;
if ($currentsort) {
$newsortreverse = $currentsort > 0;
}
if (!$tip) {
$tip = $title;
}
if ($newsortreverse) {
$tip = get_string('sortbyxreverse', '', $tip);
} else {
$tip = get_string('sortbyx', '', $tip);
}
$link = '<a href="' . $this->qbank->new_sort_url($sort, $newsortreverse) . '" title="' . $tip . '">';
$link .= $title;
if ($currentsort) {
$link .= $this->get_sort_icon($currentsort < 0);
}
$link .= '</a>';
return $link;
}
/**
* Get an icon representing the corrent sort state.
* @param bool $reverse sort is descending, not ascending.
* @return string HTML image tag.
*/
protected function get_sort_icon($reverse) {
global $OUTPUT;
if ($reverse) {
return $OUTPUT->pix_icon('t/sort_desc', get_string('desc'), '', array('class' => 'iconsort'));
} else {
return $OUTPUT->pix_icon('t/sort_asc', get_string('asc'), '', array('class' => 'iconsort'));
}
}
/**
* Output this column.
* @param object $question the row from the $question table, augmented with extra information.
* @param string $rowclasses CSS class names that should be applied to this row of output.
*/
public function display($question, $rowclasses) {
$this->display_start($question, $rowclasses);
$this->display_content($question, $rowclasses);
$this->display_end($question, $rowclasses);
}
/**
* Output the opening column tag. If it is set as heading, it will use <th> tag instead of <td>
*
* @param \stdClass $question
* @param string $rowclasses
*/
protected function display_start($question, $rowclasses) {
$tag = 'td';
$attr = array('class' => $this->get_classes());
if ($this->isheading) {
$tag = 'th';
$attr['scope'] = 'row';
}
echo \html_writer::start_tag($tag, $attr);
}
/**
* @return string the CSS classes to apply to every cell in this column.
*/
protected function get_classes() {
$classes = $this->get_extra_classes();
$classes[] = $this->get_name();
return implode(' ', $classes);
}
/**
* Get the internal name for this column. Used as a CSS class name,
* and to store information about the current sort. Must match PARAM_ALPHA.
*
* @return string column name.
*/
public abstract function get_name();
/**
* @return array any extra class names you would like applied to every cell in this column.
*/
public function get_extra_classes() {
return array();
}
/**
* Output the contents of this column.
* @param object $question the row from the $question table, augmented with extra information.
* @param string $rowclasses CSS class names that should be applied to this row of output.
*/
protected abstract function display_content($question, $rowclasses);
/**
* Output the closing column tag
*
* @param object $question
* @param string $rowclasses
*/
protected function display_end($question, $rowclasses) {
$tag = 'td';
if ($this->isheading) {
$tag = 'th';
}
echo \html_writer::end_tag($tag);
}
/**
* Return an array 'table_alias' => 'JOIN clause' to bring in any data that
* this column required.
*
* The return values for all the columns will be checked. It is OK if two
* columns join in the same table with the same alias and identical JOIN clauses.
* If to columns try to use the same alias with different joins, you get an error.
* The only table included by default is the question table, which is aliased to 'q'.
*
* It is importnat that your join simply adds additional data (or NULLs) to the
* existing rows of the query. It must not cause additional rows.
*
* @return array 'table_alias' => 'JOIN clause'
*/
public function get_extra_joins() {
return array();
}
/**
* @return array fields required. use table alias 'q' for the question table, or one of the
* ones from get_extra_joins. Every field requested must specify a table prefix.
*/
public function get_required_fields() {
return array();
}
/**
* If this column needs extra data (e.g. tags) then load that here.
*
* The extra data should be added to the question object in the array.
* Probably a good idea to check that another column has not already
* loaded the data you want.
*
* @param \stdClass[] $questions the questions that will be displayed.
*/
public function load_additional_data(array $questions) {
}
/**
* Load the tags for each question.
*
* Helper that can be used from {@see load_additional_data()};
*
* @param array $questions
*/
public function load_question_tags(array $questions) {
$firstquestion = reset($questions);
if (isset($firstquestion->tags)) {
// Looks like tags are already loaded, so don't do it again.
return;
}
// Load the tags.
$tagdata = \core_tag_tag::get_items_tags('core_question', 'question',
array_keys($questions));
// Add them to the question objects.
foreach ($tagdata as $questionid => $tags) {
$questions[$questionid]->tags = $tags;
}
}
/**
* Can this column be sorted on? You can return either:
* + false for no (the default),
* + a field name, if sorting this column corresponds to sorting on that datbase field.
* + an array of subnames to sort on as follows
* return array(
* 'firstname' => array('field' => 'uc.firstname', 'title' => get_string('firstname')),
* 'lastname' => array('field' => 'uc.lastname', 'title' => get_string('lastname')),
* );
* As well as field, and field, you can also add 'revers' => 1 if you want the default sort
* order to be DESC.
* @return mixed as above.
*/
public function is_sortable() {
return false;
}
/**
* Helper method for building sort clauses.
* @param bool $reverse whether the normal direction should be reversed.
* @return string 'ASC' or 'DESC'
*/
protected function sortorder($reverse) {
if ($reverse) {
return ' DESC';
} else {
return ' ASC';
}
}
/**
* @param bool $reverse Whether to sort in the reverse of the default sort order.
* @param string $subsort if is_sortable returns an array of subnames, then this will be
* one of those. Otherwise will be empty.
* @return string some SQL to go in the order by clause.
*/
public function sort_expression($reverse, $subsort) {
$sortable = $this->is_sortable();
if (is_array($sortable)) {
if (array_key_exists($subsort, $sortable)) {
return $sortable[$subsort]['field'] . $this->sortorder($reverse);
} else {
throw new \coding_exception('Unexpected $subsort type: ' . $subsort);
}
} else if ($sortable) {
return $sortable . $this->sortorder($reverse);
} else {
throw new \coding_exception('sort_expression called on a non-sortable column.');
}
}
}
@@ -1,66 +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/>.
/**
* Question bank column for the duplicate action icon.
*
* @package core_question
* @copyright 2013 The Open University
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace core_question\bank;
defined('MOODLE_INTERNAL') || die();
/**
* Question bank column for the duplicate action icon.
*
* @copyright 2013 The Open University
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
* @todo MDL-72004 delete the class and add it to lib/db/renameclasses.php pointing to the plugin
*/
class copy_action_column extends menu_action_column_base {
/** @var string avoids repeated calls to get_string('duplicate'). */
protected $strcopy;
public function init() {
parent::init();
$this->strcopy = get_string('duplicate');
}
public function get_name() {
return 'copyaction';
}
protected function get_url_icon_and_label(\stdClass $question): array {
if (!\question_bank::is_qtype_installed($question->qtype)) {
// It sometimes happens that people end up with junk questions
// in their question bank of a type that is no longer installed.
// We cannot do most actions on them, because that leads to errors.
return [null, null, null];
}
// To copy a question, you need permission to add a question in the same
// category as the existing question, and ability to access the details of
// the question being copied.
if (question_has_capability_on($question, 'add') &&
(question_has_capability_on($question, 'edit') || question_has_capability_on($question, 'view'))) {
return [$this->qbank->copy_question_moodle_url($question->id), 't/copy', $this->strcopy];
}
return [null, null, null];
}
}
@@ -1,75 +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/>.
/**
* A column type for the name of the question creator.
*
* @package core_question
* @copyright 2009 Tim Hunt
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace core_question\bank;
defined('MOODLE_INTERNAL') || die();
/**
* A column type for the name of the question creator.
*
* @copyright 2009 Tim Hunt
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
* @todo MDL-72004 delete the class and add it to lib/db/renameclasses.php pointing to the plugin
*/
class creator_name_column extends column_base {
public function get_name() {
return 'creatorname';
}
protected function get_title() {
return get_string('createdby', 'question');
}
protected function display_content($question, $rowclasses) {
if (!empty($question->creatorfirstname) && !empty($question->creatorlastname)) {
$u = new \stdClass();
$u = username_load_fields_from_object($u, $question, 'creator');
$date = userdate($question->timecreated, get_string('strftimedatetime', 'langconfig'));
echo fullname($u) . '<br>' . \html_writer::tag('span', $date, array('class' => 'date'));
}
}
public function get_extra_joins() {
return array('uc' => 'LEFT JOIN {user} uc ON uc.id = q.createdby');
}
public function get_required_fields() {
$allnames = \core_user\fields::get_name_fields();
$requiredfields = array();
foreach ($allnames as $allname) {
$requiredfields[] = 'uc.' . $allname . ' AS creator' . $allname;
}
$requiredfields[] = 'q.timecreated';
return $requiredfields;
}
public function is_sortable() {
return array(
'firstname' => array('field' => 'uc.firstname', 'title' => get_string('firstname')),
'lastname' => array('field' => 'uc.lastname', 'title' => get_string('lastname')),
'timecreated' => array('field' => 'q.timecreated', 'title' => get_string('date'))
);
}
}
@@ -1,82 +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/>.
/**
* action to delete (or hide) a question, or restore a previously hidden question.
*
* @package core_question
* @copyright 2009 Tim Hunt
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace core_question\bank;
defined('MOODLE_INTERNAL') || die();
/**
* action to delete (or hide) a question, or restore a previously hidden question.
*
* @copyright 2009 Tim Hunt
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
* @todo MDL-72004 delete the class and add it to lib/db/renameclasses.php pointing to the plugin
*/
class delete_action_column extends menu_action_column_base {
protected $strdelete;
protected $strrestore;
public function init() {
parent::init();
$this->strdelete = get_string('delete');
$this->strrestore = get_string('restore');
}
public function get_name() {
return 'deleteaction';
}
/**
* Work out the info required to display this action, if appropriate.
*
* If the action is not appropriate to this question, return [null, null, null].
*
* Otherwise return an array with three elements:
* moodel_url $url the URL to perform the action.
* string $icon the icon name. E.g. 't/delete'.
* string $label the label to display.
*
* @param object $question the row from the $question table, augmented with extra information.
* @return array [$url, $label, $icon] as above.
*/
protected function get_url_icon_and_label(\stdClass $question): array {
if (!question_has_capability_on($question, 'edit')) {
return [null, null, null];
}
if ($question->hidden) {
$url = new \moodle_url($this->qbank->base_url(), array('unhide' => $question->id, 'sesskey' => sesskey()));
return [$url, 't/restore', $this->strrestore];
} else {
$url = new \moodle_url($this->qbank->base_url(), array('deleteselected' => $question->id, 'q' . $question->id => 1,
'sesskey' => sesskey()));
return [$url, 't/delete', $this->strdelete];
}
}
public function get_required_fields() {
$required = parent::get_required_fields();
$required[] = 'q.hidden';
return $required;
}
}
@@ -1,66 +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/>.
/**
* Base class for question bank columns that just contain an action icon.
*
* @package core_question
* @copyright 2009 Tim Hunt
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace core_question\bank;
defined('MOODLE_INTERNAL') || die();
/**
* Base class for question bank columns that just contain an action icon.
*
* @copyright 2009 Tim Hunt
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
* @todo MDL-72004 delete the class and add it to lib/db/renameclasses.php pointing to the plugin
*/
class edit_action_column extends menu_action_column_base {
protected $stredit;
protected $strview;
public function init() {
parent::init();
$this->stredit = get_string('editquestion', 'question');
$this->strview = get_string('view');
}
public function get_name() {
return 'editaction';
}
protected function get_url_icon_and_label(\stdClass $question): array {
if (!\question_bank::is_qtype_installed($question->qtype)) {
// It sometimes happens that people end up with junk questions
// in their question bank of a type that is no longer installed.
// We cannot do most actions on them, because that leads to errors.
return [null, null, null];
}
if (question_has_capability_on($question, 'edit')) {
return [$this->qbank->edit_question_moodle_url($question->id), 't/edit', $this->stredit];
} else if (question_has_capability_on($question, 'view')) {
return [$this->qbank->edit_question_moodle_url($question->id), 'i/info', $this->strview];
} else {
return [null, null, null];
}
}
}
-102
View File
@@ -1,102 +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/>.
/**
* A question bank column which gathers together all the actions into a menu.
*
* @package core_question
* @copyright 2019 The Open University
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace core_question\bank;
defined('MOODLE_INTERNAL') || die();
/**
* A question bank column which gathers together all the actions into a menu.
*
* This question bank column, if added to the question bank, will
* replace all of the other columns which implement the
* {@link menuable_action} interface and replace them with a single
* column containing an Edit menu.
*
* @copyright 2019 The Open University
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
* @todo MDL-72004 delete the class and add it to lib/db/renameclasses.php pointing to core_question/local/bank
*/
class edit_menu_column extends column_base {
/**
* @var menuable_action[]
*/
protected $actions;
/**
* Set up the list of actions that should be shown in the menu.
*
* This takes a list of column object (the list from a question
* bank view). It extracts all the ones that should go in the menu
* and stores them for later use. Then it returns the remaining columns.
*
* @param column_base[] $allcolumns a set of columns.
* @return column_base[] the non-action columns from the set.
*/
public function claim_menuable_columns($allcolumns) {
$remainingcolumns = [];
foreach ($allcolumns as $key => $column) {
if ($column instanceof menuable_action) {
$this->actions[$key] = $column;
} else {
$remainingcolumns[$key] = $column;
}
}
return $remainingcolumns;
}
protected function get_title() {
return get_string('actions');
}
public function get_name() {
return 'editmenu';
}
protected function display_content($question, $rowclasses) {
global $OUTPUT;
$menu = new \action_menu();
$menu->set_menu_trigger(get_string('edit'));
$menu->set_alignment(\action_menu::TL, \action_menu::BL);
foreach ($this->actions as $actioncolumn) {
$action = $actioncolumn->get_action_menu_link($question);
if ($action) {
$menu->add($action);
}
}
$qtypeactions = \question_bank::get_qtype($question->qtype, false)
->get_extra_question_bank_actions($question);
foreach ($qtypeactions as $action) {
$menu->add($action);
}
echo $OUTPUT->render($menu);
}
public function get_required_fields() {
return ['q.qtype'];
}
}
@@ -1,64 +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/>.
/**
* Question bank column export the question in Moodle XML format.
*
* @package core_question
* @copyright 2019 The Open University
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace core_question\bank;
defined('MOODLE_INTERNAL') || die();
/**
* Question bank column export the question in Moodle XML format.
*
* @copyright 2019 The Open University
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
* @todo MDL-72004 delete the class and add it to lib/db/renameclasses.php pointing to the plugin
*/
class export_xml_action_column extends menu_action_column_base {
/** @var string avoids repeated calls to get_string('duplicate'). */
protected $strexportasxml;
public function init() {
parent::init();
$this->strexportasxml = get_string('exportasxml', 'question');
}
public function get_name() {
return 'exportasxmlaction';
}
protected function get_url_icon_and_label(\stdClass $question): array {
if (!\question_bank::is_qtype_installed($question->qtype)) {
// It sometimes happens that people end up with junk questions
// in their question bank of a type that is no longer installed.
// We cannot do most actions on them, because that leads to errors.
return [null, null, null];
}
if (!question_has_capability_on($question, 'view')) {
return [null, null, null];
}
return [\qbank_exporttoxml\helper::question_get_export_single_question_url($question),
't/download', $this->strexportasxml];
}
}
@@ -1,71 +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/>.
/**
* Base class to make it easier to implement actions that are menuable_actions.
*
* @package core_question
* @copyright 2019 Tim Hunt
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace core_question\bank;
defined('MOODLE_INTERNAL') || die();
/**
* Base class to make it easier to implement actions that are menuable_actions.
*
* Use this class if your action is simple (defined by just a URL, label and icon).
* If your action is not simple enough to fit into the pattern that this
* class implements, then you will have to implement the menuable_action
* interface yourself.
*
* @copyright 2019 Tim Hunt
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
* @todo MDL-72004 delete the class and add it to lib/db/renameclasses.php pointing to core_question/local/bank
*/
abstract class menu_action_column_base extends action_column_base implements menuable_action {
/**
* Get the information required to display this action either as a menu item or a separate action column.
*
* If this action cannot apply to this question (e.g. because the user does not have
* permission, then return [null, null, null].
*
* @param \stdClass $question the row from the $question table, augmented with extra information.
* @return array with three elements.
* $url - the URL to perform the action.
* $icon - the icon for this action. E.g. 't/delete'.
* $label - text label to display in the UI (either in the menu, or as a tool-tip on the icon)
*/
abstract protected function get_url_icon_and_label(\stdClass $question): array;
protected function display_content($question, $rowclasses) {
[$url, $icon, $label] = $this->get_url_icon_and_label($question);
if ($url) {
$this->print_icon($icon, $label, $url);
}
}
public function get_action_menu_link(\stdClass $question): ?\action_menu_link {
[$url, $icon, $label] = $this->get_url_icon_and_label($question);
if (!$url) {
return null;
}
return new \action_menu_link_secondary($url, new \pix_icon($icon, ''), $label);
}
}
-57
View File
@@ -1,57 +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/>.
/**
* Interface to indicate that a question bank column can go in the action menu.
*
* @package core_question
* @copyright 2019 Tim Hunt
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace core_question\bank;
defined('MOODLE_INTERNAL') || die();
/**
* Interface to indicate that a question bank column can go in the action menu.
*
* If a question bank column implements this interface, and if the {@link edit_menu_column}
* is present in the question bank view, then the 'column' will be shown as an entry in the
* edit menu instead of as a separate column.
*
* Probably most columns that want to implement this will be subclasses of
* {@link action_column_base}, and most such columns should probably implement
* this interface.
*
* If your column is a simple action, you can probably save duplicated code by
* using the base class action_column_menuable as an easy way to implement both
* action_column_base and this interface.
*
* @copyright 2019 Tim Hunt
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
* @todo MDL-72004 delete the class and add it to lib/db/renameclasses.php pointing to core_question/local/bank
*/
interface menuable_action {
/**
* Return the appropriate action menu link, or null if it does not apply to this question.
*
* @param \stdClass $question data about the question being displayed in this row.
* @return \action_menu_link|null the action, if applicable to this question.
*/
public function get_action_menu_link(\stdClass $question): ?\action_menu_link;
}
@@ -1,75 +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/>.
/**
* A column type for the name of the question last modifier.
*
* @package core_question
* @copyright 2009 Tim Hunt
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace core_question\bank;
defined('MOODLE_INTERNAL') || die();
/**
* A column type for the name of the question last modifier.
*
* @copyright 2009 Tim Hunt
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
* @todo MDL-72004 delete the class and add it to lib/db/renameclasses.php pointing to the plugin
*/
class modifier_name_column extends column_base {
public function get_name() {
return 'modifiername';
}
protected function get_title() {
return get_string('lastmodifiedby', 'question');
}
protected function display_content($question, $rowclasses) {
if (!empty($question->modifierfirstname) && !empty($question->modifierlastname)) {
$u = new \stdClass();
$u = username_load_fields_from_object($u, $question, 'modifier');
$date = userdate($question->timemodified, get_string('strftimedatetime', 'langconfig'));
echo fullname($u) . '<br>' . \html_writer::tag('span', $date, array('class' => 'date'));
}
}
public function get_extra_joins() {
return array('um' => 'LEFT JOIN {user} um ON um.id = q.modifiedby');
}
public function get_required_fields() {
$allnames = \core_user\fields::get_name_fields();
$requiredfields = array();
foreach ($allnames as $allname) {
$requiredfields[] = 'um.' . $allname . ' AS modifier' . $allname;
}
$requiredfields[] = 'q.timemodified';
return $requiredfields;
}
public function is_sortable() {
return array(
'firstname' => array('field' => 'um.firstname', 'title' => get_string('firstname')),
'lastname' => array('field' => 'um.lastname', 'title' => get_string('lastname')),
'timemodified' => array('field' => 'q.timemodified', 'title' => get_string('date'))
);
}
}
@@ -1,84 +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/>.
/**
* Question bank columns for the preview action icon.
*
* @package core_question
* @copyright 2009 Tim Hunt
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace core_question\bank;
defined('MOODLE_INTERNAL') || die();
/**
* Question bank columns for the preview action icon.
*
* @copyright 2009 Tim Hunt
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
* @todo MDL-72004 delete the class and add it to lib/db/renameclasses.php pointing to the plugin
*/
class preview_action_column extends action_column_base implements menuable_action {
/**
* @var string store this lang string for performance.
*/
protected $strpreview;
public function init() {
parent::init();
$this->strpreview = get_string('preview');
}
public function get_name() {
return 'previewaction';
}
protected function display_content($question, $rowclasses) {
global $PAGE;
if (!\question_bank::is_qtype_installed($question->qtype)) {
// It sometimes happens that people end up with junk questions
// in their question bank of a type that is no longer installed.
// We cannot do most actions on them, because that leads to errors.
return;
}
if (question_has_capability_on($question, 'use')) {
echo $PAGE->get_renderer('core_question')->question_preview_link(
$question->id, $this->qbank->get_most_specific_context(), false);
}
}
public function get_action_menu_link(\stdClass $question): ?\action_menu_link {
if (!\question_bank::is_qtype_installed($question->qtype)) {
// It sometimes happens that people end up with junk questions
// in their question bank of a type that is no longer installed.
// We cannot do most actions on them, because that leads to errors.
return null;
}
if (!question_has_capability_on($question, 'use')) {
return null;
}
$context = $this->qbank->get_most_specific_context();
$url = question_preview_url($question->id, null, null, null, null, $context);
return new \action_menu_link_secondary($url, new \pix_icon('t/preview', ''),
$this->strpreview, ['target' => 'questionpreview']);
}
}
@@ -1,76 +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/>.
/**
* A column type for the name of the question name.
*
* @package core_question
* @copyright 2009 Tim Hunt
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace core_question\bank;
defined('MOODLE_INTERNAL') || die();
/**
* A column type for the name of the question name.
*
* @copyright 2009 Tim Hunt
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
* @todo MDL-72004 delete the class and add it to lib/db/renameclasses.php pointing to the plugin
*/
class question_name_column extends column_base {
protected $checkboxespresent = null;
public function get_name() {
return 'questionname';
}
protected function get_title() {
return get_string('question');
}
protected function label_for($question) {
if (is_null($this->checkboxespresent)) {
$this->checkboxespresent = $this->qbank->has_column('core_question\local\bank\checkbox_column');
}
if ($this->checkboxespresent) {
return 'checkq' . $question->id;
} else {
return '';
}
}
protected function display_content($question, $rowclasses) {
$labelfor = $this->label_for($question);
if ($labelfor) {
echo '<label for="' . $labelfor . '">';
}
echo format_string($question->name);
if ($labelfor) {
echo '</label>';
}
}
public function get_required_fields() {
return array('q.id', 'q.name');
}
public function is_sortable() {
return 'q.name';
}
}
@@ -1,90 +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/>.
/**
* A question bank column showing the question name with idnumber and tags.
*
* @package core_question
* @copyright 2019 The Open University
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace core_question\bank;
defined('MOODLE_INTERNAL') || die();
/**
* A question bank column showing the question name with idnumber and tags.
*
* @copyright 2019 The Open University
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
* @todo MDL-72004 delete the class and add it to lib/db/renameclasses.php pointing to the plugin
*/
class question_name_idnumber_tags_column extends question_name_column {
public function get_name() {
return 'qnameidnumbertags';
}
protected function display_content($question, $rowclasses) {
global $OUTPUT;
$layoutclasses = 'd-inline-flex flex-nowrap overflow-hidden w-100';
$labelfor = $this->label_for($question);
if ($labelfor) {
echo '<label for="' . $labelfor . '" class="' . $layoutclasses . '">';
$closetag = '</label>';
} else {
echo '<span class="' . $layoutclasses . '">';
$closetag = '</span>';
}
// Question name.
echo \html_writer::span(format_string($question->name), 'questionname flex-grow-1 flex-shrink-1 text-truncate');
// Question idnumber.
if ($question->idnumber !== null && $question->idnumber !== '') {
echo ' ' . \html_writer::span(
\html_writer::span(get_string('idnumber', 'question'), 'accesshide') . ' ' .
\html_writer::span(s($question->idnumber), 'badge badge-primary'), 'ml-1');
}
// Question tags.
if (!empty($question->tags)) {
$tags = \core_tag_tag::get_item_tags('core_question', 'question', $question->id);
echo $OUTPUT->tag_list($tags, null, 'd-inline flex-shrink-1 text-truncate ml-1', 0, null, true);
}
echo $closetag; // Computed above to ensure it matches.
}
public function get_required_fields() {
$fields = parent::get_required_fields();
$fields[] = 'q.idnumber';
return $fields;
}
public function is_sortable() {
return [
'name' => ['field' => 'q.name', 'title' => get_string('questionname', 'question')],
'idnumber' => ['field' => 'q.idnumber', 'title' => get_string('idnumber', 'question')],
];
}
public function load_additional_data(array $questions) {
parent::load_additional_data($questions);
parent::load_question_tags($questions);
}
}
@@ -1,72 +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/>.
/**
* A column type for the name of the question name.
*
* @package core_question
* @copyright 2009 Tim Hunt
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace core_question\bank;
defined('MOODLE_INTERNAL') || die();
/**
* A column type for the name of the question name.
*
* @copyright 2009 Tim Hunt
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
* @todo MDL-72004 delete the class and add it to lib/db/renameclasses.php pointing to the plugin
*/
class question_text_row extends row_base {
protected $formatoptions;
protected function init() {
$this->formatoptions = new \stdClass();
$this->formatoptions->noclean = true;
$this->formatoptions->para = false;
}
public function get_name() {
return 'questiontext';
}
protected function get_title() {
return get_string('questiontext', 'question');
}
protected function display_content($question, $rowclasses) {
$text = question_rewrite_question_preview_urls($question->questiontext, $question->id,
$question->contextid, 'question', 'questiontext', $question->id,
$question->contextid, 'core_question');
$text = format_text($text, $question->questiontextformat,
$this->formatoptions);
if ($text == '') {
$text = '&#160;';
}
echo $text;
}
public function get_extra_joins() {
return array('qc' => 'JOIN {question_categories} qc ON qc.id = q.category');
}
public function get_required_fields() {
return array('q.id', 'q.questiontext', 'q.questiontextformat', 'qc.contextid');
}
}
@@ -1,60 +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/>.
/**
* A column type for the name of the question type.
*
* @package core_question
* @copyright 2009 Tim Hunt
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace core_question\bank;
defined('MOODLE_INTERNAL') || die();
/**
* A column type for the name of the question type.
*
* @copyright 2009 Tim Hunt
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
* @todo MDL-72004 delete the class and add it to lib/db/renameclasses.php pointing to the plugin
*/
class question_type_column extends column_base {
public function get_name() {
return 'qtype';
}
protected function get_title() {
return get_string('qtypeveryshort', 'question');
}
protected function get_title_tip() {
return get_string('questiontype', 'question');
}
protected function display_content($question, $rowclasses) {
echo print_question_icon($question);
}
public function get_required_fields() {
return array('q.qtype');
}
public function is_sortable() {
return 'q.qtype';
}
}
@@ -1,323 +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/>.
/**
* A class for efficiently finds questions at random from the question bank.
*
* @package core_question
* @copyright 2015 The Open University
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace core_question\bank;
/**
* This class efficiently finds questions at random from the question bank.
*
* You can ask for questions at random one at a time. Each time you ask, you
* pass a category id, and whether to pick from that category and all subcategories
* or just that category.
*
* The number of teams each question has been used is tracked, and we will always
* return a question from among those elegible that has been used the fewest times.
* So, if there are questions that have not been used yet in the category asked for,
* one of those will be returned. However, within one instantiation of this class,
* we will never return a given question more than once, and we will never return
* questions passed into the constructor as $usedquestions.
*
* @copyright 2015 The Open University
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
* @todo MDL-72004 delete the class and add it to lib/db/renameclasses.php pointing to core_question/local/bank
*/
class random_question_loader {
/** @var \qubaid_condition which usages to consider previous attempts from. */
protected $qubaids;
/** @var array qtypes that cannot be used by random questions. */
protected $excludedqtypes;
/** @var array categoryid & include subcategories => num previous uses => questionid => 1. */
protected $availablequestionscache = array();
/**
* @var array questionid => num recent uses. Questions that have been used,
* but that is not yet recorded in the DB.
*/
protected $recentlyusedquestions;
/**
* Constructor.
* @param \qubaid_condition $qubaids the usages to consider when counting previous uses of each question.
* @param array $usedquestions questionid => number of times used count. If we should allow for
* further existing uses of a question in addition to the ones in $qubaids.
*/
public function __construct(\qubaid_condition $qubaids, array $usedquestions = array()) {
$this->qubaids = $qubaids;
$this->recentlyusedquestions = $usedquestions;
foreach (\question_bank::get_all_qtypes() as $qtype) {
if (!$qtype->is_usable_by_random()) {
$this->excludedqtypes[] = $qtype->name();
}
}
}
/**
* Pick a question at random from the given category, from among those with the fewest uses.
* If an array of tag ids are specified, then only the questions that are tagged with ALL those tags will be selected.
*
* It is up the the caller to verify that the cateogry exists. An unknown category
* behaves like an empty one.
*
* @param int $categoryid the id of a category in the question bank.
* @param bool $includesubcategories wether to pick a question from exactly
* that category, or that category and subcategories.
* @param array $tagids An array of tag ids. A question has to be tagged with all the provided tagids (if any)
* in order to be eligible for being picked.
* @return int|null the id of the question picked, or null if there aren't any.
*/
public function get_next_question_id($categoryid, $includesubcategories, $tagids = []) {
$this->ensure_questions_for_category_loaded($categoryid, $includesubcategories, $tagids);
$categorykey = $this->get_category_key($categoryid, $includesubcategories, $tagids);
if (empty($this->availablequestionscache[$categorykey])) {
return null;
}
reset($this->availablequestionscache[$categorykey]);
$lowestcount = key($this->availablequestionscache[$categorykey]);
reset($this->availablequestionscache[$categorykey][$lowestcount]);
$questionid = key($this->availablequestionscache[$categorykey][$lowestcount]);
$this->use_question($questionid);
return $questionid;
}
/**
* Get the key into {@link $availablequestionscache} for this combination of options.
* @param int $categoryid the id of a category in the question bank.
* @param bool $includesubcategories wether to pick a question from exactly
* that category, or that category and subcategories.
* @param array $tagids an array of tag ids.
* @return string the cache key.
*/
protected function get_category_key($categoryid, $includesubcategories, $tagids = []) {
if ($includesubcategories) {
$key = $categoryid . '|1';
} else {
$key = $categoryid . '|0';
}
if (!empty($tagids)) {
$key .= '|' . implode('|', $tagids);
}
return $key;
}
/**
* Populate {@link $availablequestionscache} for this combination of options.
* @param int $categoryid The id of a category in the question bank.
* @param bool $includesubcategories Whether to pick a question from exactly
* that category, or that category and subcategories.
* @param array $tagids An array of tag ids. If an array is provided, then
* only the questions that are tagged with ALL the provided tagids will be loaded.
*/
protected function ensure_questions_for_category_loaded($categoryid, $includesubcategories, $tagids = []) {
global $DB;
$categorykey = $this->get_category_key($categoryid, $includesubcategories, $tagids);
if (isset($this->availablequestionscache[$categorykey])) {
// Data is already in the cache, nothing to do.
return;
}
// Load the available questions from the question bank.
if ($includesubcategories) {
$categoryids = question_categorylist($categoryid);
} else {
$categoryids = array($categoryid);
}
list($extraconditions, $extraparams) = $DB->get_in_or_equal($this->excludedqtypes,
SQL_PARAMS_NAMED, 'excludedqtype', false);
$questionidsandcounts = \question_bank::get_finder()->get_questions_from_categories_and_tags_with_usage_counts(
$categoryids, $this->qubaids, 'q.qtype ' . $extraconditions, $extraparams, $tagids);
if (!$questionidsandcounts) {
// No questions in this category.
$this->availablequestionscache[$categorykey] = array();
return;
}
// Put all the questions with each value of $prevusecount in separate arrays.
$idsbyusecount = array();
foreach ($questionidsandcounts as $questionid => $prevusecount) {
if (isset($this->recentlyusedquestions[$questionid])) {
// Recently used questions are never returned.
continue;
}
$idsbyusecount[$prevusecount][] = $questionid;
}
// Now put that data into our cache. For each count, we need to shuffle
// questionids, and make those the keys of an array.
$this->availablequestionscache[$categorykey] = array();
foreach ($idsbyusecount as $prevusecount => $questionids) {
shuffle($questionids);
$this->availablequestionscache[$categorykey][$prevusecount] = array_combine(
$questionids, array_fill(0, count($questionids), 1));
}
ksort($this->availablequestionscache[$categorykey]);
}
/**
* Update the internal data structures to indicate that a given question has
* been used one more time.
*
* @param int $questionid the question that is being used.
*/
protected function use_question($questionid) {
if (isset($this->recentlyusedquestions[$questionid])) {
$this->recentlyusedquestions[$questionid] += 1;
} else {
$this->recentlyusedquestions[$questionid] = 1;
}
foreach ($this->availablequestionscache as $categorykey => $questionsforcategory) {
foreach ($questionsforcategory as $numuses => $questionids) {
if (!isset($questionids[$questionid])) {
continue;
}
unset($this->availablequestionscache[$categorykey][$numuses][$questionid]);
if (empty($this->availablequestionscache[$categorykey][$numuses])) {
unset($this->availablequestionscache[$categorykey][$numuses]);
}
}
}
}
/**
* Get the list of available question ids for the given criteria.
*
* @param int $categoryid The id of a category in the question bank.
* @param bool $includesubcategories Whether to pick a question from exactly
* that category, or that category and subcategories.
* @param array $tagids An array of tag ids. If an array is provided, then
* only the questions that are tagged with ALL the provided tagids will be loaded.
* @return int[] The list of question ids
*/
protected function get_question_ids($categoryid, $includesubcategories, $tagids = []) {
$this->ensure_questions_for_category_loaded($categoryid, $includesubcategories, $tagids);
$categorykey = $this->get_category_key($categoryid, $includesubcategories, $tagids);
$cachedvalues = $this->availablequestionscache[$categorykey];
$questionids = [];
foreach ($cachedvalues as $usecount => $ids) {
$questionids = array_merge($questionids, array_keys($ids));
}
return $questionids;
}
/**
* Check whether a given question is available in a given category. If so, mark it used.
* If an optional list of tag ids are provided, then the question must be tagged with
* ALL of the provided tags to be considered as available.
*
* @param int $categoryid the id of a category in the question bank.
* @param bool $includesubcategories wether to pick a question from exactly
* that category, or that category and subcategories.
* @param int $questionid the question that is being used.
* @param array $tagids An array of tag ids. Only the questions that are tagged with all the provided tagids can be available.
* @return bool whether the question is available in the requested category.
*/
public function is_question_available($categoryid, $includesubcategories, $questionid, $tagids = []) {
$this->ensure_questions_for_category_loaded($categoryid, $includesubcategories, $tagids);
$categorykey = $this->get_category_key($categoryid, $includesubcategories, $tagids);
foreach ($this->availablequestionscache[$categorykey] as $questionids) {
if (isset($questionids[$questionid])) {
$this->use_question($questionid);
return true;
}
}
return false;
}
/**
* Get the list of available questions for the given criteria.
*
* @param int $categoryid The id of a category in the question bank.
* @param bool $includesubcategories Whether to pick a question from exactly
* that category, or that category and subcategories.
* @param array $tagids An array of tag ids. If an array is provided, then
* only the questions that are tagged with ALL the provided tagids will be loaded.
* @param int $limit Maximum number of results to return.
* @param int $offset Number of items to skip from the begging of the result set.
* @param string[] $fields The fields to return for each question.
* @return \stdClass[] The list of question records
*/
public function get_questions(
$categoryid,
$includesubcategories,
$tagids = [],
$limit = 100,
$offset = 0,
$fields = []
) {
global $DB;
$questionids = $this->get_question_ids($categoryid, $includesubcategories, $tagids);
if (empty($questionids)) {
return [];
}
if (empty($fields)) {
// Return all fields.
$fieldsstring = '*';
} else {
$fieldsstring = implode(',', $fields);
}
return $DB->get_records_list(
'question',
'id',
$questionids,
'id',
$fieldsstring,
$offset,
$limit
);
}
/**
* Count the number of available questions for the given criteria.
*
* @param int $categoryid The id of a category in the question bank.
* @param bool $includesubcategories Whether to pick a question from exactly
* that category, or that category and subcategories.
* @param array $tagids An array of tag ids. If an array is provided, then
* only the questions that are tagged with ALL the provided tagids will be loaded.
* @return int The number of questions matching the criteria.
*/
public function count_questions($categoryid, $includesubcategories, $tagids = []) {
$questionids = $this->get_question_ids($categoryid, $includesubcategories, $tagids);
return count($questionids);
}
}
-53
View File
@@ -1,53 +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/>.
/**
* Base class for 'columns' that are actually displayed as a row following the main question row.
*
* @package core_question
* @copyright 2009 Tim Hunt
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace core_question\bank;
defined('MOODLE_INTERNAL') || die();
/**
* Base class for 'columns' that are actually displayed as a row following the main question row.
*
* @copyright 2009 Tim Hunt
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
* @todo MDL-72004 delete the class and add it to lib/db/renameclasses.php pointing to core_question/local/bank
*/
abstract class row_base extends column_base {
public function is_extra_row() {
return true;
}
protected function display_start($question, $rowclasses) {
if ($rowclasses) {
echo '<tr class="' . $rowclasses . '">' . "\n";
} else {
echo "<tr>\n";
}
echo '<td colspan="' . $this->qbank->get_column_count() . '" class="' . $this->get_name() . '">';
}
protected function display_end($question, $rowclasses) {
echo "</td></tr>\n";
}
}
@@ -122,7 +122,10 @@ class category_condition extends condition {
true, -1, false);
$displaydata['categoryselect'] = \html_writer::select($catmenu, 'category', $this->cat, [],
array('class' => 'searchoptions custom-select', 'id' => 'id_selectacategory'));
$displaydata['categorydesc'] = $this->print_category_info($this->category);
$displaydata['categorydesc'] = '';
if ($this->category) {
$displaydata['categorydesc'] = $this->print_category_info($this->category);
}
return $PAGE->get_renderer('core_question', 'bank')->render_category_condition($displaydata);
}
@@ -1,109 +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/>.
/**
* The question tags column subclass.
*
* @package core_question
* @copyright 2018 Simey Lameze <[email protected]>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace core_question\bank;
defined('MOODLE_INTERNAL') || die();
/**
* Action to add and remove tags to questions.
*
* @copyright 2018 Simey Lameze <[email protected]>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
* @todo MDL-72004 delete the class and add it to lib/db/renameclasses.php pointing to the plugin
*/
class tags_action_column extends action_column_base implements menuable_action {
/**
* @var string store this lang string for performance.
*/
protected $managetags;
public function init() {
parent::init();
// Removed for conflicting js calls.
// ...global $CFG;.
// ...if ($CFG->usetags) {.
// ...global $PAGE;.
// ...$PAGE->requires->js_call_amd('core_question/edit_tags', 'init', ['#questionscontainer']);.
// ...}.
$this->managetags = get_string('managetags', 'tag');
}
/**
* Return the name for this column.
*
* @return string
*/
public function get_name() {
return 'tagsaction';
}
/**
* Display tags column content.
*
* @param object $question The question database record.
* @param string $rowclasses
*/
protected function display_content($question, $rowclasses) {
global $OUTPUT;
if (\core_tag_tag::is_enabled('core_question', 'question') &&
question_has_capability_on($question, 'view')) {
[$url, $attributes] = $this->get_link_url_and_attributes($question);
echo \html_writer::link($url, $OUTPUT->pix_icon('t/tags',
$this->managetags), $attributes);
}
}
/**
* Helper used by display_content and get_action_menu_link.
*
* @param object $question the row from the $question table, augmented with extra information.
* @return array with two elements, \moodle_url and
* an array or data $attributes needed to make the JavaScript work.
*/
protected function get_link_url_and_attributes($question) {
$url = new \moodle_url($this->qbank->edit_question_url($question->id));
$attributes = [
'data-action' => 'edittags',
'data-cantag' => question_has_capability_on($question, 'tag'),
'data-contextid' => $this->qbank->get_most_specific_context()->id,
'data-questionid' => $question->id
];
return [$url, $attributes];
}
public function get_action_menu_link(\stdClass $question): ?\action_menu_link {
if (!\core_tag_tag::is_enabled('core_question', 'question') ||
!question_has_capability_on($question, 'view')) {
return null;
}
[$url, $attributes] = $this->get_link_url_and_attributes($question);
return new \action_menu_link_secondary($url, new \pix_icon('t/tags', ''),
$this->managetags, $attributes);
}
}
File diff suppressed because it is too large Load Diff
+1 -2
View File
@@ -170,7 +170,6 @@ class core_question_external extends external_api {
}
require_once($CFG->libdir . '/questionlib.php');
require_once($CFG->dirroot . '/question/type/tags_form.php');
$cantag = question_has_capability_on($question, 'tag');
$questioncontext = \context::instance_by_id($question->contextid);
@@ -182,7 +181,7 @@ class core_question_external extends external_api {
'contexts' => $contexts->all()
];
$mform = new \core_question\form\tags(null, $formoptions, 'post', '', null, $cantag, $data);
$mform = new \qbank_tagquestion\form\tags_form(null, $formoptions, 'post', '', null, $cantag, $data);
if ($validateddata = $mform->get_data()) {
if ($cantag) {
@@ -51,12 +51,11 @@ class edit_menu_column extends column_base {
*
* @param column_base[] $allcolumns a set of columns.
* @return column_base[] the non-action columns from the set.
* @todo MDL-72004 changes for class renaming.
*/
public function claim_menuable_columns($allcolumns): array {
$remainingcolumns = [];
foreach ($allcolumns as $key => $column) {
if ($column instanceof menuable_action || $column instanceof \core_question\bank\menuable_action) {
if ($column instanceof menuable_action) {
$this->actions[$key] = $column;
} else {
$remainingcolumns[$key] = $column;
+20 -40
View File
@@ -198,7 +198,6 @@ class view {
* Get the list of qbank plugins with available objects for features.
*
* @return array
* @todo MDL-72004 changes for class renaming.
*/
protected function get_question_bank_plugins(): array {
$questionbankclasscolumns = [];
@@ -223,16 +222,12 @@ class view {
foreach ($corequestionbankcolumns as $fullname) {
$shortname = $fullname;
if (!class_exists($fullname)) {
if (class_exists('core_question\\local\\bank\\' . $fullname)) {
$fullname = 'core_question\\local\\bank\\' . $fullname;
} else if (class_exists('core_question\\bank\\' . $fullname)) {
$fullname = 'core_question\\bank\\' . $fullname;
} else {
throw new \coding_exception("No such class exists: $fullname");
}
if (class_exists('core_question\\local\\bank\\' . $fullname)) {
$fullname = 'core_question\\local\\bank\\' . $fullname;
$questionbankclasscolumns[$shortname] = new $fullname($this);
} else {
$questionbankclasscolumns[$shortname] = '';
}
$questionbankclasscolumns[$shortname] = new $fullname($this);
}
$plugins = \core_component::get_plugin_list_with_class('qbank', 'plugin_feature', 'plugin_feature.php');
foreach ($plugins as $componentname => $plugin) {
@@ -271,6 +266,13 @@ class view {
$questionbankclasscolumns[$key] = $newpluginclasscolumn;
}
// Mitigate the error in case of any regression.
foreach ($questionbankclasscolumns as $shortname => $questionbankclasscolumn) {
if (empty($questionbankclasscolumn)){
unset($questionbankclasscolumns[$shortname]);
}
}
return $questionbankclasscolumns;
}
@@ -278,30 +280,15 @@ class view {
* Loads all the available columns.
*
* @return array
* @todo MDL-72004 changes for class renaming.
*/
protected function wanted_columns(): array {
global $CFG;
$this->requiredcolumns = [];
if (empty($CFG->questionbankcolumns)) {
$questionbankcolumns = $this->get_question_bank_plugins();
foreach ($questionbankcolumns as $classobject) {
$this->requiredcolumns[get_class($classobject)] = $classobject;
}
} else {
// Config overrides the array, but uses the deprecated classes.
$questionbankcolumns = explode(',', $CFG->questionbankcolumns);
foreach ($questionbankcolumns as $fullname) {
if (! class_exists($fullname)) {
if (class_exists('core_question\\bank\\' . $fullname)) {
$fullname = 'core_question\\bank\\' . $fullname;
} else {
throw new \coding_exception("No such class exists: $fullname");
}
}
$this->requiredcolumns[$fullname] = new $fullname($this);
$questionbankcolumns = $this->get_question_bank_plugins();
foreach ($questionbankcolumns as $classobject) {
if (empty($classobject)) {
continue;
}
$this->requiredcolumns[get_class($classobject)] = $classobject;
}
return $this->requiredcolumns;
@@ -333,12 +320,11 @@ class view {
*
* @param array $wanted Collection of column names
* @param string $heading The name of column that is set as heading
* @todo MDL-72004 changes for class renaming.
*/
protected function init_columns($wanted, $heading = ''): void {
// If we are using the edit menu column, allow it to absorb all the actions.
foreach ($wanted as $column) {
if ($column instanceof edit_menu_column || $column instanceof \core_question\bank\edit_menu_column) {
if ($column instanceof edit_menu_column) {
$wanted = $column->claim_menuable_columns($wanted);
break;
}
@@ -479,20 +465,15 @@ class view {
/**
* Default sort for question data.
* @return int[]
* @todo MDL-72004 changes for class renaming.
*/
protected function default_sort(): array {
$defaultsort = [];
if (class_exists('\\qbank_viewquestiontype\\question_type_column')) {
$sort = 'qbank_viewquestiontype\question_type_column';
} else {
$sort = 'core_question\bank\question_type_column';
}
$defaultsort[$sort] = 1;
if (class_exists('\\qbank_viewquestionname\\question_name_idnumber_tags_column')) {
$sort = 'qbank_viewquestionname\question_name_idnumber_tags_column';
} else {
$sort = 'core_question\bank\question_name_idnumber_tags_column';
}
$defaultsort[$sort . '-name'] = 1;
@@ -544,7 +525,6 @@ class view {
/**
* Create the SQL query to retrieve the indicated questions, based on
* \core_question\bank\search\condition filters.
* @todo MDL-72004 changes for class renaming and default sort.
*/
protected function build_query(): void {
// Get the required tables and fields.
@@ -878,8 +858,6 @@ class view {
if (\core\plugininfo\qbank::is_plugin_enabled('qbank_viewquestiontext')) {
echo $PAGE->get_renderer('core_question', 'bank')->render_showtext_checkbox($displaydata);
}
} else {
echo $PAGE->get_renderer('core_question', 'bank')->render_showtext_checkbox($displaydata);
}
}
@@ -1116,6 +1094,7 @@ class view {
*
* @deprecated since Moodle 4.0
* @see print_table()
* @todo Final deprecation of this function in moodle 4.4
*/
protected function start_table() {
debugging('Function start_table() is deprecated, please use print_table() instead.', DEBUG_DEVELOPER);
@@ -1131,6 +1110,7 @@ class view {
*
* @deprecated since Moodle 4.0
* @see print_table()
* @todo Final deprecation of this function in moodle 4.4
*/
protected function end_table() {
debugging('Function end_table() is deprecated, please use print_table() instead.', DEBUG_DEVELOPER);
-108
View File
@@ -1,108 +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/>.
/**
* The qbank_chooser renderable.
*
* @package core_question
* @copyright 2016 Frédéric Massart - FMCorz.net
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace core_question\output;
defined('MOODLE_INTERNAL') || die();
use context_course;
use core\output\chooser_section;
use lang_string;
use moodle_url;
use question_bank;
/**
* The qbank_chooser renderable class.
*
* @package core_question
* @copyright 2016 Frédéric Massart - FMCorz.net
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
* @deprecated since Moodle 4.0
* @see \qbank_editquestion\qbank_chooser
* @todo MDL-72004 delete the class and add it to lib/db/renameclasses.php pointing to the plugin
*/
class qbank_chooser extends \core\output\chooser {
/**
* Constructor.
*
* @param array $real The real question types.
* @param array $fake The fake question types.
* @param stdClass $course The course.
* @param array $hiddenparams Hidden parameters.
* @param context $context The relevant context.
*/
public function __construct($real, $fake, $course, $hiddenparams, $context) {
$sections = [];
$sections[] = new chooser_section('questions', new lang_string('questions', 'question'),
array_map(function($qtype) use ($context) {
return new qbank_chooser_item($qtype, $context);
}, $real));
if (!empty($fake)) {
$sections[] = new chooser_section('other', new lang_string('other'),
array_map(function ($qtype) use ($context) {
return new qbank_chooser_item($qtype, $context);
}, $fake));
}
parent::__construct(new moodle_url('/question/question.php'),
new lang_string('chooseqtypetoadd', 'question'), $sections, 'qtype');
$this->set_instructions(new lang_string('selectaqtypefordescription', 'question'));
$this->set_method('get');
$this->add_param('courseid', $course->id);
foreach ($hiddenparams as $k => $v) {
$this->add_param($k, $v);
}
}
/**
* Get an instance of the question bank chooser.
*
* @param stdClass $course The course.
* @param array $hiddenparams Hidden parameters.
* @param array|null $allowedqtypes Allowed question types.
* @return qbank_chooser
*/
public static function get($course, $hiddenparams, array $allowedqtypes = null) {
$realqtypes = array();
$fakeqtypes = array();
foreach (question_bank::get_creatable_qtypes() as $qtypename => $qtype) {
if ($allowedqtypes && !in_array($qtypename, $allowedqtypes)) {
continue;
}
if ($qtype->is_real_question_type()) {
$realqtypes[] = $qtype;
} else {
$fakeqtypes[] = $qtype;
}
}
return new static($realqtypes, $fakeqtypes, $course, $hiddenparams, context_course::instance($course->id));
}
}
@@ -1,59 +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/>.
/**
* The qbank_chooser_item renderable.
*
* @package core_question
* @copyright 2016 Frédéric Massart - FMCorz.net
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace core_question\output;
defined('MOODLE_INTERNAL') || die();
use lang_string;
use pix_icon;
/**
* The qbank_chooser_item renderable class.
*
* @package core_question
* @copyright 2016 Frédéric Massart - FMCorz.net
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
* @deprecated since Moodle 4.0
* @see \qbank_editquestion\qbank_chooser_item
* @todo MDL-72004 delete the class and add it to lib/db/renameclasses.php pointing to the plugin
*/
class qbank_chooser_item extends \core\output\chooser_item {
/**
* Constructor.
*
* @param object $qtype The question type.
* @param context $context The relevant context.
*/
public function __construct($qtype, $context) {
$icon = new pix_icon('icon', $qtype->local_name(), $qtype->plugin_name(), [
'class' => 'icon',
'title' => $qtype->local_name()
]);
$help = new lang_string('pluginnamesummary', $qtype->plugin_name());
parent::__construct($qtype->plugin_name(), $qtype->menu_name(), $qtype->name(), $icon, $help, $context);
}
}
+10 -154
View File
@@ -108,7 +108,7 @@ function question_is_only_child_of_top_category_in_context($categoryid) {
has been deprecated and moved to qbank_managecategories plugin,
Please use qbank_managecategories\helper::question_is_only_child_of_top_category_in_context() instead.',
DEBUG_DEVELOPER);
return \qbank_managecategories\helper::question_is_only_child_of_top_category_in_contextt($categoryid);
return \qbank_managecategories\helper::question_is_only_child_of_top_category_in_context($categoryid);
}
/**
@@ -140,151 +140,6 @@ function question_can_delete_cat($todelete) {
\qbank_managecategories\helper::question_can_delete_cat($todelete);
}
/**
* Base class for representing a column in a {@see question_bank_view}.
*
* @copyright 2009 Tim Hunt
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
* @deprecated since Moodle 2.7 MDL-40457
* @todo MDl-72004 delete the class alias, not done in MDL-71516 for any potential error from other plugins.
*/
class_alias('core_question\local\bank\column_base', 'question_bank_column_base', true);
/**
* A column with a checkbox for each question with name q{questionid}.
*
* @copyright 2009 Tim Hunt
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
* @deprecated since Moodle 2.7 MDL-40457
* @todo MDl-72004 delete the class alias, not done in MDL-71516 for any potential error from other plugins.
*/
class_alias('core_question\local\bank\checkbox_column', 'question_bank_checkbox_column', true);
/**
* A column type for the name of the question type.
*
* @copyright 2009 Tim Hunt
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
* @deprecated since Moodle 2.7 MDL-40457
* @todo MDl-72004 delete the class alias, not done in MDL-71516 for any potential error from other plugins.
*/
class_alias('qbank_viewquestiontype\question_type_column', 'question_bank_question_type_column', true);
/**
* A column type for the name of the question name.
*
* @copyright 2009 Tim Hunt
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
* @deprecated since Moodle 2.7 MDL-40457
* @todo MDl-72004 delete the class alias, not done in MDL-71516 for any potential error from other plugins.
*/
class_alias('qbank_viewquestionname\viewquestionname_column_helper', 'question_bank_question_name_column', true);
/**
* A column type for the name of the question creator.
*
* @copyright 2009 Tim Hunt
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
* @deprecated since Moodle 2.7 MDL-40457
* @todo MDl-72004 delete the class alias, not done in MDL-71516 for any potential error from other plugins.
*/
class_alias('qbank_viewcreator\creator_name_column', 'question_bank_creator_name_column', true);
/**
* A column type for the name of the question last modifier.
*
* @copyright 2009 Tim Hunt
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
* @deprecated since Moodle 2.7 MDL-40457
* @todo MDl-72004 delete the class alias, not done in MDL-71516 for any potential error from other plugins.
*/
class_alias('qbank_viewcreator\modifier_name_column', 'question_bank_modifier_name_column', true);
/**
* A base class for actions that are an icon that lets you manipulate the question in some way.
*
* @copyright 2009 Tim Hunt
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
* @deprecated since Moodle 2.7 MDL-40457
* @todo MDl-72004 delete the class alias, not done in MDL-71516 for any potential error from other plugins.
*/
class_alias('core_question\local\bank\action_column_base', 'question_bank_action_column_base', true);
/**
* Base class for question bank columns that just contain an action icon.
*
* @copyright 2009 Tim Hunt
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
* @deprecated since Moodle 2.7 MDL-40457
* @todo MDl-72004 delete the class alias, not done in MDL-71516 for any potential error from other plugins.
*/
class_alias('qbank_editquestion\edit_action_column', 'question_bank_edit_action_column', true);
/**
* Question bank column for the duplicate action icon.
*
* @copyright 2013 The Open University
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
* @deprecated since Moodle 2.7 MDL-40457
* @todo MDl-72004 delete the class alias, not done in MDL-71516 for any potential error from other plugins.
*/
class_alias('qbank_editquestion\copy_action_column', 'question_bank_copy_action_column', true);
/**
* Question bank columns for the preview action icon.
*
* @copyright 2009 Tim Hunt
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
* @deprecated since Moodle 2.7 MDL-40457
* @todo MDl-72004 delete the class alias, not done in MDL-71516 for any potential error from other plugins.
*/
class_alias('qbank_previewquestion\preview_action_column', 'question_bank_preview_action_column', true);
/**
* action to delete (or hide) a question, or restore a previously hidden question.
*
* @copyright 2009 Tim Hunt
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
* @deprecated since Moodle 2.7 MDL-40457
* @todo MDl-72004 delete the class alias, not done in MDL-71516 for any potential error from other plugins.
*/
class_alias('core_question\bank\delete_action_column', 'question_bank_delete_action_column', true);
/**
* Base class for 'columns' that are actually displayed as a row following the main question row.
*
* @copyright 2009 Tim Hunt
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
* @deprecated since Moodle 2.7 MDL-40457
* @todo MDl-72004 delete the class alias, not done in MDL-71516 for any potential error from other plugins.
*/
class_alias('core_question\local\bank\row_base', 'question_bank_row_base', true);
/**
* A column type for the name of the question name.
*
* @copyright 2009 Tim Hunt
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
* @deprecated since Moodle 2.7 MDL-40457
* @todo MDl-72004 delete the class alias, not done in MDL-71516 for any potential error from other plugins.
*/
class_alias('qbank_viewquestiontext\question_text_row', 'question_bank_question_text_row', true);
/**
* @copyright 2009 Tim Hunt
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
* @deprecated since Moodle 2.7 MDL-40457
* @todo MDl-72004 delete the class alias, not done in MDL-71516 for any potential error from other plugins.
*/
class_alias('core_question\local\bank\view', 'question_bank_view', true);
/**
* Common setup for all pages for editing questions.
* @param string $baseurl the name of the script calling this funciton. For examle 'qusetion/edit.php'.
@@ -322,7 +177,7 @@ function question_edit_setup($edittab, $baseurl, $requirecmid = false, $unused =
$params['qperpage'] = optional_param('qperpage', null, PARAM_INT);
// Question table sorting options.
for ($i = 1; $i <= question_bank_view::MAX_SORTS; $i++) {
for ($i = 1; $i <= core_question\local\bank\view::MAX_SORTS; $i++) {
$param = 'qbs' . $i;
if ($sort = optional_param($param, '', PARAM_TEXT)) {
$params[$param] = $sort;
@@ -371,7 +226,7 @@ function question_edit_setup($edittab, $baseurl, $requirecmid = false, $unused =
* 'qbs1' => PARAM_TEXT,
* 'qbs2' => PARAM_TEXT,
* 'qbs3' => PARAM_TEXT,
* ... and more qbs keys up to question_bank_view::MAX_SORTS ...
* ... and more qbs keys up to core_question\local\bank\view::MAX_SORTS ...
* ];
*
* @param string $edittab Code for this edit tab
@@ -481,7 +336,7 @@ function question_build_edit_resources($edittab, $baseurl, $params) {
// This need to occur after the override_active_url call above because
// these values change on the page request causing the URLs to mismatch
// when trying to work out the active node.
for ($i = 1; $i <= question_bank_view::MAX_SORTS; $i++) {
for ($i = 1; $i <= core_question\local\bank\view::MAX_SORTS; $i++) {
$param = 'qbs' . $i;
if (isset($params[$param])) {
$value = clean_param($params[$param], PARAM_TEXT);
@@ -637,12 +492,14 @@ function require_login_in_context($contextorid = null){
* those qtypes will be shown. Example value array('description', 'multichoice').
* @deprecated since Moodle 4.0
* @see \qbank_editquestion\editquestion_helper::print_choose_qtype_to_add_form()
* @todo MDL-72004 deprecate the function and add debugging message.
* @todo Final deprecation of this class in moodle 4.4 MDL-72438
*/
function print_choose_qtype_to_add_form($hiddenparams, array $allowedqtypes = null, $enablejs = true) {
debugging('Function print_choose_qtype_to_add_form() is deprecated,
please use \qbank_editquestion\editquestion_helper::print_choose_qtype_to_add_form() instead.', DEBUG_DEVELOPER);
global $CFG, $PAGE, $OUTPUT;
$chooser = core_question\output\qbank_chooser::get($PAGE->course, $hiddenparams, $allowedqtypes);
$chooser = \qbank_editquestion\qbank_chooser::get($PAGE->course, $hiddenparams, $allowedqtypes);
$renderer = $PAGE->get_renderer('question', 'bank');
return $renderer->render($chooser);
@@ -661,6 +518,7 @@ function print_choose_qtype_to_add_form($hiddenparams, array $allowedqtypes = nu
* @param bool $disabled if true, the button will be disabled.
* @deprecated since Moodle 4.0
* @see \qbank_editquestion\editquestion_helper::create_new_question_button()
* @todo Final deprecation of this class in moodle 4.4 MDL-72438
*/
function create_new_question_button($categoryid, $params, $caption, $tooltip = '', $disabled = false) {
debugging('Function create_new_question_button() has been deprecated and moved to bank/editquestion,
@@ -668,7 +526,7 @@ function create_new_question_button($categoryid, $params, $caption, $tooltip = '
global $CFG, $PAGE, $OUTPUT;
static $choiceformprinted = false;
$params['category'] = $categoryid;
$url = new moodle_url('/question/addquestion.php', $params);
$url = new moodle_url('/question/bank/editquestion/addquestion.php', $params);
echo $OUTPUT->single_button($url, $caption, 'get', array('disabled'=>$disabled, 'title'=>$tooltip));
if (!$choiceformprinted) {
@@ -678,5 +536,3 @@ function create_new_question_button($categoryid, $params, $caption, $tooltip = '
$choiceformprinted = true;
}
}
+3 -5
View File
@@ -50,13 +50,11 @@ class core_question_renderer extends plugin_renderer_base {
* If false, just show the icon.
* @deprecated since Moodle 4.0
* @see qbank_previewquestion\output\renderer
* @todo MDL-71679 uncomment the debugging message after implementing the changes in mod_quiz
* @todo Final deprecation on Moodle 4.4 MDL-72438
*/
public function question_preview_link($questionid, context $context, $showlabel) {
// Debugging message will be re-added after implementing the changes in mod_quiz.
// ...debugging('Function question_preview_link() has been deprecated and moved to qbank_previewquestion plugin,
// Please use qbank_previewquestion renderer.', DEBUG_DEVELOPER);.
debugging('Function question_preview_link() has been deprecated and moved to qbank_previewquestion plugin,
Please use qbank_previewquestion renderer.', DEBUG_DEVELOPER);
return $this->page->get_renderer('qbank_previewquestion')->question_preview_link(
$questionid, $context, $showlabel
@@ -351,7 +349,7 @@ class core_question_renderer extends plugin_renderer_base {
$params['returnurl'] = $params['returnurl']->out_as_local_url(false);
}
$params['id'] = $qa->get_question_id();
$editurl = new moodle_url('/question/question.php', $params);
$editurl = new moodle_url('/question/bank/editquestion/question.php', $params);
return html_writer::tag('div', html_writer::link(
$editurl, $this->pix_icon('t/edit', get_string('edit'), '', array('class' => 'iconsmall')) .
+1 -72
View File
@@ -21,78 +21,7 @@
* @subpackage questionbank
* @copyright 2007 Jamie Pratt [email protected]
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
defined('MOODLE_INTERNAL') || die();
require_once($CFG->libdir . '/formslib.php');
/**
* Form to export questions from the question bank.
*
* @copyright 2007 Jamie Pratt [email protected]
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
* @deprecated since Moodle 4.0 MDL-71573
* @see qbank_exportquestions\form\export_form
* @todo Final deprecation on Moodle 4.4 MDL-72438
*/
class question_export_form extends moodleform {
protected function definition() {
debugging('Class question_export_form in \core_question\export_form is deprecated,
please use core_question\bank\exportquestions\export_form instead.', DEBUG_DEVELOPER);
global $OUTPUT;
$mform = $this->_form;
$defaultcategory = $this->_customdata['defaultcategory'];
$contexts = $this->_customdata['contexts'];
// Choice of format, with help.
$mform->addElement('header', 'fileformat', get_string('fileformat', 'question'));
$fileformatnames = get_import_export_formats('export');
$radioarray = array();
$separators = array();
foreach ($fileformatnames as $shortname => $fileformatname) {
$radioarray[] = $mform->createElement('radio', 'format', '', $fileformatname, $shortname);
$separator = '';
if (get_string_manager()->string_exists('pluginname_help', 'qformat_' . $shortname)) {
$separator .= $OUTPUT->help_icon('pluginname', 'qformat_' . $shortname);
}
$separator .= '<div class="w-100"></div>';
$separators[] = $separator;
}
$radioarray[] = $mform->createElement('static', 'makelasthelpiconshowup', '');
$mform->addGroup($radioarray, "formatchoices", '', $separators, false);
$mform->addRule("formatchoices", null, 'required', null, 'client');
// Export options.
$mform->addElement('header', 'general', get_string('general', 'form'));
$mform->addElement('questioncategory', 'category', get_string('exportcategory', 'question'),
array('contexts' => $contexts, 'top' => true));
$mform->setDefault('category', $defaultcategory);
$mform->addHelpButton('category', 'exportcategory', 'question');
$categorygroup = array();
$categorygroup[] = $mform->createElement('checkbox', 'cattofile', '', get_string('tofilecategory', 'question'));
$categorygroup[] = $mform->createElement('checkbox', 'contexttofile', '', get_string('tofilecontext', 'question'));
$mform->addGroup($categorygroup, 'categorygroup', '', '', false);
$mform->disabledIf('categorygroup', 'cattofile', 'notchecked');
$mform->setDefault('cattofile', 1);
$mform->setDefault('contexttofile', 1);
// Set a template for the format select elements
$renderer = $mform->defaultRenderer();
$template = "{help} {element}\n";
$renderer->setGroupElementTemplate($template, 'format');
// Submit buttons.
$this->add_action_buttons(false, get_string('exportquestions', 'question'));
}
}
-79
View File
@@ -1,79 +0,0 @@
<?php
// This file is part of Stack - http://stack.maths.ed.ac.uk/
//
// Stack 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.
//
// Stack 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 Stack. If not, see <http://www.gnu.org/licenses/>.
/**
* Script to download the export of a single question.
*
* @copyright 2015 the Open University
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
require_once(__DIR__.'/../config.php');
require_once($CFG->libdir . '/questionlib.php');
require_once($CFG->dirroot . '/question/format/xml/format.php');
// Get the parameters from the URL.
$questionid = required_param('id', PARAM_INT);
$cmid = optional_param('cmid', 0, PARAM_INT);
$courseid = optional_param('courseid', 0, PARAM_INT);
$urlparams = ['id' => $questionid, 'sesskey' => sesskey()];
if ($cmid) {
$cm = get_coursemodule_from_id(null, $cmid);
require_login($cm->course, false, $cm);
$thiscontext = context_module::instance($cmid);
$urlparams['cmid'] = $cmid;
} else if ($courseid) {
require_login($courseid, false);
$thiscontext = context_course::instance($courseid);
$urlparams['courseid'] = $courseid;
} else {
print_error('missingcourseorcmid', 'question');
}
require_sesskey();
// Load the necessary data.
$contexts = new question_edit_contexts($thiscontext);
$questiondata = question_bank::load_question_data($questionid);
// Check permissions.
question_require_capability_on($questiondata, 'view');
// Initialise $PAGE. Nothing is output, so this does not really matter. Just avoids notices.
$nexturl = new moodle_url('/question/type/stack/questiontestrun.php', $urlparams);
$PAGE->set_url('/question/exportone.php', $urlparams);
$PAGE->set_heading($COURSE->fullname);
$PAGE->set_pagelayout('admin');
// Set up the export format.
$qformat = new qformat_xml();
$filename = question_default_export_filename($COURSE, $questiondata) .
$qformat->export_file_extension();
$qformat->setContexts($contexts->having_one_edit_tab_cap('export'));
$qformat->setCourse($COURSE);
$qformat->setQuestions([$questiondata]);
$qformat->setCattofile(false);
$qformat->setContexttofile(false);
// Do the export.
if (!$qformat->exportpreprocess()) {
send_file_not_found();
}
if (!$content = $qformat->exportprocess(true)) {
send_file_not_found();
}
send_file($content, $filename, 0, 0, true, true, $qformat->mime_type());
-149
View File
@@ -1,149 +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/>.
/**
* Defines the import questions form.
*
* @package moodlecore
* @subpackage questionbank
* @copyright 1999 onwards Martin Dougiamas {@link http://moodle.com}
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
require_once(__DIR__ . '/../config.php');
require_once($CFG->dirroot . '/question/editlib.php');
require_once($CFG->dirroot . '/question/import_form.php');
require_once($CFG->dirroot . '/question/format.php');
list($thispageurl, $contexts, $cmid, $cm, $module, $pagevars) =
question_edit_setup('import', '/question/import.php');
// get display strings
$txt = new stdClass();
$txt->importerror = get_string('importerror', 'question');
$txt->importquestions = get_string('importquestions', 'question');
list($catid, $catcontext) = explode(',', $pagevars['cat']);
if (!$category = $DB->get_record("question_categories", array('id' => $catid))) {
print_error('nocategory', 'question');
}
$categorycontext = context::instance_by_id($category->contextid);
$category->context = $categorycontext;
//this page can be called without courseid or cmid in which case
//we get the context from the category object.
if ($contexts === null) { // need to get the course from the chosen category
$contexts = new question_edit_contexts($categorycontext);
$thiscontext = $contexts->lowest();
if ($thiscontext->contextlevel == CONTEXT_COURSE){
require_login($thiscontext->instanceid, false);
} elseif ($thiscontext->contextlevel == CONTEXT_MODULE){
list($module, $cm) = get_module_from_cmid($thiscontext->instanceid);
require_login($cm->course, false, $cm);
}
$contexts->require_one_edit_tab_cap($edittab);
}
$PAGE->set_url($thispageurl);
$import_form = new question_import_form($thispageurl, array('contexts'=>$contexts->having_one_edit_tab_cap('import'),
'defaultcategory'=>$pagevars['cat']));
if ($import_form->is_cancelled()){
redirect($thispageurl);
}
//==========
// PAGE HEADER
//==========
$PAGE->set_title($txt->importquestions);
$PAGE->set_heading($COURSE->fullname);
echo $OUTPUT->header();
// Print horizontal nav if needed.
$renderer = $PAGE->get_renderer('core_question', 'bank');
echo $renderer->extra_horizontal_navigation();
// file upload form sumitted
if ($form = $import_form->get_data()) {
// file checks out ok
$fileisgood = false;
// work out if this is an uploaded file
// or one from the filesarea.
$realfilename = $import_form->get_new_filename('newfile');
$importfile = make_request_directory() . "/{$realfilename}";
if (!$result = $import_form->save_file('newfile', $importfile, true)) {
throw new moodle_exception('uploadproblem');
}
$formatfile = 'format/' . $form->format . '/format.php';
if (!is_readable($formatfile)) {
throw new moodle_exception('formatnotfound', 'question', '', $form->format);
}
require_once($formatfile);
$classname = 'qformat_' . $form->format;
$qformat = new $classname();
// load data into class
$qformat->setCategory($category);
$qformat->setContexts($contexts->having_one_edit_tab_cap('import'));
$qformat->setCourse($COURSE);
$qformat->setFilename($importfile);
$qformat->setRealfilename($realfilename);
$qformat->setMatchgrades($form->matchgrades);
$qformat->setCatfromfile(!empty($form->catfromfile));
$qformat->setContextfromfile(!empty($form->contextfromfile));
$qformat->setStoponerror($form->stoponerror);
// Do anything before that we need to
if (!$qformat->importpreprocess()) {
print_error('cannotimport', '', $thispageurl->out());
}
// Process the uploaded file
if (!$qformat->importprocess()) {
print_error('cannotimport', '', $thispageurl->out());
}
// In case anything needs to be done after
if (!$qformat->importpostprocess()) {
print_error('cannotimport', '', $thispageurl->out());
}
// Log the import into this category.
$eventparams = [
'contextid' => $qformat->category->contextid,
'other' => ['format' => $form->format, 'categoryid' => $qformat->category->id],
];
$event = \core\event\questions_imported::create($eventparams);
$event->trigger();
$params = $thispageurl->params() + array(
'category' => $qformat->category->id . ',' . $qformat->category->contextid);
echo $OUTPUT->continue_button(new moodle_url('edit.php', $params));
echo $OUTPUT->footer();
exit;
}
echo $OUTPUT->heading_with_help($txt->importquestions, 'importquestions', 'question');
/// Print upload form
$import_form->display();
echo $OUTPUT->footer();
+3 -136
View File
@@ -21,140 +21,7 @@
* @subpackage questionbank
* @copyright 2007 Jamie Pratt [email protected]
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
* @deprecated since Moodle 4.0 MDL-71585
* @see \qbank_importquestions\form\question_import_form
* @todo Final deprecation on Moodle 4.4 MDL-72438
*/
defined('MOODLE_INTERNAL') || die();
require_once($CFG->libdir . '/formslib.php');
/**
* Form to import questions into the question bank.
*
* @copyright 2007 Jamie Pratt [email protected]
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class question_import_form extends moodleform {
protected function definition() {
global $OUTPUT;
$mform = $this->_form;
$defaultcategory = $this->_customdata['defaultcategory'];
$contexts = $this->_customdata['contexts'];
// Choice of import format, with help icons.
$mform->addElement('header', 'fileformat', get_string('fileformat', 'question'));
$fileformatnames = get_import_export_formats('import');
$radioarray = array();
$separators = array();
foreach ($fileformatnames as $shortname => $fileformatname) {
$radioarray[] = $mform->createElement('radio', 'format', '', $fileformatname, $shortname);
$separator = '';
if (get_string_manager()->string_exists('pluginname_help', 'qformat_' . $shortname)) {
$separator .= $OUTPUT->help_icon('pluginname', 'qformat_' . $shortname);
}
$separator .= '<div class="w-100"></div>';
$separators[] = $separator;
}
$radioarray[] = $mform->createElement('static', 'makelasthelpiconshowup', '');
$mform->addGroup($radioarray, "formatchoices", '', $separators, false);
$mform->addRule("formatchoices", null, 'required', null, 'client');
// Import options.
$mform->addElement('header','general', get_string('general', 'form'));
$mform->addElement('questioncategory', 'category', get_string('importcategory', 'question'), compact('contexts'));
$mform->setDefault('category', $defaultcategory);
$mform->addHelpButton('category', 'importcategory', 'question');
$categorygroup = array();
$categorygroup[] = $mform->createElement('checkbox', 'catfromfile', '', get_string('getcategoryfromfile', 'question'));
$categorygroup[] = $mform->createElement('checkbox', 'contextfromfile', '', get_string('getcontextfromfile', 'question'));
$mform->addGroup($categorygroup, 'categorygroup', '', '', false);
$mform->disabledIf('categorygroup', 'catfromfile', 'notchecked');
$mform->setDefault('catfromfile', 1);
$mform->setDefault('contextfromfile', 1);
$matchgrades = array();
$matchgrades['error'] = get_string('matchgradeserror', 'question');
$matchgrades['nearest'] = get_string('matchgradesnearest', 'question');
$mform->addElement('select', 'matchgrades', get_string('matchgrades', 'question'), $matchgrades);
$mform->addHelpButton('matchgrades', 'matchgrades', 'question');
$mform->setDefault('matchgrades', 'error');
$mform->addElement('selectyesno', 'stoponerror', get_string('stoponerror', 'question'));
$mform->setDefault('stoponerror', 1);
$mform->addHelpButton('stoponerror', 'stoponerror', 'question');
// The file to import
$mform->addElement('header', 'importfileupload', get_string('importquestions', 'question'));
$mform->addElement('filepicker', 'newfile', get_string('import'));
$mform->addRule('newfile', null, 'required', null, 'client');
// Submit button.
$mform->addElement('submit', 'submitbutton', get_string('import'));
// Set a template for the format select elements
$renderer = $mform->defaultRenderer();
$template = "{help} {element}\n";
$renderer->setGroupElementTemplate($template, 'format');
}
/**
* Checks that a file has been uploaded, and that it is of a plausible type.
* @param array $data the submitted data.
* @param array $errors the errors so far.
* @return array the updated errors.
* @throws moodle_exception
*/
protected function validate_uploaded_file($data, $errors) {
if (empty($data['newfile'])) {
$errors['newfile'] = get_string('required');
return $errors;
}
$files = $this->get_draft_files('newfile');
if (!is_array($files) || count($files) < 1) {
$errors['newfile'] = get_string('required');
return $errors;
}
if (empty($data['format'])) {
$errors['format'] = get_string('required');
return $errors;
}
$formatfile = 'format/' . $data['format'] . '/format.php';
if (!is_readable($formatfile)) {
throw new moodle_exception('formatnotfound', 'question', '', $data['format']);
}
require_once($formatfile);
$classname = 'qformat_' . $data['format'];
$qformat = new $classname();
$file = reset($files);
if (!$qformat->can_import_file($file)) {
$a = new stdClass();
$a->actualtype = $file->get_mimetype();
$a->expectedtype = $qformat->mime_type();
$errors['newfile'] = get_string('importwrongfiletype', 'question', $a);
}
return $errors;
}
public function validation($data, $files) {
$errors = parent::validation($data, $files);
$errors = $this->validate_uploaded_file($data, $errors);
return $errors;
}
}
+1 -2
View File
@@ -43,7 +43,6 @@ function core_question_output_fragment_tags_form($args) {
if (!empty($args['id'])) {
global $CFG, $DB;
require_once($CFG->dirroot . '/question/type/tags_form.php');
require_once($CFG->libdir . '/questionlib.php');
$id = clean_param($args['id'], PARAM_INT);
$editingcontext = $args['context'];
@@ -88,7 +87,7 @@ function core_question_output_fragment_tags_form($args) {
];
$cantag = question_has_capability_on($question, 'tag');
$mform = new \core_question\form\tags(null, $formoptions, 'post', '', null, $cantag, $data);
$mform = new \qbank_tagquestion\form\tags_form(null, $formoptions, 'post', '', null, $cantag, $data);
$mform->set_data($data);
return $mform->render();
+1 -31
View File
@@ -21,37 +21,7 @@
* @subpackage questionbank
* @copyright 2008 The Open University
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
defined('MOODLE_INTERNAL') || die();
require_once($CFG->libdir . '/formslib.php');
/**
* Form for moving questions between categories.
*
* @copyright 2008 The Open University
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
* @deprecated since Moodle 4.0 MDL-71585
* @see qbank_managecategories\form\question_move_form
* @todo Final deprecation on Moodle 4.4 MDL-72438
*/
class question_move_form extends moodleform {
protected function definition() {
debugging('Class question_move_form in \core_question\move_form is deprecated,
please use qbank_managecategories\form\question_move_form instead.', DEBUG_DEVELOPER);
$mform = $this->_form;
$currentcat = $this->_customdata['currentcat'];
$contexts = $this->_customdata['contexts'];
$mform->addElement('questioncategory', 'category', get_string('category', 'question'), compact('contexts', 'currentcat'));
$this->add_action_buttons(true, get_string('categorymoveto', 'question'));
$mform->addElement('hidden', 'delete', $currentcat);
$mform->setType('delete', PARAM_INT);
}
}
-307
View File
@@ -1,307 +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 page displays a preview of a question
*
* The preview uses the option settings from the activity within which the question
* is previewed or the default settings if no activity is specified. The question session
* information is stored in the session as an array of subsequent states rather
* than in the database.
*
* @package moodlecore
* @subpackage questionengine
* @copyright Alex Smith {@link http://maths.york.ac.uk/serving_maths} and
* numerous contributors.
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
require_once(__DIR__ . '/../config.php');
require_once($CFG->libdir . '/questionlib.php');
require_once(__DIR__ . '/previewlib.php');
/**
* The maximum number of variants previewable. If there are more variants than this for a question
* then we only allow the selection of the first x variants.
* @var integer
*/
define('QUESTION_PREVIEW_MAX_VARIANTS', 100);
// Get and validate question id.
$id = required_param('id', PARAM_INT);
$question = question_bank::load_question($id);
// Were we given a particular context to run the question in?
// This affects things like filter settings, or forced theme or language.
if ($cmid = optional_param('cmid', 0, PARAM_INT)) {
$cm = get_coursemodule_from_id(false, $cmid);
require_login($cm->course, false, $cm);
$context = context_module::instance($cmid);
} else if ($courseid = optional_param('courseid', 0, PARAM_INT)) {
require_login($courseid);
$context = context_course::instance($courseid);
} else {
require_login();
$category = $DB->get_record('question_categories',
array('id' => $question->category), '*', MUST_EXIST);
$context = context::instance_by_id($category->contextid);
$PAGE->set_context($context);
// Note that in the other cases, require_login will set the correct page context.
}
question_require_capability_on($question, 'use');
$PAGE->set_pagelayout('popup');
// Get and validate display options.
$maxvariant = min($question->get_num_variants(), QUESTION_PREVIEW_MAX_VARIANTS);
$options = new qbank_previewquestion\question_preview_options($question);
$options->load_user_defaults();
$options->set_from_request();
$PAGE->set_url(question_preview_url($id, $options->behaviour, $options->maxmark,
$options, $options->variant, $context));
// Get and validate existing preview, or start a new one.
$previewid = optional_param('previewid', 0, PARAM_INT);
if ($previewid) {
try {
$quba = question_engine::load_questions_usage_by_activity($previewid);
} catch (Exception $e) {
// This may not seem like the right error message to display, but
// actually from the user point of view, it makes sense.
print_error('submissionoutofsequencefriendlymessage', 'question',
question_preview_url($question->id, $options->behaviour,
$options->maxmark, $options, $options->variant, $context), null, $e);
}
if ($quba->get_owning_context()->instanceid != $USER->id) {
print_error('notyourpreview', 'question');
}
$slot = $quba->get_first_question_number();
$usedquestion = $quba->get_question($slot, false);
if ($usedquestion->id != $question->id) {
print_error('questionidmismatch', 'question');
}
$question = $usedquestion;
$options->variant = $quba->get_variant($slot);
} else {
$quba = question_engine::make_questions_usage_by_activity(
'core_question_preview', context_user::instance($USER->id));
$quba->set_preferred_behaviour($options->behaviour);
$slot = $quba->add_question($question, $options->maxmark);
if ($options->variant) {
$options->variant = min($maxvariant, max(1, $options->variant));
} else {
$options->variant = rand(1, $maxvariant);
}
$quba->start_question($slot, $options->variant);
$transaction = $DB->start_delegated_transaction();
question_engine::save_questions_usage_by_activity($quba);
$transaction->allow_commit();
}
$options->behaviour = $quba->get_preferred_behaviour();
$options->maxmark = $quba->get_question_max_mark($slot);
// Create the settings form, and initialise the fields.
$optionsform = new preview_options_form(question_preview_form_url($question->id, $context, $previewid),
array('quba' => $quba, 'maxvariant' => $maxvariant));
$optionsform->set_data($options);
// Process change of settings, if that was requested.
if ($newoptions = $optionsform->get_submitted_data()) {
// Set user preferences.
$options->save_user_preview_options($newoptions);
if (!isset($newoptions->variant)) {
$newoptions->variant = $options->variant;
}
if (isset($newoptions->saverestart)) {
qbank_previewquestion\helper::restart_preview($previewid, $question->id, $newoptions, $context);
}
}
// Prepare a URL that is used in various places.
$actionurl = question_preview_action_url($question->id, $quba->get_id(), $options, $context);
// Process any actions from the buttons at the bottom of the form.
if (data_submitted() && confirm_sesskey()) {
try {
if (optional_param('restart', false, PARAM_BOOL)) {
qbank_previewquestion\helper::restart_preview($previewid, $question->id, $options, $context);
} else if (optional_param('fill', null, PARAM_BOOL)) {
$correctresponse = $quba->get_correct_response($slot);
if (!is_null($correctresponse)) {
$quba->process_action($slot, $correctresponse);
$transaction = $DB->start_delegated_transaction();
question_engine::save_questions_usage_by_activity($quba);
$transaction->allow_commit();
}
redirect($actionurl);
} else if (optional_param('finish', null, PARAM_BOOL)) {
$quba->process_all_actions();
$quba->finish_all_questions();
$transaction = $DB->start_delegated_transaction();
question_engine::save_questions_usage_by_activity($quba);
$transaction->allow_commit();
redirect($actionurl);
} else {
$quba->process_all_actions();
$transaction = $DB->start_delegated_transaction();
question_engine::save_questions_usage_by_activity($quba);
$transaction->allow_commit();
$scrollpos = optional_param('scrollpos', '', PARAM_RAW);
if ($scrollpos !== '') {
$actionurl->param('scrollpos', (int) $scrollpos);
}
redirect($actionurl);
}
} catch (question_out_of_sequence_exception $e) {
print_error('submissionoutofsequencefriendlymessage', 'question', $actionurl);
} catch (Exception $e) {
// This sucks, if we display our own custom error message, there is no way
// to display the original stack trace.
$debuginfo = '';
if (!empty($e->debuginfo)) {
$debuginfo = $e->debuginfo;
}
print_error('errorprocessingresponses', 'question', $actionurl,
$e->getMessage(), $debuginfo);
}
}
if ($question->length) {
$displaynumber = '1';
} else {
$displaynumber = 'i';
}
$restartdisabled = array();
$finishdisabled = array();
$filldisabled = array();
if ($quba->get_question_state($slot)->is_finished()) {
$finishdisabled = array('disabled' => 'disabled');
$filldisabled = array('disabled' => 'disabled');
}
// If question type cannot give us a correct response, disable this button.
if (is_null($quba->get_correct_response($slot))) {
$filldisabled = array('disabled' => 'disabled');
}
if (!$previewid) {
$restartdisabled = array('disabled' => 'disabled');
}
// Prepare technical info to be output.
$qa = $quba->get_question_attempt($slot);
$technical = array();
$technical[] = get_string('behaviourbeingused', 'question',
question_engine::get_behaviour_name($qa->get_behaviour_name()));
$technical[] = get_string('technicalinfominfraction', 'question', $qa->get_min_fraction());
$technical[] = get_string('technicalinfomaxfraction', 'question', $qa->get_max_fraction());
$technical[] = get_string('technicalinfovariant', 'question', $qa->get_variant());
$technical[] = get_string('technicalinfoquestionsummary', 'question', s($qa->get_question_summary()));
$technical[] = get_string('technicalinforightsummary', 'question', s($qa->get_right_answer_summary()));
$technical[] = get_string('technicalinforesponsesummary', 'question', s($qa->get_response_summary()));
$technical[] = get_string('technicalinfostate', 'question', '' . $qa->get_state());
// Start output.
$title = get_string('previewquestion', 'question', format_string($question->name));
$headtags = question_engine::initialise_js() . $quba->render_question_head_html($slot);
$PAGE->set_title($title);
$PAGE->set_heading($title);
echo $OUTPUT->header();
// Start the question form.
echo html_writer::start_tag('form', array('method' => 'post', 'action' => $actionurl,
'enctype' => 'multipart/form-data', 'id' => 'responseform'));
echo html_writer::start_tag('div');
echo html_writer::empty_tag('input', array('type' => 'hidden', 'name' => 'sesskey', 'value' => sesskey()));
echo html_writer::empty_tag('input', array('type' => 'hidden', 'name' => 'slots', 'value' => $slot));
echo html_writer::empty_tag('input', array('type' => 'hidden', 'name' => 'scrollpos', 'value' => '', 'id' => 'scrollpos'));
echo html_writer::end_tag('div');
// Output the question.
echo $quba->render_question($slot, $options, $displaynumber);
// Finish the question form.
echo html_writer::start_tag('div', array('id' => 'previewcontrols', 'class' => 'controls'));
echo html_writer::empty_tag('input', $restartdisabled + array('type' => 'submit',
'name' => 'restart', 'value' => get_string('restart', 'question'), 'class' => 'btn btn-secondary mr-1 mb-1'));
echo html_writer::empty_tag('input', $finishdisabled + array('type' => 'submit',
'name' => 'save', 'value' => get_string('save', 'question'), 'class' => 'btn btn-secondary mr-1 mb-1',
'id' => 'id_save_question_preview'));
echo html_writer::empty_tag('input', $filldisabled + array('type' => 'submit',
'name' => 'fill', 'value' => get_string('fillincorrect', 'question'), 'class' => 'btn btn-secondary mr-1 mb-1'));
echo html_writer::empty_tag('input', $finishdisabled + array('type' => 'submit',
'name' => 'finish', 'value' => get_string('submitandfinish', 'question'), 'class' => 'btn btn-secondary mr-1 mb-1',
'id' => 'id_finish_question_preview'));
echo html_writer::end_tag('div');
echo html_writer::end_tag('form');
// Output the technical info.
print_collapsible_region_start('', 'techinfo', get_string('technicalinfo', 'question'),
'core_question_preview_techinfo_collapsed', true, false, $OUTPUT->help_icon('technicalinfo', 'question'));
foreach ($technical as $info) {
echo html_writer::tag('p', $info, array('class' => 'notifytiny'));
}
print_collapsible_region_end();
// Output a link to export this single question.
if (question_has_capability_on($question, 'view')) {
if (class_exists('qbank_exporttoxml\\helper')) {
if (\core\plugininfo\qbank::is_plugin_enabled('qbank_exporttoxml')) {
$exportfunction = '\\qbank_exporttoxml\\helper::question_get_export_single_question_url';
echo html_writer::link($exportfunction($question),
get_string('exportonequestion', 'question'));
}
} else {
$exportfunction = 'question_get_export_single_question_url';
echo html_writer::link($exportfunction($question),
get_string('exportonequestion', 'question'));
}
}
// Log the preview of this question.
$event = \core\event\question_viewed::create_from_question_instance($question, $context);
$event->trigger();
// Display the settings form.
$optionsform->display();
$PAGE->requires->js_module('core_question_engine');
$PAGE->requires->strings_for_js(array(
'closepreview',
), 'question');
$PAGE->requires->yui_module('moodle-question-preview', 'M.question.preview.init');
$PAGE->requires->js_call_amd('core_form/submit', 'init', ['id_save_question_preview']);
$PAGE->requires->js_call_amd('core_form/submit', 'init', ['id_finish_question_preview']);
echo $OUTPUT->footer();
+1 -200
View File
@@ -21,211 +21,12 @@
* @subpackage questionengine
* @copyright 2010 The Open University
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
defined('MOODLE_INTERNAL') || die();
require_once($CFG->libdir . '/formslib.php');
/**
* Settings form for the preview options.
*
* @copyright 2009 The Open University
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
* @deprecated since Moodle 4.0
* @see qbank_previewquestion\form\preview_options_form
* @todo MDL-71679 class renaming
*/
class preview_options_form extends moodleform {
public function definition() {
debugging('Class preview_options_form has been deprecated and moved to qbank_previewquestion plugin,
please use qbank_previewquestion\form\preview_options_form instead.', DEBUG_DEVELOPER);
$mform = $this->_form;
$hiddenofvisible = array(
question_display_options::HIDDEN => get_string('notshown', 'question'),
question_display_options::VISIBLE => get_string('shown', 'question'),
);
$mform->addElement('header', 'attemptoptionsheader', get_string('attemptoptions', 'question'));
$behaviours = question_engine::get_behaviour_options(
$this->_customdata['quba']->get_preferred_behaviour());
$mform->addElement('select', 'behaviour',
get_string('howquestionsbehave', 'question'), $behaviours);
$mform->addHelpButton('behaviour', 'howquestionsbehave', 'question');
$mform->addElement('float', 'maxmark', get_string('markedoutof', 'question'),
array('size' => '5'));
if ($this->_customdata['maxvariant'] > 1) {
$variants = range(1, $this->_customdata['maxvariant']);
$mform->addElement('select', 'variant', get_string('questionvariant', 'question'),
array_combine($variants, $variants));
}
$mform->setType('variant', PARAM_INT);
$mform->addElement('submit', 'saverestart',
get_string('restartwiththeseoptions', 'question'));
$mform->addElement('header', 'displayoptionsheader', get_string('displayoptions', 'question'));
$mform->addElement('select', 'correctness', get_string('whethercorrect', 'question'),
$hiddenofvisible);
$marksoptions = array(
question_display_options::HIDDEN => get_string('notshown', 'question'),
question_display_options::MAX_ONLY => get_string('showmaxmarkonly', 'question'),
question_display_options::MARK_AND_MAX => get_string('showmarkandmax', 'question'),
);
$mform->addElement('select', 'marks', get_string('marks', 'question'), $marksoptions);
$mform->addElement('select', 'markdp', get_string('decimalplacesingrades', 'question'),
question_engine::get_dp_options());
$mform->addElement('select', 'feedback',
get_string('specificfeedback', 'question'), $hiddenofvisible);
$mform->addElement('select', 'generalfeedback',
get_string('generalfeedback', 'question'), $hiddenofvisible);
$mform->addElement('select', 'rightanswer',
get_string('rightanswer', 'question'), $hiddenofvisible);
$mform->addElement('select', 'history',
get_string('responsehistory', 'question'), $hiddenofvisible);
$mform->addElement('submit', 'saveupdate',
get_string('updatedisplayoptions', 'question'));
}
}
/**
* Displays question preview options as default and set the options.
*
* Setting default, getting and setting user preferences in question preview options.
*
* @copyright 2010 The Open University
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
* @deprecated since Moodle 4.0
* @see qbank_previewquestion\output\question_preview_options
* @todo MDL-71679 class renaming
*/
class question_preview_options extends question_display_options {
/** @var string the behaviour to use for this preview. */
public $behaviour;
/** @var number the maximum mark to use for this preview. */
public $maxmark;
/** @var int the variant of the question to preview. */
public $variant;
/** @var string prefix to append to field names to get user_preference names. */
const OPTIONPREFIX = 'question_preview_options_';
/**
* Constructor.
* @param stdClass $question
*/
public function __construct($question) {
debugging('Class question_preview_options has been deprecated and moved to qbank_previewquestion plugin,
please use qbank_previewquestion\question_preview_options instead.', DEBUG_DEVELOPER);
$this->behaviour = 'deferredfeedback';
$this->maxmark = $question->defaultmark;
$this->variant = null;
$this->correctness = self::VISIBLE;
$this->marks = self::MARK_AND_MAX;
$this->markdp = get_config('quiz', 'decimalpoints');
$this->feedback = self::VISIBLE;
$this->numpartscorrect = $this->feedback;
$this->generalfeedback = self::VISIBLE;
$this->rightanswer = self::VISIBLE;
$this->history = self::HIDDEN;
$this->flags = self::HIDDEN;
$this->manualcomment = self::HIDDEN;
}
/**
* @return array names of the options we store in the user preferences table.
*/
protected function get_user_pref_fields() {
return array('behaviour', 'correctness', 'marks', 'markdp', 'feedback',
'generalfeedback', 'rightanswer', 'history');
}
/**
* @return array names and param types of the options we read from the request.
*/
protected function get_field_types() {
return array(
'behaviour' => PARAM_ALPHA,
'maxmark' => PARAM_LOCALISEDFLOAT,
'variant' => PARAM_INT,
'correctness' => PARAM_BOOL,
'marks' => PARAM_INT,
'markdp' => PARAM_INT,
'feedback' => PARAM_BOOL,
'generalfeedback' => PARAM_BOOL,
'rightanswer' => PARAM_BOOL,
'history' => PARAM_BOOL,
);
}
/**
* Load the value of the options from the user_preferences table.
*/
public function load_user_defaults() {
$defaults = get_config('question_preview');
foreach ($this->get_user_pref_fields() as $field) {
$this->$field = get_user_preferences(
self::OPTIONPREFIX . $field, $defaults->$field);
}
$this->numpartscorrect = $this->feedback;
}
/**
* Save a change to the user's preview options to the database.
* @param object $newoptions
*/
public function save_user_preview_options($newoptions) {
foreach ($this->get_user_pref_fields() as $field) {
if (isset($newoptions->$field)) {
set_user_preference(self::OPTIONPREFIX . $field, $newoptions->$field);
}
}
}
/**
* Set the value of any fields included in the request.
*/
public function set_from_request() {
foreach ($this->get_field_types() as $field => $type) {
$this->$field = optional_param($field, $this->$field, $type);
}
$this->numpartscorrect = $this->feedback;
}
/**
* @return string URL fragment. Parameters needed in the URL when continuing
* this preview.
*/
public function get_url_params() {
$params = array();
foreach ($this->get_field_types() as $field => $notused) {
if ($field == 'behaviour' || $field == 'maxmark' || is_null($this->$field)) {
continue;
}
$params[$field] = $this->$field;
}
return $params;
}
}
use qbank_previewquestion\question_preview_options;
/**
* Called via pluginfile.php -> question_pluginfile to serve files belonging to
-346
View File
@@ -1,346 +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/>.
/**
* Page for editing questions.
*
* @package moodlecore
* @subpackage questionbank
* @copyright 1999 onwards Martin Dougiamas {@link http://moodle.com}
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
require_once(__DIR__ . '/../config.php');
require_once(__DIR__ . '/editlib.php');
require_once($CFG->libdir . '/filelib.php');
require_once($CFG->libdir . '/formslib.php');
// Read URL parameters telling us which question to edit.
$id = optional_param('id', 0, PARAM_INT); // question id
$makecopy = optional_param('makecopy', 0, PARAM_BOOL);
$qtype = optional_param('qtype', '', PARAM_COMPONENT);
$categoryid = optional_param('category', 0, PARAM_INT);
$cmid = optional_param('cmid', 0, PARAM_INT);
$courseid = optional_param('courseid', 0, PARAM_INT);
$wizardnow = optional_param('wizardnow', '', PARAM_ALPHA);
$originalreturnurl = optional_param('returnurl', 0, PARAM_LOCALURL);
$appendqnumstring = optional_param('appendqnumstring', '', PARAM_ALPHA);
$inpopup = optional_param('inpopup', 0, PARAM_BOOL);
$scrollpos = optional_param('scrollpos', 0, PARAM_INT);
$url = new moodle_url('/question/question.php');
if ($id !== 0) {
$url->param('id', $id);
}
if ($makecopy) {
$url->param('makecopy', $makecopy);
}
if ($qtype !== '') {
$url->param('qtype', $qtype);
}
if ($categoryid !== 0) {
$url->param('category', $categoryid);
}
if ($cmid !== 0) {
$url->param('cmid', $cmid);
}
if ($courseid !== 0) {
$url->param('courseid', $courseid);
}
if ($wizardnow !== '') {
$url->param('wizardnow', $wizardnow);
}
if ($originalreturnurl !== 0) {
$url->param('returnurl', $originalreturnurl);
}
if ($appendqnumstring !== '') {
$url->param('appendqnumstring', $appendqnumstring);
}
if ($inpopup !== 0) {
$url->param('inpopup', $inpopup);
}
if ($scrollpos) {
$url->param('scrollpos', $scrollpos);
}
$PAGE->set_url($url);
if ($cmid) {
$questionbankurl = new moodle_url('/question/edit.php', array('cmid' => $cmid));
} else {
$questionbankurl = new moodle_url('/question/edit.php', array('courseid' => $courseid));
}
navigation_node::override_active_url($questionbankurl);
if ($originalreturnurl) {
if (strpos($originalreturnurl, '/') !== 0) {
throw new coding_exception("returnurl must be a local URL starting with '/'. $originalreturnurl was given.");
}
$returnurl = new moodle_url($originalreturnurl);
} else {
$returnurl = $questionbankurl;
}
if ($scrollpos) {
$returnurl->param('scrollpos', $scrollpos);
}
if ($cmid){
list($module, $cm) = get_module_from_cmid($cmid);
require_login($cm->course, false, $cm);
$thiscontext = context_module::instance($cmid);
} elseif ($courseid) {
require_login($courseid, false);
$thiscontext = context_course::instance($courseid);
$module = null;
$cm = null;
} else {
print_error('missingcourseorcmid', 'question');
}
$contexts = new question_edit_contexts($thiscontext);
$PAGE->set_pagelayout('admin');
if (optional_param('addcancel', false, PARAM_BOOL)) {
redirect($returnurl);
}
if ($id) {
if (!$question = $DB->get_record('question', array('id' => $id))) {
print_error('questiondoesnotexist', 'question', $returnurl);
}
// We can use $COURSE here because it's been initialised as part of the
// require_login above. Passing it as the third parameter tells the function
// to filter the course tags by that course.
get_question_options($question, true, [$COURSE]);
} else if ($categoryid && $qtype) { // only for creating new questions
$question = new stdClass();
$question->category = $categoryid;
$question->qtype = $qtype;
$question->createdby = $USER->id;
// Check that users are allowed to create this question type at the moment.
if (!question_bank::qtype_enabled($qtype)) {
print_error('cannotenable', 'question', $returnurl, $qtype);
}
} else if ($categoryid) {
// Category, but no qtype. They probably came from the addquestion.php
// script without choosing a question type. Send them back.
$addurl = new moodle_url('/question/addquestion.php', $url->params());
$addurl->param('validationerror', 1);
redirect($addurl);
} else {
print_error('notenoughdatatoeditaquestion', 'question', $returnurl);
}
$qtypeobj = question_bank::get_qtype($question->qtype);
if (isset($question->categoryobject)) {
$category = $question->categoryobject;
} else {
// Validate the question category.
if (!$category = $DB->get_record('question_categories', array('id' => $question->category))) {
print_error('categorydoesnotexist', 'question', $returnurl);
}
}
// Check permissions
$question->formoptions = new stdClass();
$categorycontext = context::instance_by_id($category->contextid);
$question->contextid = $category->contextid;
$addpermission = has_capability('moodle/question:add', $categorycontext);
if ($id) {
$question->formoptions->canedit = question_has_capability_on($question, 'edit');
$question->formoptions->canmove = $addpermission && question_has_capability_on($question, 'move');
$question->formoptions->cansaveasnew = $addpermission &&
(question_has_capability_on($question, 'view') || $question->formoptions->canedit);
$question->formoptions->repeatelements = $question->formoptions->canedit || $question->formoptions->cansaveasnew;
$formeditable = $question->formoptions->canedit || $question->formoptions->cansaveasnew || $question->formoptions->canmove;
if (!$formeditable) {
question_require_capability_on($question, 'view');
}
if ($makecopy) {
// If we are duplicating a question, add some indication to the question name.
$question->name = get_string('questionnamecopy', 'question', $question->name);
$question->idnumber = core_question_find_next_unused_idnumber($question->idnumber, $category->id);
$question->beingcopied = true;
}
} else { // creating a new question
$question->formoptions->canedit = question_has_capability_on($question, 'edit');
$question->formoptions->canmove = (question_has_capability_on($question, 'move') && $addpermission);
$question->formoptions->cansaveasnew = false;
$question->formoptions->repeatelements = true;
$formeditable = true;
require_capability('moodle/question:add', $categorycontext);
}
$question->formoptions->mustbeusable = (bool) $appendqnumstring;
// Validate the question type.
$PAGE->set_pagetype('question-type-' . $question->qtype);
// Create the question editing form.
if ($wizardnow !== '') {
$mform = $qtypeobj->next_wizard_form('question.php', $question, $wizardnow, $formeditable);
} else {
$mform = $qtypeobj->create_editing_form('question.php', $question, $category, $contexts, $formeditable);
}
$toform = fullclone($question); // send the question object and a few more parameters to the form
$toform->category = "{$category->id},{$category->contextid}";
$toform->scrollpos = $scrollpos;
if ($formeditable && $id){
$toform->categorymoveto = $toform->category;
}
$toform->appendqnumstring = $appendqnumstring;
$toform->returnurl = $originalreturnurl;
$toform->makecopy = $makecopy;
if ($cm !== null){
$toform->cmid = $cm->id;
$toform->courseid = $cm->course;
} else {
$toform->courseid = $COURSE->id;
}
$toform->inpopup = $inpopup;
$mform->set_data($toform);
if ($mform->is_cancelled()) {
if ($inpopup) {
close_window();
} else {
redirect($returnurl);
}
} else if ($fromform = $mform->get_data()) {
// If we are saving as a copy, break the connection to the old question.
if ($makecopy) {
$question->id = 0;
$question->hidden = 0; // Copies should not be hidden.
}
/// Process the combination of usecurrentcat, categorymoveto and category form
/// fields, so the save_question method only has to consider $fromform->category
if (!empty($fromform->usecurrentcat)) {
// $fromform->category is the right category to save in.
} else {
if (!empty($fromform->categorymoveto)) {
$fromform->category = $fromform->categorymoveto;
} else {
// $fromform->category is the right category to save in.
}
}
/// If we are moving a question, check we have permission to move it from
/// whence it came. (Where we are moving to is validated by the form.)
list($newcatid, $newcontextid) = explode(',', $fromform->category);
if (!empty($question->id) && $newcatid != $question->category) {
$contextid = $newcontextid;
question_require_capability_on($question, 'move');
} else {
$contextid = $category->contextid;
}
// Ensure we redirect back to the category the question is being saved into.
$returnurl->param('category', $fromform->category);
// We are actually saving the question.
if (!empty($question->id)) {
question_require_capability_on($question, 'edit');
} else {
require_capability('moodle/question:add', context::instance_by_id($contextid));
if (!empty($fromform->makecopy) && !$question->formoptions->cansaveasnew) {
print_error('nopermissions', '', '', 'edit');
}
}
// If this is a new question, save defaults for user in user_preferences table.
if (empty($question->id)) {
$qtypeobj->save_defaults_for_new_questions($fromform);
}
$question = $qtypeobj->save_question($question, $fromform);
if (isset($fromform->tags)) {
// If we have any question context level tags then set those tags now.
core_tag_tag::set_item_tags('core_question', 'question', $question->id,
context::instance_by_id($contextid), $fromform->tags, 0);
}
if (isset($fromform->coursetags)) {
// If we have and course context level tags then set those now.
core_tag_tag::set_item_tags('core_question', 'question', $question->id,
context_course::instance($fromform->courseid), $fromform->coursetags, 0);
}
// Purge this question from the cache.
question_bank::notify_question_edited($question->id);
// If we are saving and continuing to edit the question.
if (!empty($fromform->updatebutton)) {
$url->param('id', $question->id);
$url->remove_params('makecopy');
redirect($url);
}
if ($qtypeobj->finished_edit_wizard($fromform)) {
if ($inpopup) {
echo $OUTPUT->notification(get_string('changessaved'), '');
close_window(3);
} else {
$returnurl->param('lastchanged', $question->id);
if ($appendqnumstring) {
$returnurl->param($appendqnumstring, $question->id);
$returnurl->param('sesskey', sesskey());
$returnurl->param('cmid', $cmid);
}
redirect($returnurl);
}
} else {
$nexturlparams = array(
'returnurl' => $originalreturnurl,
'appendqnumstring' => $appendqnumstring,
'scrollpos' => $scrollpos);
if (isset($fromform->nextpageparam) && is_array($fromform->nextpageparam)){
//useful for passing data to the next page which is not saved in the database.
$nexturlparams += $fromform->nextpageparam;
}
$nexturlparams['id'] = $question->id;
$nexturlparams['wizardnow'] = $fromform->wizard;
$nexturl = new moodle_url('/question/question.php', $nexturlparams);
if ($cmid){
$nexturl->param('cmid', $cmid);
} else {
$nexturl->param('courseid', $COURSE->id);
}
redirect($nexturl);
}
}
$streditingquestion = $qtypeobj->get_heading();
$PAGE->set_title($streditingquestion);
$PAGE->set_heading($COURSE->fullname);
$PAGE->navbar->add($streditingquestion);
// Display a heading, question editing form and possibly some extra content needed for
// for this question type.
echo $OUTPUT->header();
$qtypeobj->display_question_editing_page($mform, $question, $wizardnow);
echo $OUTPUT->footer();
+7 -1
View File
@@ -98,9 +98,11 @@ class core_question_bank_renderer extends plugin_renderer_base {
* @return string
* @deprecated since Moodle 4.0
* @see \qbank_editquestion\output\renderer
* @todo MDL-72004 deprecate the function and add debugging message.
* @todo Final deprecation on Moodle 4.4 MDL-72438
*/
public function render_qbank_chooser(renderable $qbankchooser) {
debugging('Function render_qbank_chooser is deprecated,
please use qbank_editquestion renderer instead.', DEBUG_DEVELOPER);
return $this->render_from_template('core_question/qbank_chooser', $qbankchooser->export_for_template($this));
}
@@ -162,6 +164,7 @@ class core_question_bank_renderer extends plugin_renderer_base {
* @param object $course The course that will be displayed
* @param array $hiddenparams Any hidden parameters to add to the form
* @return string The composed HTML for the questionbank chooser
* @todo Final deprecation on Moodle 4.4 MDL-72438
*/
public function qbank_chooser($real, $fake, $course, $hiddenparams) {
debugging('Method core_question_bank_renderer::qbank_chooser() is deprecated, ' .
@@ -174,6 +177,7 @@ class core_question_bank_renderer extends plugin_renderer_base {
*
* @param array $types A set of question types as used by the qbank_chooser_module function
* @return string The composed HTML for the module
* @todo Final deprecation on Moodle 4.4 MDL-72438
*/
protected function qbank_chooser_types($types) {
debugging('Method core_question_bank_renderer::qbank_chooser_types() is deprecated, ' .
@@ -188,6 +192,7 @@ class core_question_bank_renderer extends plugin_renderer_base {
* If the module contains subtypes in the types option, then these will also be displayed.
* @param array $classes Additional classes to add to the encompassing div element
* @return string The composed HTML for the question type
* @todo Final deprecation on Moodle 4.4 MDL-72438
*/
protected function qbank_chooser_qtype($qtype, $classes = array()) {
debugging('Method core_question_bank_renderer::qbank_chooser_qtype() is deprecated, ' .
@@ -201,6 +206,7 @@ class core_question_bank_renderer extends plugin_renderer_base {
* @param string $title The language string identifier
* @param string $identifier The component identifier
* @return string The composed HTML for the title
* @todo Final deprecation on Moodle 4.4 MDL-72438
*/
protected function qbank_chooser_title($title, $identifier = null) {
debugging('Method core_question_bank_renderer::qbank_chooser_title() is deprecated, ' .
+3 -10
View File
@@ -337,16 +337,9 @@ class question_dataset_dependent_items_form extends question_wizard_form {
$buttonarray = [];
$buttonarray[] = $mform->createElement(
'submit', 'savechanges', get_string('savechanges'));
// Todo MDL-72004 changes for class renaming and default sort.
if (class_exists('qbank_previewquestion\\preview_action_column')) {
if (\core\plugininfo\qbank::is_plugin_enabled('qbank_previewquestion')) {
$previewlink = $PAGE->get_renderer('qbank_previewquestion')->question_preview_link(
$this->question->id, $this->categorycontext, true);
}
} else {
$previewlink = $PAGE->get_renderer('core_question')->question_preview_link(
$this->question->id, $this->categorycontext, true);
if (\core\plugininfo\qbank::is_plugin_enabled('qbank_previewquestion')) {
$previewlink = $PAGE->get_renderer('qbank_previewquestion')->question_preview_link($this->question->id,
$this->categorycontext, true);
}
$buttonarray[] = $mform->createElement('static', 'previewlink', '', $previewlink);
-100
View File
@@ -1,100 +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/>.
/**
* The mform to manage question tags.
*
* @package core_question
* @copyright 2018 Simey Lameze <[email protected]>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace core_question\form;
defined('MOODLE_INTERNAL') || die();
require_once($CFG->dirroot . '/lib/formslib.php');
require_once($CFG->dirroot . '/lib/questionlib.php');
/**
* The mform class for manage question tags.
*
* @copyright 2018 Simey Lameze <[email protected]>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
* @deprecated since Moodle 4.0
* @see \qbank_tagquestion\form\tags_form
* @todo MDL-71679 class renaming
*/
class tags extends \moodleform {
/**
* The form definition
*/
public function definition() {
debugging('Class column_base in core_question\form\tags is deprecated,
please use qbank_tagquestion\form\tags_form instead.', DEBUG_DEVELOPER);
$mform = $this->_form;
$customdata = $this->_customdata;
$mform->disable_form_change_checker();
$mform->addElement('hidden', 'id');
$mform->setType('id', PARAM_INT);
$mform->addElement('hidden', 'categoryid');
$mform->setType('categoryid', PARAM_INT);
$mform->addElement('hidden', 'contextid');
$mform->setType('contextid', PARAM_INT);
$mform->addElement('static', 'questionname', get_string('questionname', 'question'));
$mform->addElement('static', 'questioncategory', get_string('categorycurrent', 'question'));
$mform->addElement('static', 'context', '');
if (\core_tag_tag::is_enabled('core_question', 'question')) {
$tags = \core_tag_tag::get_tags_by_area_in_contexts('core_question', 'question', $customdata['contexts']);
$tagstrings = [];
foreach ($tags as $tag) {
$tagstrings[$tag->name] = $tag->name;
}
$options = [
'tags' => true,
'multiple' => true,
'noselectionstring' => get_string('anytags', 'quiz'),
];
$mform->addElement('autocomplete', 'tags', get_string('tags'), $tagstrings, $options);
// Is the question category in a course context?
$qcontext = $customdata['questioncontext'];
$qcoursecontext = $qcontext->get_course_context(false);
$iscourseoractivityquestion = !empty($qcoursecontext);
// Is the current context we're editing in a course context?
$editingcontext = $customdata['editingcontext'];
$editingcoursecontext = $editingcontext->get_course_context(false);
$iseditingcontextcourseoractivity = !empty($editingcoursecontext);
if ($iseditingcontextcourseoractivity && !$iscourseoractivityquestion) {
// If the question is being edited in a course or activity context
// and the question isn't a course or activity level question then
// allow course tags to be added to the course.
$coursetagheader = get_string('questionformtagheader', 'core_question',
$editingcoursecontext->get_context_name(true));
$mform->addElement('autocomplete', 'coursetags', $coursetagheader, $tagstrings, $options);
}
}
}
}
+54
View File
@@ -6,6 +6,7 @@ This files describes API changes for code that uses the question API.
are divided in two different parts, base classes and feature classes. All the base
classes are moved classes/local/bank and all the feature classes will be moved to
the plugin for that feature.
2) submit_tags_form and associated external services for question tag, tags_form in question/type,
core_question_output_fragment_tags_form method in lib is deprecated and moved to the tagquestion plugin.
@@ -19,6 +20,59 @@ This files describes API changes for code that uses the question API.
The following classes are deprecated in previewlib and moves the previewquestion plugin:
question_preview_options, preview_options_form.
5) submit_tags_form and associated external services for question tag, tags_form in question/type,
core_question_output_fragment_tags_form method in lib is deprecated and moved to the tagquestion plugin.
6) Function question_get_export_single_question_url() in questionlib has been deprecated
and moved to qbank_exporttoxml plugin, the new location is:
qbank_exporttoxml\exporttoxml_helper::question_get_export_single_question_url().
7) The following classes are deleted and available in the new location:
'core_question\bank\action_column_base' => 'core_question\local\bank\action_column_base',
'core_question\bank\checkbox_column' => 'core_question\local\bank\checkbox_column',
'core_question\bank\column_base' => 'core_question\local\bank\column_base',
'core_question\bank\edit_menu_column' => 'core_question\local\bank\edit_menu_column',
'core_question\bank\menu_action_column_base' => 'core_question\local\bank\menu_action_column_base',
'core_question\bank\menuable_action' => 'core_question\local\bank\menuable_action',
'core_question\bank\random_question_loader' => 'core_question\local\bank\random_question_loader',
'core_question\bank\row_base' => 'core_question\local\bank\row_base',
'core_question\bank\view' => 'core_question\local\bank\view',
'core_question\bank\copy_action_column' => 'qbank_editquestion\copy_action_column',
'core_question\bank\edit_action_column' => 'qbank_editquestion\edit_action_column',
'core_question\bank\creator_name_column' => 'qbank_viewcreator\creator_name_column',
'core_question\bank\modifier_name_column' => 'qbank_viewcreator\modifier_name_column',
'core_question\bank\question_name_column' => 'qbank_viewquestionname\viewquestionname_column_helper',
'core_question\bank\question_name_idnumber_tags_column' => 'qbank_viewquestionname\question_name_idnumber_tags_column',
'core_question\bank\delete_action_column' => 'qbank_deletequestion\delete_action_column',
'core_question\bank\export_xml_action_column' => 'qbank_exporttoxml\export_xml_action_column',
'core_question\bank\preview_action_column' => 'qbank_previewquestion\preview_action_column',
'core_question\bank\question_text_row' => 'qbank_viewquestiontext\question_text_row',
'core_question\bank\question_type_column' => 'qbank_viewquestiontype\question_type_column',
'core_question\bank\tags_action_column' => 'qbank_tagquestion\tags_action_column',
'core_question\form\tags' => '\qbank_tagquestion\form\tags_form',
'core_question\output\qbank_chooser' => 'qbank_editquestion\qbank_chooser',
'core_question\output\qbank_chooser_item' => 'qbank_editquestion\qbank_chooser_item',
8) The following classes are deprecated and moved to a new location. These are marked for final deprecation on 4.4:
'question_category_list' => 'qbank_managecategories\question_category_list',
'question_category_list_item' => 'qbank_managecategories\question_category_list_item',
'question_category_object' => 'qbank_managecategories\question_category_object',
'question_category_edit_form' => 'qbank_managecategories\form\category_form',
'question_export_form' => 'qbank_exportquestions\form\export_form',
'question_import_form' => 'qbank_importquestions\form\question_import_form',
'question_move_form' => 'qbank_managecategories\form\question_move_form',
'preview_options_form' => 'qbank_previewquestion\form\preview_options_form',
'question_preview_options' => 'qbank_previewquestion\output\question_preview_options',
'category_form' => 'qbank_managecategories\form\category_form',
'export_form' => 'qbank_exportquestions\form\export_form'.
9) The following functions are deprecated and moved to the new location:
question_preview_question_pluginfile() => qbank_previewquestion\helper::question_preview_question_pluginfile(),
question_preview_action_url() => qbank_previewquestion\helper::question_preview_action_url(),
question_preview_form_url() => qbank_previewquestion\helper::question_preview_form_url(),
restart_preview() => qbank_previewquestion\helper::restart_preview(),
core_question_output_fragment_tags_form() => /question/bank/qbank_tagquestion/lib.php.
=== 3.9 ==
1) For years, the ..._questions_in_use callback has been the right way for plugins to