Proyectos de Subversion Moodle

Rev

| Ultima modificación | Ver Log |

Rev Autor Línea Nro. Línea
1 efrain 1
<?php
2
 
3
// This file is part of Moodle - http://moodle.org/
4
//
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.
9
//
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.
14
//
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/>.
17
 
18
/**
19
 * @package moodlecore
20
 * @subpackage backup-plan
21
 * @copyright 2010 onwards Eloy Lafuente (stronk7) {@link http://stronk7.com}
22
 * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
23
 */
24
 
25
/**
26
 * Abstract class defining the needed stuff to backup one @backup_structure
27
 *
28
 * TODO: Finish phpdocs
29
 */
30
abstract class backup_structure_step extends backup_step {
31
 
32
    /**
33
     * Name of the file to be generated
34
     * @var string
35
     */
36
    protected $filename;
37
 
38
    /**
39
     * xml content transformer being used (need it here, apart from xml_writer,
40
     * thanks to serialized data to process - say thanks to blocks!)
41
     * @var backup_xml_transformer|null
42
     */
43
    protected $contenttransformer;
44
 
45
    /**
46
     * Constructor - instantiates one object of this class
47
     */
48
    public function __construct($name, $filename, $task = null) {
49
        if (!is_null($task) && !($task instanceof backup_task)) {
50
            throw new backup_step_exception('wrong_backup_task_specified');
51
        }
52
        $this->filename = $filename;
53
        $this->contenttransformer = null;
54
        parent::__construct($name, $task);
55
    }
56
 
57
    public function execute() {
58
 
59
        if (!$this->execute_condition()) { // Check any condition to execute this
60
            return;
61
        }
62
 
63
        $fullpath = $this->task->get_taskbasepath();
64
 
65
        // We MUST have one fullpath here, else, error
66
        if (empty($fullpath)) {
67
            throw new backup_step_exception('backup_structure_step_undefined_fullpath');
68
        }
69
 
70
        // Append the filename to the fullpath
71
        $fullpath = rtrim($fullpath, '/') . '/' . $this->filename;
72
 
73
        // Create output, transformer, writer, processor
74
        $xo = new file_xml_output($fullpath);
75
        $xt = null;
76
        if (class_exists('backup_xml_transformer')) {
77
            $xt = new backup_xml_transformer($this->get_courseid());
78
            $this->contenttransformer = $xt; // Save the reference to the transformer
79
                                             // as far as we are going to need it out
80
                                             // from xml_writer (blame serialized data!)
81
        }
82
        $xw = new xml_writer($xo, $xt);
83
        $progress = $this->task->get_progress();
84
        $progress->start_progress($this->get_name());
85
        $pr = new backup_structure_processor($xw, $progress);
86
 
87
        // Set processor variables from settings
88
        foreach ($this->get_settings() as $setting) {
89
            $pr->set_var($setting->get_name(), $setting->get_value());
90
        }
91
        // Add backupid as one more var for processor
92
        $pr->set_var(backup::VAR_BACKUPID, $this->get_backupid());
93
 
94
        // Get structure definition
95
        $structure = $this->define_structure();
96
        if (! $structure instanceof backup_nested_element) {
97
            throw new backup_step_exception('backup_structure_step_wrong_structure');
98
        }
99
 
100
        // Start writer
101
        $xw->start();
102
 
103
        // Process structure definition
104
        $structure->process($pr);
105
 
106
        // Get the results from the nested elements
107
        $results = $structure->get_results();
108
 
109
        // Get the log messages to append to the log
110
        $logs = $structure->get_logs();
111
        foreach ($logs as $log) {
112
            $this->log($log->message, $log->level, $log->a, $log->depth, $log->display);
113
        }
114
 
115
        // Close everything
116
        $xw->stop();
117
        $progress->end_progress();
118
 
119
        // Destroy the structure. It helps PHP 5.2 memory a lot!
120
        $structure->destroy();
121
 
122
        return $results;
123
    }
124
 
125
    /**
126
     * As far as backup structure steps are implementing backup_plugin stuff, they need to
127
     * have the parent task available for wrapping purposes (get course/context....)
128
     */
129
    public function get_task() {
130
        return $this->task;
131
    }
132
 
133
// Protected API starts here
134
 
135
    /**
136
     * Add plugin structure to any element in the structure backup tree
137
     *
138
     * @param string $plugintype type of plugin as defined by core_component::get_plugin_types()
139
     * @param backup_nested_element $element element in the structure backup tree that
140
     *                                       we are going to add plugin information to
141
     * @param bool $multiple to define if multiple plugins can produce information
142
     *                       for each instance of $element (true) or no (false)
143
     */
144
    protected function add_plugin_structure($plugintype, $element, $multiple) {
145
 
146
        global $CFG;
147
 
148
        // Check the requested plugintype is a valid one
149
        if (!array_key_exists($plugintype, core_component::get_plugin_types($plugintype))) {
150
             throw new backup_step_exception('incorrect_plugin_type', $plugintype);
151
        }
152
 
153
        // Arrived here, plugin is correct, let's create the optigroup
154
        $optigroupname = $plugintype . '_' . $element->get_name() . '_plugin';
155
        $optigroup = new backup_optigroup($optigroupname, null, $multiple);
156
        $element->add_child($optigroup); // Add optigroup to stay connected since beginning
157
 
158
        // Get all the optigroup_elements, looking across all the plugin dirs
159
        $pluginsdirs = core_component::get_plugin_list($plugintype);
160
        foreach ($pluginsdirs as $name => $plugindir) {
161
            $classname = 'backup_' . $plugintype . '_' . $name . '_plugin';
162
            $backupfile = $plugindir . '/backup/moodle2/' . $classname . '.class.php';
163
            if (file_exists($backupfile)) {
164
                require_once($backupfile);
165
                $backupplugin = new $classname($plugintype, $name, $optigroup, $this);
166
                // Add plugin returned structure to optigroup
167
                $backupplugin->define_plugin_structure($element->get_name());
168
            }
169
        }
170
    }
171
 
172
    /**
173
     * Add subplugin structure for a given plugin to any element in the structure backup tree.
174
     *
175
     * This method allows the injection of subplugins (of a specified plugin) data to any
176
     * element in any backup structure.
177
     *
178
     * NOTE: Initially subplugins were only available for activities (mod), so only the
179
     * {@link backup_activity_structure_step} class had support for them, always
180
     * looking for /mod/modulenanme subplugins. This new method is a generalization of the
181
     * existing one for activities, supporting all subplugins injecting information everywhere.
182
     *
183
     * @param string $subplugintype type of subplugin as defined in plugin's db/subplugins.json.
184
     * @param backup_nested_element $element element in the backup tree (anywhere) that
185
     *                                       we are going to add subplugin information to.
186
     * @param bool $multiple to define if multiple subplugins can produce information
187
     *                       for each instance of $element (true) or no (false).
188
     * @param string $plugintype type of the plugin.
189
     * @param string $pluginname name of the plugin.
190
     * @return void
191
     */
192
    protected function add_subplugin_structure($subplugintype, $element, $multiple, $plugintype = null, $pluginname = null) {
193
        global $CFG;
194
        // This global declaration is required, because where we do require_once($backupfile);
195
        // That file may in turn try to do require_once($CFG->dirroot ...).
196
        // That worked in the past, we should keep it working.
197
 
198
        // Verify if this is a BC call for an activity backup. See NOTE above for this special case.
199
        if ($plugintype === null and $pluginname === null) {
200
            $plugintype = 'mod';
201
            $pluginname = $this->task->get_modulename();
202
            // TODO: Once all the calls have been changed to add both not null plugintype and pluginname, add a debugging here.
203
        }
204
 
205
        // Check the requested plugintype is a valid one.
206
        if (!array_key_exists($plugintype, core_component::get_plugin_types())) {
207
             throw new backup_step_exception('incorrect_plugin_type', $plugintype);
208
        }
209
 
210
        // Check the requested pluginname, for the specified plugintype, is a valid one.
211
        if (!array_key_exists($pluginname, core_component::get_plugin_list($plugintype))) {
212
             throw new backup_step_exception('incorrect_plugin_name', array($plugintype, $pluginname));
213
        }
214
 
215
        // Check the requested subplugintype is a valid one.
216
        $subplugins = core_component::get_subplugins("{$plugintype}_{$pluginname}");
217
        if (null === $subplugins) {
218
            throw new backup_step_exception('plugin_missing_subplugins_configuration', [$plugintype, $pluginname]);
219
        }
220
        if (!array_key_exists($subplugintype, $subplugins)) {
221
             throw new backup_step_exception('incorrect_subplugin_type', $subplugintype);
222
        }
223
 
224
        // Arrived here, subplugin is correct, let's create the optigroup.
225
        $optigroupname = $subplugintype . '_' . $element->get_name() . '_subplugin';
226
        $optigroup = new backup_optigroup($optigroupname, null, $multiple);
227
        $element->add_child($optigroup); // Add optigroup to stay connected since beginning.
228
 
229
        // Every subplugin optionally can have a common/parent subplugin
230
        // class for shared stuff.
231
        $parentclass = 'backup_' . $plugintype . '_' . $pluginname . '_' . $subplugintype . '_subplugin';
232
        $parentfile = core_component::get_component_directory($plugintype . '_' . $pluginname) .
233
            '/backup/moodle2/' . $parentclass . '.class.php';
234
        if (file_exists($parentfile)) {
235
            require_once($parentfile);
236
        }
237
 
238
        // Get all the optigroup_elements, looking over all the subplugin dirs.
239
        $subpluginsdirs = core_component::get_plugin_list($subplugintype);
240
        foreach ($subpluginsdirs as $name => $subpluginsdir) {
241
            $classname = 'backup_' . $subplugintype . '_' . $name . '_subplugin';
242
            $backupfile = $subpluginsdir . '/backup/moodle2/' . $classname . '.class.php';
243
            if (file_exists($backupfile)) {
244
                require_once($backupfile);
245
                $backupsubplugin = new $classname($subplugintype, $name, $optigroup, $this);
246
                // Add subplugin returned structure to optigroup.
247
                $backupsubplugin->define_subplugin_structure($element->get_name());
248
            }
249
        }
250
    }
251
 
252
    /**
253
     * To conditionally decide if one step will be executed or no
254
     *
255
     * For steps needing to be executed conditionally, based in dynamic
256
     * conditions (at execution time vs at declaration time) you must
257
     * override this function. It will return true if the step must be
258
     * executed and false if not
259
     */
260
    protected function execute_condition() {
261
        return true;
262
    }
263
 
264
    /**
265
     * Define the structure to be processed by this backup step.
266
     *
267
     * @return backup_nested_element
268
     */
269
    abstract protected function define_structure();
270
}