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-structure
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
 * TODO: Finish phpdocs
25
 */
26
 
27
/**
28
 * Abstract class representing one final element atom (name/value/parent) piece of information
29
 */
30
abstract class base_final_element extends base_atom {
31
 
32
    /** @var array base_attributes of the element (maps to XML attributes of the tag) */
33
        private $attributes;
34
 
35
    /** @var base_nested_element parent of this element (describes structure of the XML file) */
36
        private $parent;
37
 
38
    /**
39
     * Constructor - instantiates one base_final_element, specifying its basic info.
40
     *
41
     * @param string $name name of the element
42
     * @param array  $attributes attributes this element will handle (optional, defaults to null)
43
     */
44
    public function __construct($name, $attributes = null) {
45
        parent::__construct($name);
46
        $this->attributes = array();
47
        if (!empty($attributes)) {
48
            $this->add_attributes($attributes);
49
        }
50
        $this->parent = null;
51
    }
52
 
53
    /**
54
     * Destroy all circular references. It helps PHP 5.2 a lot!
55
     */
56
    public function destroy() {
57
        // No need to destroy anything recursively here, direct reset
58
        $this->attributes = array();
59
        $this->parent = null;
60
    }
61
 
62
    protected function set_parent($element) {
63
        if ($this->parent) {
64
            $info = new stdClass();
65
            $info->currparent= $this->parent->get_name();
66
            $info->newparent = $element->get_name();
67
            $info->element   = $this->get_name();
68
            throw new base_element_parent_exception('baseelementhasparent', $info);
69
        }
70
        $this->parent = $element;
71
    }
72
 
73
    protected function get_grandparent() {
74
        $parent = $this->parent;
75
        if ($parent instanceof base_nested_element) {
76
            return $parent->get_grandparent();
77
        } else {
78
            return $this;
79
        }
80
    }
81
 
82
    protected function get_grandoptigroupelement_or_grandparent() {
83
        $parent = $this->parent;
84
        if ($parent instanceof base_optigroup) {
85
            return $this; // Have found one parent optigroup, so I (first child of optigroup) am
86
        } else if ($parent instanceof base_nested_element) {
87
            return $parent->get_grandoptigroupelement_or_grandparent(); // Continue searching
88
        } else {
89
            return $this;
90
        }
91
    }
92
 
93
    protected function find_element_by_path($path) {
94
        $patharr = explode('/', trim($path, '/')); // Split the path trimming slashes
95
        if (substr($path, 0, 1) == '/') { // Absolute path, go to grandparent and process
96
            if (!$this->get_grandparent() instanceof base_nested_element) {
97
                throw new base_element_struct_exception('baseelementincorrectgrandparent', $patharr[0]);
98
            } else if ($this->get_grandparent()->get_name() !== $patharr[0]) {
99
                throw new base_element_struct_exception('baseelementincorrectgrandparent', $patharr[0]);
100
            } else {
101
                $newpath = implode('/', array_slice($patharr, 1)); // Take out 1st element
102
                return $this->get_grandparent()->find_element_by_path($newpath); // Process as relative in grandparent
103
            }
104
        } else {
105
            if ($patharr[0] == '..') { // Go to parent
106
                if (!$this->get_parent() instanceof base_nested_element) {
107
                    throw new base_element_struct_exception('baseelementincorrectparent', $patharr[0]);
108
                } else {
109
                    $newpath = implode('/', array_slice($patharr, 1)); // Take out 1st element
110
                    return $this->get_parent()->find_element_by_path($newpath); // Process as relative in parent
111
                }
112
            } else if (count($patharr) > 1) { // Go to next child
113
                if (!$this->get_child($patharr[0]) instanceof base_nested_element) {
114
                    throw new base_element_struct_exception('baseelementincorrectchild', $patharr[0]);
115
                } else {
116
                    $newpath = implode('/', array_slice($patharr, 1)); // Take out 1st element
117
                    return $this->get_child($patharr[0])->find_element_by_path($newpath); // Process as relative in parent
118
                }
119
            } else { // Return final element or attribute
120
                if ($this->get_final_element($patharr[0]) instanceof base_final_element) {
121
                    return $this->get_final_element($patharr[0]);
122
                } else if ($this->get_attribute($patharr[0]) instanceof base_attribute) {
123
                    return $this->get_attribute($patharr[0]);
124
                } else {
125
                    throw new base_element_struct_exception('baseelementincorrectfinalorattribute', $patharr[0]);
126
                }
127
            }
128
        }
129
    }
130
 
131
    protected function find_first_parent_by_name($name) {
132
        if ($parent = $this->get_parent()) { // If element has parent
133
            $element   = $parent->get_final_element($name); // Look for name into parent finals
134
            $attribute = $parent->get_attribute($name);     // Look for name into parent attrs
135
            if ($element instanceof base_final_element) {
136
                return $element;
137
 
138
            } else if ($attribute instanceof base_attribute) {
139
                return $attribute;
140
 
141
            } else { // Not found, go up 1 level and continue searching
142
                return $parent->find_first_parent_by_name($name);
143
            }
144
        } else { // No more parents available, return the original backup::VAR_PARENTID, exception
145
            throw new base_element_struct_exception('cannotfindparentidforelement', $name);
146
        }
147
    }
148
 
149
 
150
/// Public API starts here
151
 
152
    public function get_attributes() {
153
        return $this->attributes;
154
    }
155
 
156
    public function get_attribute($name) {
157
        if (array_key_exists($name, $this->attributes)) {
158
            return $this->attributes[$name];
159
        } else {
160
            return null;
161
        }
162
    }
163
 
164
    public function get_parent() {
165
        return $this->parent;
166
    }
167
 
168
    public function get_level() {
169
        return $this->parent == null ? 1 : $this->parent->get_level() + 1;
170
    }
171
 
172
    public function add_attributes($attributes) {
173
        if ($attributes instanceof base_attribute || is_string($attributes)) { // Accept 1 attribute, object or string
174
            $attributes = array($attributes);
175
        }
176
        if (is_array($attributes)) {
177
            foreach ($attributes as $attribute) {
178
                if (is_string($attribute)) { // Accept string attributes
179
                    $attribute = $this->get_new_attribute($attribute);
180
                }
181
                if (!($attribute instanceof base_attribute)) {
182
                    throw new base_element_attribute_exception('baseelementnoattribute', get_class($attribute));
183
                }
184
                if (array_key_exists($attribute->get_name(), $this->attributes)) {
185
                    throw new base_element_attribute_exception('baseelementattributeexists', $attribute->get_name());
186
                }
187
                $this->attributes[$attribute->get_name()] = $attribute;
188
            }
189
        } else {
190
            throw new base_element_attribute_exception('baseelementattributeincorrect');
191
        }
192
    }
193
 
194
    public function clean_values() {
195
        parent::clean_value();
196
        if (!empty($this->attributes)) {
197
            foreach ($this->attributes as $attribute) {
198
                $attribute->clean_value();
199
            }
200
        }
201
    }
202
 
203
    public function to_string($showvalue = false) {
204
        // Decide the correct prefix
205
        $prefix = '#'; // default
206
        if ($this->parent instanceof base_optigroup) {
207
            $prefix = '?';
208
        } else if ($this instanceof base_nested_element) {
209
            $prefix = '';
210
        }
211
        $indent = str_repeat('    ', $this->get_level()); // Indent output based in level (4cc)
212
        $output = $indent . $prefix . $this->get_name() . ' (level: ' . $this->get_level() . ')';
213
        if ($showvalue) {
214
            $value = $this->is_set() ? $this->get_value() : 'not set';
215
            $output .= ' => ' . $value;
216
        }
217
        if (!empty($this->attributes)) {
218
            foreach ($this->attributes as $attribute) {
219
                $output .= PHP_EOL . $indent . '    ' . $attribute->to_string($showvalue);
220
            }
221
        }
222
        return $output;
223
    }
224
 
225
// Implementable API
226
 
227
    /**
228
     * Returns one instace of the @base_attribute class to work with
229
     * when attributes are added simply by name
230
     */
231
    abstract protected function get_new_attribute($name);
232
}
233
 
234
/**
235
 * base_element exception to control all the errors related with parents handling
236
 */
237
class base_element_parent_exception extends base_atom_exception {
238
 
239
    /**
240
     * Constructor - instantiates one base_element_parent_exception
241
     *
242
     * @param string $errorcode key for the corresponding error string
243
     * @param object $a extra words and phrases that might be required in the error string
244
     * @param string $debuginfo optional debugging information
245
     */
246
    public function __construct($errorcode, $a = null, $debuginfo = null) {
247
        parent::__construct($errorcode, $a, $debuginfo);
248
    }
249
}
250
 
251
/**
252
 * base_element exception to control all the errors related with attributes handling
253
 */
254
class base_element_attribute_exception extends base_atom_exception {
255
 
256
    /**
257
     * Constructor - instantiates one base_element_attribute_exception
258
     *
259
     * @param string $errorcode key for the corresponding error string
260
     * @param object $a extra words and phrases that might be required in the error string
261
     * @param string $debuginfo optional debugging information
262
     */
263
    public function __construct($errorcode, $a = null, $debuginfo = null) {
264
        parent::__construct($errorcode, $a, $debuginfo);
265
    }
266
}