MDL-26825 do not return any form data if form cancelled
[moodle.git] / admin / qtypes.php
blob33a70d87a4f9ed2fd0489b44245d384d923b09af
1 <?php
2 // Allows the admin to manage question types.
4 require_once(dirname(__FILE__) . '/../config.php');
5 require_once($CFG->libdir . '/questionlib.php');
6 require_once($CFG->libdir . '/adminlib.php');
7 require_once($CFG->libdir . '/tablelib.php');
9 /// Check permissions.
10 require_login();
11 $systemcontext = get_context_instance(CONTEXT_SYSTEM);
12 require_capability('moodle/question:config', $systemcontext);
13 $canviewreports = has_capability('report/questioninstances:view', $systemcontext);
15 admin_externalpage_setup('manageqtypes');
17 /// Get some data we will need - question counts and which types are needed.
18 $counts = $DB->get_records_sql("
19 SELECT qtype, COUNT(1) as numquestions, SUM(hidden) as numhidden
20 FROM {question} GROUP BY qtype", array());
21 $needed = array();
22 foreach ($QTYPES as $qtypename => $qtype) {
23 if (!isset($counts[$qtypename])) {
24 $counts[$qtypename] = new stdClass;
25 $counts[$qtypename]->numquestions = 0;
26 $counts[$qtypename]->numhidden = 0;
28 $needed[$qtypename] = $counts[$qtypename]->numquestions > 0;
29 $counts[$qtypename]->numquestions -= $counts[$qtypename]->numhidden;
31 $needed['missingtype'] = true; // The system needs the missing question type.
32 foreach ($QTYPES as $qtypename => $qtype) {
33 foreach ($qtype->requires_qtypes() as $reqtype) {
34 $needed[$reqtype] = true;
37 foreach ($counts as $qtypename => $count) {
38 if (!isset($QTYPES[$qtypename])) {
39 $counts['missingtype']->numquestions += $count->numquestions - $count->numhidden;
40 $counts['missingtype']->numhidden += $count->numhidden;
44 /// Work of the correct sort order.
45 $config = get_config('question');
46 $sortedqtypes = array();
47 foreach ($QTYPES as $qtypename => $qtype) {
48 $sortedqtypes[$qtypename] = $qtype->local_name();
50 $sortedqtypes = question_sort_qtype_array($sortedqtypes, $config);
52 /// Process actions ============================================================
54 // Disable.
55 if (($disable = optional_param('disable', '', PARAM_SAFEDIR)) && confirm_sesskey()) {
56 if (!isset($QTYPES[$disable])) {
57 print_error('unknownquestiontype', 'question', admin_url('qtypes.php'), $disable);
60 set_config($disable . '_disabled', 1, 'question');
61 redirect(admin_url('qtypes.php'));
64 // Enable.
65 if (($enable = optional_param('enable', '', PARAM_SAFEDIR)) && confirm_sesskey()) {
66 if (!isset($QTYPES[$enable])) {
67 print_error('unknownquestiontype', 'question', admin_url('qtypes.php'), $enable);
70 if (!$QTYPES[$enable]->menu_name()) {
71 print_error('cannotenable', 'question', admin_url('qtypes.php'), $enable);
74 unset_config($enable . '_disabled', 'question');
75 redirect(admin_url('qtypes.php'));
78 // Move up in order.
79 if (($up = optional_param('up', '', PARAM_SAFEDIR)) && confirm_sesskey()) {
80 if (!isset($QTYPES[$up])) {
81 print_error('unknownquestiontype', 'question', admin_url('qtypes.php'), $up);
84 $neworder = question_reorder_qtypes($sortedqtypes, $up, -1);
85 question_save_qtype_order($neworder, $config);
86 redirect(admin_url('qtypes.php'));
89 // Move down in order.
90 if (($down = optional_param('down', '', PARAM_SAFEDIR)) && confirm_sesskey()) {
91 if (!isset($QTYPES[$down])) {
92 print_error('unknownquestiontype', 'question', admin_url('qtypes.php'), $down);
95 $neworder = question_reorder_qtypes($sortedqtypes, $down, +1);
96 question_save_qtype_order($neworder, $config);
97 redirect(admin_url('qtypes.php'));
100 // Delete.
101 if (($delete = optional_param('delete', '', PARAM_SAFEDIR)) && confirm_sesskey()) {
102 // Check it is OK to delete this question type.
103 if ($delete == 'missingtype') {
104 print_error('cannotdeletemissingqtype', 'admin', admin_url('qtypes.php'));
107 if (!isset($QTYPES[$delete])) {
108 print_error('unknownquestiontype', 'question', admin_url('qtypes.php'), $delete);
111 $qtypename = $QTYPES[$delete]->local_name();
112 if ($counts[$delete]->numquestions + $counts[$delete]->numhidden > 0) {
113 print_error('cannotdeleteqtypeinuse', 'admin', admin_url('qtypes.php'), $qtypename);
116 if ($needed[$delete] > 0) {
117 print_error('cannotdeleteqtypeneeded', 'admin', admin_url('qtypes.php'), $qtypename);
120 // If not yet confirmed, display a confirmation message.
121 if (!optional_param('confirm', '', PARAM_BOOL)) {
122 $qtypename = $QTYPES[$delete]->local_name();
123 echo $OUTPUT->header();
124 echo $OUTPUT->heading(get_string('deleteqtypeareyousure', 'admin', $qtypename));
125 echo $OUTPUT->confirm(get_string('deleteqtypeareyousuremessage', 'admin', $qtypename),
126 admin_url('qtypes.php?delete=' . $delete . '&confirm=1'),
127 admin_url('qtypes.php'));
128 echo $OUTPUT->footer();
129 exit;
132 // Do the deletion.
133 echo $OUTPUT->header();
134 echo $OUTPUT->heading(get_string('deletingqtype', 'admin', $qtypename));
136 // Delete any configuration records.
137 if (!unset_all_config_for_plugin('qtype_' . $delete)) {
138 echo $OUTPUT->notification(get_string('errordeletingconfig', 'admin', 'qtype_' . $delete));
140 unset_config($delete . '_disabled', 'question');
141 unset_config($delete . '_sortorder', 'question');
143 // Then the tables themselves
144 drop_plugin_tables($delete, $QTYPES[$delete]->plugin_dir() . '/db/install.xml', false);
146 // Remove event handlers and dequeue pending events
147 events_uninstall('qtype/' . $delete);
149 $a->qtype = $qtypename;
150 $a->directory = $QTYPES[$delete]->plugin_dir();
151 echo $OUTPUT->box(get_string('qtypedeletefiles', 'admin', $a), 'generalbox', 'notice');
152 echo $OUTPUT->continue_button(admin_url('qtypes.php'));
153 echo $OUTPUT->footer();
154 exit;
157 // End of process actions ==================================================
159 /// Print the page heading.
160 echo $OUTPUT->header();
161 echo $OUTPUT->heading(get_string('manageqtypes', 'admin'));
163 /// Set up the table.
164 $table = new flexible_table('qtypeadmintable');
165 $table->define_columns(array('questiontype', 'numquestions', 'version', 'requires',
166 'availableto', 'delete', 'settings'));
167 $table->define_headers(array(get_string('questiontype', 'admin'), get_string('numquestions', 'admin'),
168 get_string('version'), get_string('requires', 'admin'), get_string('availableq', 'question'),
169 get_string('delete'), get_string('settings')));
170 $table->set_attribute('id', 'qtypes');
171 $table->set_attribute('class', 'generaltable generalbox boxaligncenter boxwidthwide');
172 $table->setup();
174 /// Add a row for each question type.
175 $createabletypes = question_type_menu();
176 foreach ($sortedqtypes as $qtypename => $localname) {
177 $qtype = $QTYPES[$qtypename];
178 $row = array();
180 // Question icon and name.
181 $fakequestion = new stdClass;
182 $fakequestion->qtype = $qtypename;
183 $icon = print_question_icon($fakequestion, true);
184 $row[] = $icon . ' ' . $localname;
186 // Number of questions of this type.
187 if ($counts[$qtypename]->numquestions + $counts[$qtypename]->numhidden > 0) {
188 if ($counts[$qtypename]->numhidden > 0) {
189 $strcount = get_string('numquestionsandhidden', 'admin', $counts[$qtypename]);
190 } else {
191 $strcount = $counts[$qtypename]->numquestions;
193 if ($canviewreports) {
194 $row[] = '<a href="' . admin_url('/report/questioninstances/index.php?qtype=' . $qtypename) .
195 '" title="' . get_string('showdetails', 'admin') . '">' . $strcount . '</a>';
196 } else {
197 $strcount;
199 } else {
200 $row[] = 0;
203 // Question version number.
204 $version = get_config('qtype_' . $qtypename, 'version');
205 if ($version) {
206 $row[] = $version;
207 } else {
208 $row[] = '<span class="disabled">' . get_string('nodatabase', 'admin') . '</span>';
211 // Other question types required by this one.
212 $requiredtypes = $qtype->requires_qtypes();
213 $strtypes = array();
214 if (!empty($requiredtypes)) {
215 foreach ($requiredtypes as $required) {
216 $strtypes[] = $QTYPES[$required]->local_name();
218 $row[] = implode(', ', $strtypes);
219 } else {
220 $row[] = '';
223 // Are people allowed to create new questions of this type?
224 $rowclass = '';
225 if ($qtype->menu_name()) {
226 $createable = isset($createabletypes[$qtypename]);
227 $icons = enable_disable_button($qtypename, $createable);
228 if (!$createable) {
229 $rowclass = 'dimmed_text';
231 } else {
232 $icons = '<img src="' . $OUTPUT->pix_url('spacer') . '" alt="" class="spacer" />';
235 // Move icons.
236 $icons .= icon_html('up', $qtypename, 't/up', get_string('up'), '');
237 $icons .= icon_html('down', $qtypename, 't/down', get_string('down'), '');
238 $row[] = $icons;
240 // Delete link, if available.
241 if ($needed[$qtypename]) {
242 $row[] = '';
243 } else {
244 $row[] = '<a href="' . admin_url('qtypes.php?delete=' . $qtypename .
245 '&amp;sesskey=' . sesskey()) . '" title="' .
246 get_string('uninstallqtype', 'admin') . '">' . get_string('delete') . '</a>';
249 // Settings link, if available.
250 $settings = admin_get_root()->locate('qtypesetting' . $qtypename);
251 if ($settings instanceof admin_externalpage) {
252 $row[] = '<a href="' . $settings->url .
253 '">' . get_string('settings') . '</a>';
254 } else if ($settings instanceof admin_settingpage) {
255 $row[] = '<a href="' . admin_url('settings.php?section=qtypesetting' . $qtypename) .
256 '">' . get_string('settings') . '</a>';
257 } else {
258 $row[] = '';
261 $table->add_data($row, $rowclass);
264 $table->finish_output();
266 echo $OUTPUT->footer();
268 function admin_url($endbit) {
269 global $CFG;
270 return $CFG->wwwroot . '/' . $CFG->admin . '/' . $endbit;
273 function enable_disable_button($qtypename, $createable) {
274 if ($createable) {
275 return icon_html('disable', $qtypename, 'i/hide', get_string('enabled', 'question'), get_string('disable'));
276 } else {
277 return icon_html('enable', $qtypename, 'i/show', get_string('disabled', 'question'), get_string('enable'));
281 function icon_html($action, $qtypename, $icon, $alt, $tip) {
282 global $OUTPUT;
283 if ($tip) {
284 $tip = 'title="' . $tip . '" ';
286 $html = ' <form action="' . admin_url('qtypes.php') . '" method="post"><div>';
287 $html .= '<input type="hidden" name="sesskey" value="' . sesskey() . '" />';
288 $html .= '<input type="image" name="' . $action . '" value="' . $qtypename .
289 '" src="' . $OUTPUT->pix_url($icon) . '" alt="' . $alt . '" ' . $tip . '/>';
290 $html .= '</div></form>';
291 return $html;