Proyectos de Subversion Moodle

Rev

Rev 1 | | Comparar con el anterior | Ultima modificación | Ver Log |

Rev Autor Línea Nro. Línea
1 efrain 1
<?php
2
// This file is part of Moodle - http://moodle.org/
3
//
4
// Moodle is free software: you can redistribute it and/or modify
5
// it under the terms of the GNU General Public License as published by
6
// the Free Software Foundation, either version 3 of the License, or
7
// (at your option) any later version.
8
//
9
// Moodle is distributed in the hope that it will be useful,
10
// but WITHOUT ANY WARRANTY; without even the implied warranty of
11
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
// GNU General Public License for more details.
13
//
14
// You should have received a copy of the GNU General Public License
15
// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
16
 
17
/**
18
 * This file contains the generic moodleform bridge for the backup user interface
19
 * as well as the individual forms that relate to the different stages the user
20
 * interface can exist within.
21
 *
22
 * @package   core_backup
23
 * @copyright 2010 Sam Hemelryk
24
 * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
25
 */
26
 
27
defined('MOODLE_INTERNAL') || die();
28
 
29
require_once($CFG->libdir . '/formslib.php');
30
 
31
/**
32
 * Base moodleform bridge
33
 *
34
 * Ahhh the mighty moodleform bridge! Strong enough to take the weight of 682 full
35
 * grown african swallows all of whom have been carring coconuts for several days.
36
 * EWWWWW!!!!!!!!!!!!!!!!!!!!!!!!
37
 *
38
 * @package   core_backup
39
 * @copyright 2010 Sam Hemelryk
40
 * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
41
 */
42
abstract class base_moodleform extends moodleform {
43
 
44
    /**
45
     * The stage this form belongs to
46
     * @var base_ui_stage
47
     */
48
    protected $uistage = null;
49
 
50
    /**
1441 ariadna 51
     * Group stack to control open and closed div groups.
52
     * @var array
1 efrain 53
     */
1441 ariadna 54
    protected array $groupstack = [];
1 efrain 55
 
56
    /**
57
     * Creates the form
58
     *
59
     * @param base_ui_stage $uistage
60
     * @param moodle_url|string $action
61
     * @param mixed $customdata
62
     * @param string $method get|post
63
     * @param string $target
64
     * @param array $attributes
65
     * @param bool $editable
66
     */
67
    public function __construct(base_ui_stage $uistage, $action = null, $customdata = null, $method = 'post',
68
                                $target = '', $attributes = null, $editable = true) {
69
        $this->uistage = $uistage;
70
        // Add a class to the attributes to prevent the default collapsible behaviour.
71
        if (!$attributes) {
72
            $attributes = array();
73
        }
74
        $attributes['class'] = 'unresponsive';
75
        if (!isset($attributes['enctype'])) {
76
            $attributes['enctype'] = 'application/x-www-form-urlencoded'; // Enforce compatibility with our max_input_vars hack.
77
        }
78
        parent::__construct($action, $customdata, $method, $target, $attributes, $editable);
79
    }
80
 
81
    /**
82
     * The standard form definition... obviously not much here
83
     */
84
    public function definition() {
85
        $ui = $this->uistage->get_ui();
86
        $mform = $this->_form;
87
        $mform->setDisableShortforms();
88
        $stage = $mform->addElement('hidden', 'stage', $this->uistage->get_stage());
89
        $mform->setType('stage', PARAM_INT);
90
        $stage = $mform->addElement('hidden', $ui->get_name(), $ui->get_uniqueid());
91
        $mform->setType($ui->get_name(), PARAM_ALPHANUM);
92
        $params = $this->uistage->get_params();
93
        if (is_array($params) && count($params) > 0) {
94
            foreach ($params as $name => $value) {
95
                // TODO: Horrible hack, but current backup ui structure does not allow
96
                // to make this easy (only changing params to objects that would be
97
                // possible. MDL-38735.
98
                $intparams = array(
99
                        'contextid', 'importid', 'target');
100
                $stage = $mform->addElement('hidden', $name, $value);
101
                if (in_array($name, $intparams)) {
102
                    $mform->setType($name, PARAM_INT);
103
                } else {
104
                    // Adding setType() to avoid missing setType() warnings.
105
                    // MDL-39126: support $mform->setType() for additional backup parameters.
106
                    $mform->setType($name, PARAM_RAW);
107
                }
108
            }
109
        }
110
    }
111
    /**
112
     * Definition applied after the data is organised.. why's it here? because I want
113
     * to add elements on the fly.
114
     * @global moodle_page $PAGE
115
     */
116
    public function definition_after_data() {
117
        $buttonarray = array();
118
        if (!$this->uistage->is_first_stage()) {
119
            $buttonarray[] = $this->_form->createElement('submit', 'previous', get_string('previousstage', 'backup'));
120
        } else if ($this->uistage instanceof backup_ui_stage) {
121
            // Only display the button on the first stage of backup, they only place where it has an effect.
122
            $buttonarray[] = $this->_form->createElement('submit', 'oneclickbackup', get_string('jumptofinalstep', 'backup'),
123
                array('class' => 'oneclickbackup'));
124
        }
125
 
126
        $cancelparams = [
127
            'data-modal' => 'confirmation',
128
            'data-modal-content-str' => json_encode([
129
                'confirmcancelquestion',
130
                'backup',
131
            ]),
132
            'data-modal-yes-button-str' => json_encode([
133
                'yes',
134
                'moodle',
135
            ]),
136
        ];
137
        if ($this->uistage->get_ui() instanceof import_ui) {
138
            $cancelparams['data-modal-title-str'] = json_encode([
139
                'confirmcancelimport',
140
                'backup',
141
            ]);
142
        } else if ($this->uistage->get_ui() instanceof restore_ui) {
143
            $cancelparams['data-modal-title-str'] = json_encode([
144
                'confirmcancelrestore',
145
                'backup',
146
            ]);
147
        } else {
148
            $cancelparams['data-modal-title-str'] = json_encode([
149
                'confirmcancel',
150
                'backup',
151
            ]);
152
        }
153
 
154
        $buttonarray[] = $this->_form->createElement('cancel', 'cancel', get_string('cancel'), $cancelparams);
155
        $buttonarray[] = $this->_form->createElement(
156
            'submit',
157
            'submitbutton',
158
            get_string($this->uistage->get_ui()->get_name().'stage'.$this->uistage->get_stage().'action', 'backup'),
159
            array('class' => 'proceedbutton')
160
        );
161
        $this->_form->addGroup($buttonarray, 'buttonar', '', array(' '), false);
162
        $this->_form->closeHeaderBefore('buttonar');
163
 
164
        $this->_definition_finalized = true;
165
    }
166
 
167
    /**
1441 ariadna 168
     * Closes any open divs.
1 efrain 169
     */
170
    public function close_task_divs() {
1441 ariadna 171
        while (!empty($this->groupstack)) {
1 efrain 172
            $this->_form->addElement('html', html_writer::end_tag('div'));
1441 ariadna 173
            array_pop($this->groupstack);
1 efrain 174
        }
175
    }
176
 
177
    /**
178
     * Adds the backup_setting as a element to the form
179
     * @param backup_setting $setting
180
     * @param base_task $task
181
     * @return bool
182
     */
1441 ariadna 183
    public function add_setting(backup_setting $setting, ?base_task $task = null) {
1 efrain 184
        return $this->add_settings(array(array($setting, $task)));
185
    }
186
 
187
    /**
188
     * Adds multiple backup_settings as elements to the form
189
     * @param array $settingstasks Consists of array($setting, $task) elements
190
     * @return bool
191
     */
192
    public function add_settings(array $settingstasks) {
193
        global $OUTPUT;
194
 
195
        // Determine highest setting level, which is displayed in this stage. This is relevant for considering only
196
        // locks of dependency settings for parent settings, which are not displayed in this stage.
197
        $highestlevel = backup_setting::ACTIVITY_LEVEL;
198
        foreach ($settingstasks as $st) {
199
            list($setting, $task) = $st;
200
            if ($setting->get_level() < $highestlevel) {
201
                $highestlevel = $setting->get_level();
202
            }
203
        }
204
 
205
        $defaults = array();
206
        foreach ($settingstasks as $st) {
207
            list($setting, $task) = $st;
208
            // If the setting cant be changed or isn't visible then add it as a fixed setting.
209
            if (!$setting->get_ui()->is_changeable($highestlevel) ||
210
                $setting->get_visibility() != backup_setting::VISIBLE) {
211
                $this->add_fixed_setting($setting, $task);
212
                continue;
213
            }
214
 
215
            // First add the formatting for this setting.
216
            $this->add_html_formatting($setting);
217
 
218
            // Then call the add method with the get_element_properties array.
219
            call_user_func_array(array($this->_form, 'addElement'),
220
                array_values($setting->get_ui()->get_element_properties($task, $OUTPUT)));
221
            $this->_form->setType($setting->get_ui_name(), $setting->get_param_validation());
222
            $defaults[$setting->get_ui_name()] = $setting->get_value();
223
            if ($setting->has_help()) {
224
                list($identifier, $component) = $setting->get_help();
225
                $this->_form->addHelpButton($setting->get_ui_name(), $identifier, $component);
226
            }
1441 ariadna 227
            $this->pop_group();
1 efrain 228
        }
229
        $this->_form->setDefaults($defaults);
230
        return true;
231
    }
232
 
233
    /**
234
     * Adds a heading to the form
235
     * @param string $name
236
     * @param string $text
237
     */
238
    public function add_heading($name , $text) {
239
        $this->_form->addElement('header', $name, $text);
240
    }
241
 
242
    /**
243
     * Adds HTML formatting for the given backup setting, needed to group/segment
244
     * correctly.
245
     * @param backup_setting $setting
246
     */
247
    protected function add_html_formatting(backup_setting $setting) {
248
        $isincludesetting = (strpos($setting->get_name(), '_include') !== false);
249
        if ($isincludesetting && $setting->get_level() != backup_setting::ROOT_LEVEL) {
250
            switch ($setting->get_level()) {
251
                case backup_setting::COURSE_LEVEL:
1441 ariadna 252
                    $this->pop_groups_to('course');
253
                    $this->push_group_start('course', 'grouped_settings course_level');
254
                    $this->push_group_start(null, 'include_setting course_level');
1 efrain 255
                    break;
256
                case backup_setting::SECTION_LEVEL:
1441 ariadna 257
                    $this->pop_groups_to('course');
258
                    $this->push_group_start('section', 'grouped_settings section_level');
259
                    $this->push_group_start(null, 'include_setting section_level');
1 efrain 260
                    break;
261
                case backup_setting::ACTIVITY_LEVEL:
1441 ariadna 262
                    $this->pop_groups_to('section');
263
                    $this->push_group_start('activity', 'grouped_settings activity_level');
264
                    $this->push_group_start(null, 'include_setting activity_level');
1 efrain 265
                    break;
1441 ariadna 266
                case backup_setting::SUBSECTION_LEVEL:
267
                    $this->pop_groups_to('section');
268
                    $this->push_group_start('subsection', 'grouped_settings subsection_level');
269
                    $this->push_group_start(null, 'normal_setting');
270
                    break;
271
                case backup_setting::SUBACTIVITY_LEVEL:
272
                    $this->pop_groups_to('subsection');
273
                    $this->push_group_start('subactivity', 'grouped_settings activity_level');
274
                    $this->push_group_start(null, 'include_setting activity_level');
275
                    break;
1 efrain 276
                default:
1441 ariadna 277
                    $this->push_group_start(null, 'normal_setting');
1 efrain 278
                    break;
279
            }
280
        } else if ($setting->get_level() == backup_setting::ROOT_LEVEL) {
1441 ariadna 281
            $this->push_group_start('root', 'root_setting');
1 efrain 282
        } else {
1441 ariadna 283
            $this->push_group_start(null, 'normal_setting');
1 efrain 284
        }
285
    }
286
 
287
    /**
288
     * Adds a fixed or static setting to the form
289
     * @param backup_setting $setting
290
     * @param base_task $task
291
     */
292
    public function add_fixed_setting(backup_setting $setting, base_task $task) {
293
        global $OUTPUT;
294
        $settingui = $setting->get_ui();
295
        if ($setting->get_visibility() == backup_setting::VISIBLE) {
296
            $this->add_html_formatting($setting);
297
            switch ($setting->get_status()) {
298
                case backup_setting::LOCKED_BY_PERMISSION:
299
                    $icon = ' '.$OUTPUT->pix_icon('i/permissionlock', get_string('lockedbypermission', 'backup'), 'moodle',
300
                            array('class' => 'smallicon lockedicon permissionlock'));
301
                    break;
302
                case backup_setting::LOCKED_BY_CONFIG:
303
                    $icon = ' '.$OUTPUT->pix_icon('i/configlock', get_string('lockedbyconfig', 'backup'), 'moodle',
304
                            array('class' => 'smallicon lockedicon configlock'));
305
                    break;
306
                case backup_setting::LOCKED_BY_HIERARCHY:
307
                    $icon = ' '.$OUTPUT->pix_icon('i/hierarchylock', get_string('lockedbyhierarchy', 'backup'), 'moodle',
308
                            array('class' => 'smallicon lockedicon configlock'));
309
                    break;
310
                default:
311
                    $icon = '';
312
                    break;
313
            }
314
            $context = context_course::instance($task->get_courseid());
315
            $label = format_string($settingui->get_label($task), true, array('context' => $context));
316
            $labelicon = $settingui->get_icon();
317
            if (!empty($labelicon)) {
318
                $label .= $OUTPUT->render($labelicon);
319
            }
320
            $this->_form->addElement('static', 'static_'.$settingui->get_name(), $label, $settingui->get_static_value().$icon);
1441 ariadna 321
            $this->pop_group();
1 efrain 322
        }
323
        $this->_form->addElement('hidden', $settingui->get_name(), $settingui->get_value());
324
        $this->_form->setType($settingui->get_name(), $settingui->get_param_validation());
325
    }
326
 
327
    /**
1441 ariadna 328
     * Pushes a group start to the form.
329
     *
330
     * This method will create a new group div in the form and add it to the group stack.
331
     * The name can be used to close all stacked groups up to a certain group.
332
     *
333
     * @param string|null $name The name of the group, if any.
334
     * @param string $classes The classes to add to the div.
335
     */
336
    protected function push_group_start(?string $name, string $classes) {
337
        $mform = $this->_form;
338
        $this->groupstack[] = $name;
339
        $mform->addElement('html', html_writer::start_tag('div', ['class' => $classes]));
340
    }
341
 
342
    /**
343
     * Pops groups from the stack until the given group name is reached.
344
     *
345
     * @param string $name The name of the group to pop to.
346
     */
347
    protected function pop_groups_to(string $name) {
348
        if (empty($this->groupstack)) {
349
            return;
350
        }
351
        while (!empty($this->groupstack) && end($this->groupstack) !== $name) {
352
            $this->pop_group();
353
        }
354
    }
355
 
356
    /**
357
     * Pops a group from the stack and closes the div.
358
     *
359
     * @return string|null The name of the group that was popped, or null if the stack is empty.
360
     */
361
    protected function pop_group(): ?string {
362
        if (empty($this->groupstack)) {
363
            return null;
364
        }
365
        $mform = $this->_form;
366
        $mform->addElement('html', html_writer::end_tag('div'));
367
        return array_pop($this->groupstack);
368
    }
369
 
370
    /**
1 efrain 371
     * Adds dependencies to the form recursively
372
     *
373
     * @param backup_setting $setting
374
     */
375
    public function add_dependencies(backup_setting $setting) {
376
        $mform = $this->_form;
377
        // Apply all dependencies for backup.
378
        foreach ($setting->get_my_dependency_properties() as $key => $dependency) {
379
            call_user_func_array(array($this->_form, 'disabledIf'), array_values($dependency));
380
        }
381
    }
382
 
383
    /**
384
     * Returns true if the form was cancelled, false otherwise
385
     * @return bool
386
     */
387
    public function is_cancelled() {
388
        return (optional_param('cancel', false, PARAM_BOOL) || parent::is_cancelled());
389
    }
390
 
391
    /**
392
     * Removes an element from the form if it exists
393
     * @param string $elementname
394
     * @return bool
395
     */
396
    public function remove_element($elementname) {
397
        if ($this->_form->elementExists($elementname)) {
398
            return $this->_form->removeElement($elementname);
399
        } else {
400
            return false;
401
        }
402
    }
403
 
404
    /**
405
     * Gets an element from the form if it exists
406
     *
407
     * @param string $elementname
408
     * @return HTML_QuickForm_input|MoodleQuickForm_group
409
     */
410
    public function get_element($elementname) {
411
        if ($this->_form->elementExists($elementname)) {
412
            return $this->_form->getElement($elementname);
413
        } else {
414
            return false;
415
        }
416
    }
417
 
418
    /**
419
     * Displays the form
420
     */
421
    public function display() {
422
        global $PAGE, $COURSE;
423
 
424
        $this->require_definition_after_data();
425
 
426
        // Get list of module types on course.
427
        $modinfo = get_fast_modinfo($COURSE);
428
        $modnames = array_map('strval', $modinfo->get_used_module_names(true));
429
        core_collator::asort($modnames);
1441 ariadna 430
        $PAGE->requires->js_call_amd('core_backup/schema_backup_form', 'init', [$modnames]);
1 efrain 431
        $PAGE->requires->strings_for_js(array('select', 'all', 'none'), 'moodle');
432
        $PAGE->requires->strings_for_js(array('showtypes', 'hidetypes'), 'backup');
433
 
434
        parent::display();
435
    }
436
 
437
    /**
438
     * Ensures the the definition after data is loaded
439
     */
440
    public function require_definition_after_data() {
441
        if (!$this->_definition_finalized) {
442
            $this->definition_after_data();
443
        }
444
    }
445
}