3 // This file is part of Moodle - http://moodle.org/
5 // Moodle is free software: you can redistribute it and/or modify
6 // it under the terms of the GNU General Public License as published by
7 // the Free Software Foundation, either version 3 of the License, or
8 // (at your option) any later version.
10 // Moodle is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 // GNU General Public License for more details.
15 // You should have received a copy of the GNU General Public License
16 // along with Moodle. If not, see <http://www.gnu.org/licenses/>.
19 * Allows the admin to manage question behaviours.
22 * @subpackage questionengine
23 * @copyright 2011 The Open University
24 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
28 require_once(dirname(__FILE__
) . '/../config.php');
29 require_once($CFG->libdir
. '/questionlib.php');
30 require_once($CFG->libdir
. '/adminlib.php');
31 require_once($CFG->libdir
. '/tablelib.php');
35 $systemcontext = get_context_instance(CONTEXT_SYSTEM
);
36 require_capability('moodle/question:config', $systemcontext);
38 admin_externalpage_setup('manageqbehaviours');
39 $thispageurl = new moodle_url('/admin/qbehaviours.php');
41 $behaviours = get_plugin_list('qbehaviour');
43 // Get some data we will need - question counts and which types are needed.
44 $counts = $DB->get_records_sql_menu("
45 SELECT behaviour, COUNT(1)
46 FROM {question_attempts} GROUP BY behaviour");
48 $archetypal = array();
49 foreach ($behaviours as $behaviour => $notused) {
50 if (!array_key_exists($behaviour, $counts)) {
51 $counts[$behaviour] = 0;
53 $needed[$behaviour] = $counts[$behaviour] > 0;
54 $archetypal[$behaviour] = question_engine
::is_behaviour_archetypal($behaviour);
57 foreach ($behaviours as $behaviour => $notused) {
58 foreach (question_engine
::get_behaviour_required_behaviours($behaviour) as $reqbehaviour) {
59 $needed[$reqbehaviour] = true;
62 foreach ($counts as $behaviour => $count) {
63 if (!array_key_exists($behaviour, $behaviours)) {
64 $counts['missing'] +
= $count;
67 $needed['missing'] = true;
69 // Work of the correct sort order.
70 $config = get_config('question');
71 $sortedbehaviours = array();
72 foreach ($behaviours as $behaviour => $notused) {
73 $sortedbehaviours[$behaviour] = question_engine
::get_behaviour_name($behaviour);
75 if (!empty($config->behavioursortorder
)) {
76 $sortedbehaviours = question_engine
::sort_behaviours($sortedbehaviours,
77 $config->behavioursortorder
, '');
80 if (!empty($config->disabledbehaviours
)) {
81 $disabledbehaviours = explode(',', $config->disabledbehaviours
);
83 $disabledbehaviours = array();
86 // Process actions ============================================================
89 if (($disable = optional_param('disable', '', PARAM_SAFEDIR
)) && confirm_sesskey()) {
90 if (!isset($behaviours[$disable])) {
91 print_error('unknownbehaviour', 'question', $thispageurl, $disable);
94 if (array_search($disable, $disabledbehaviours) === false) {
95 $disabledbehaviours[] = $disable;
96 set_config('disabledbehaviours', implode(',', $disabledbehaviours), 'question');
98 redirect($thispageurl);
102 if (($enable = optional_param('enable', '', PARAM_SAFEDIR
)) && confirm_sesskey()) {
103 if (!isset($behaviours[$enable])) {
104 print_error('unknownbehaviour', 'question', $thispageurl, $enable);
107 if (!$archetypal[$enable]) {
108 print_error('cannotenablebehaviour', 'question', $thispageurl, $enable);
111 if (($key = array_search($enable, $disabledbehaviours)) !== false) {
112 unset($disabledbehaviours[$key]);
113 set_config('disabledbehaviours', implode(',', $disabledbehaviours), 'question');
115 redirect($thispageurl);
119 if (($up = optional_param('up', '', PARAM_SAFEDIR
)) && confirm_sesskey()) {
120 if (!isset($behaviours[$up])) {
121 print_error('unknownbehaviour', 'question', $thispageurl, $up);
124 // This function works fine for behaviours, as well as qtypes.
125 $neworder = question_reorder_qtypes($sortedbehaviours, $up, -1);
126 set_config('behavioursortorder', implode(',', $neworder), 'question');
127 redirect($thispageurl);
130 // Move down in order.
131 if (($down = optional_param('down', '', PARAM_SAFEDIR
)) && confirm_sesskey()) {
132 if (!isset($behaviours[$down])) {
133 print_error('unknownbehaviour', 'question', $thispageurl, $down);
136 // This function works fine for behaviours, as well as qtypes.
137 $neworder = question_reorder_qtypes($sortedbehaviours, $down, +
1);
138 set_config('behavioursortorder', implode(',', $neworder), 'question');
139 redirect($thispageurl);
143 if (($delete = optional_param('delete', '', PARAM_SAFEDIR
)) && confirm_sesskey()) {
144 // Check it is OK to delete this question type.
145 if ($delete == 'missing') {
146 print_error('cannotdeletemissingbehaviour', 'question', $thispageurl);
149 if (!isset($behaviours[$delete])) {
150 print_error('unknownbehaviour', 'question', $thispageurl, $delete);
153 $behaviourname = $sortedbehaviours[$delete];
154 if ($counts[$delete] > 0) {
155 print_error('cannotdeletebehaviourinuse', 'question', $thispageurl, $behaviourname);
157 if ($needed[$delete] > 0) {
158 print_error('cannotdeleteneededbehaviour', 'question', $thispageurl, $behaviourname);
161 // If not yet confirmed, display a confirmation message.
162 if (!optional_param('confirm', '', PARAM_BOOL
)) {
163 echo $OUTPUT->header();
164 echo $OUTPUT->heading(get_string('deletebehaviourareyousure', 'question', $behaviourname));
165 echo $OUTPUT->confirm(
166 get_string('deletebehaviourareyousuremessage', 'question', $behaviourname),
167 new moodle_url($thispageurl, array('delete' => $delete, 'confirm' => 1)),
169 echo $OUTPUT->footer();
174 echo $OUTPUT->header();
175 echo $OUTPUT->heading(get_string('deletingbehaviour', 'question', $behaviourname));
177 // Delete any configuration records.
178 if (!unset_all_config_for_plugin('qbehaviour_' . $delete)) {
179 echo $OUTPUT->notification(get_string('errordeletingconfig', 'admin', 'qbehaviour_' . $delete));
181 if (($key = array_search($delete, $disabledbehaviours)) !== false) {
182 unset($disabledbehaviours[$key]);
183 set_config('disabledbehaviours', implode(',', $disabledbehaviours), 'question');
185 $behaviourorder = array_keys($sortedbehaviours);
186 if (($key = array_search($delete, $behaviourorder)) !== false) {
187 unset($behaviourorder[$key]);
188 set_config('behavioursortorder', implode(',', $behaviourorder), 'question');
191 // Then the tables themselves
192 drop_plugin_tables($delete, get_plugin_directory('qbehaviour', $delete) . '/db/install.xml', false);
194 // Remove event handlers and dequeue pending events
195 events_uninstall('qbehaviour_' . $delete);
198 $a->behaviour
= $behaviourname;
199 $a->directory
= get_plugin_directory('qbehaviour', $delete);
200 echo $OUTPUT->box(get_string('qbehaviourdeletefiles', 'question', $a), 'generalbox', 'notice');
201 echo $OUTPUT->continue_button($thispageurl);
202 echo $OUTPUT->footer();
206 // End of process actions ==================================================
208 // Print the page heading.
209 echo $OUTPUT->header();
210 echo $OUTPUT->heading(get_string('manageqbehaviours', 'admin'));
213 $table = new flexible_table('qbehaviouradmintable');
214 $table->define_baseurl($thispageurl);
215 $table->define_columns(array('behaviour', 'numqas', 'version', 'requires',
216 'available', 'delete'));
217 $table->define_headers(array(get_string('behaviour', 'question'), get_string('numqas', 'question'),
218 get_string('version'), get_string('requires', 'admin'),
219 get_string('availableq', 'question'), get_string('delete')));
220 $table->set_attribute('id', 'qbehaviours');
221 $table->set_attribute('class', 'generaltable generalbox boxaligncenter boxwidthwide');
224 // Add a row for each question type.
225 foreach ($sortedbehaviours as $behaviour => $behaviourname) {
228 // Question icon and name.
229 $row[] = $behaviourname;
232 $row[] = $counts[$behaviour];
234 // Question version number.
235 $version = get_config('qbehaviour_' . $behaviour, 'version');
239 $row[] = html_writer
::tag('span', get_string('nodatabase', 'admin'), array('class' => 'disabled'));
242 // Other question types required by this one.
243 $requiredbehaviours = question_engine
::get_behaviour_required_behaviours($behaviour);
244 if (!empty($requiredbehaviours)) {
245 $strrequiredbehaviours = array();
246 foreach ($requiredbehaviours as $required) {
247 $strrequiredbehaviours[] = $sortedbehaviours[$required];
249 $row[] = implode(', ', $strrequiredbehaviours);
254 // Are people allowed to select this behaviour?
256 if ($archetypal[$behaviour]) {
257 $enabled = array_search($behaviour, $disabledbehaviours) === false;
258 $icons = question_behaviour_enable_disable_icons($behaviour, $enabled);
260 $rowclass = 'dimmed_text';
263 $icons = $OUTPUT->spacer() . ' ';
267 $icons .= question_behaviour_icon_html('up', $behaviour, 't/up', get_string('up'), null);
268 $icons .= question_behaviour_icon_html('down', $behaviour, 't/down', get_string('down'), null);
271 // Delete link, if available.
272 if ($needed[$behaviour]) {
275 $row[] = html_writer
::link(new moodle_url($thispageurl,
276 array('delete' => $behaviour, 'sesskey' => sesskey())), get_string('delete'),
277 array('title' => get_string('uninstallbehaviour', 'question')));
280 $table->add_data($row, $rowclass);
283 $table->finish_output();
285 echo $OUTPUT->footer();
287 function question_behaviour_enable_disable_icons($behaviour, $enabled) {
289 return question_behaviour_icon_html('disable', $behaviour, 'i/hide',
290 get_string('enabled', 'question'), get_string('disable'));
292 return question_behaviour_icon_html('enable', $behaviour, 'i/show',
293 get_string('disabled', 'question'), get_string('enable'));
297 function question_behaviour_icon_html($action, $behaviour, $icon, $alt, $tip) {
299 return $OUTPUT->action_icon(new moodle_url('/admin/qbehaviours.php',
300 array($action => $behaviour, 'sesskey' => sesskey())),
301 new pix_icon($icon, $alt, 'moodle', array('title' => '')),
302 null, array('title' => $tip)) . ' ';