Merge branch 'master_MDL-71679-mod_quiz-52' of https://github.com/catalyst/moodle-MDL-70329

This commit is contained in:
Ilya Tregubov
2021-10-05 23:18:47 +02:00
committed by Eloy Lafuente (stronk7)
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
@@ -71,6 +71,11 @@ information provided here is intended especially for developers.
that wants to listen for the events. Backwards compatibility with existing code using jQuery is preserved.
* 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