forked from moodle/moodle
-
Notifications
You must be signed in to change notification settings - Fork 0
/
xmldb_object.php
422 lines (371 loc) · 12.1 KB
/
xmldb_object.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* This class represent the XMLDB base class where all the common pieces are defined
*
* @package core_xmldb
* @copyright 1999 onwards Martin Dougiamas http://dougiamas.com
* 2001-3001 Eloy Lafuente (stronk7) http://contiento.com
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
defined('MOODLE_INTERNAL') || die();
class xmldb_object {
/** @var string name of obejct */
protected $name;
/** @var string comment on object */
protected $comment;
/** @var xmldb_object */
protected $previous;
/** @var xmldb_object */
protected $next;
/** @var string hash of object */
protected $hash;
/** @var bool is it loaded yet */
protected $loaded;
/** @var bool was object changed */
protected $changed;
/** @var string error message */
protected $errormsg;
/**
* Creates one new xmldb_object
* @param string $name
*/
public function __construct($name) {
$this->name = $name;
$this->comment = null;
$this->previous = null;
$this->next = null;
$this->hash = null;
$this->loaded = false;
$this->changed = false;
$this->errormsg = null;
}
/**
* This function returns true/false, if the xmldb_object has been loaded
* @return bool
*/
public function isLoaded() {
return $this->loaded;
}
/**
* This function returns true/false, if the xmldb_object has changed
* @return bool
*/
public function hasChanged() {
return $this->changed;
}
/**
* This function returns the comment of one xmldb_object
* @return string
*/
public function getComment() {
return $this->comment;
}
/**
* This function returns the hash of one xmldb_object
* @return string
*/
public function getHash() {
return $this->hash;
}
/**
* This function will return the name of the previous xmldb_object
* @return xmldb_object
*/
public function getPrevious() {
return $this->previous;
}
/**
* This function will return the name of the next xmldb_object
* @return xmldb_object
*/
public function getNext() {
return $this->next;
}
/**
* This function will return the name of the xmldb_object
* @return string
*/
public function getName() {
return $this->name;
}
/**
* This function will return the error detected in the object
* @return string
*/
public function getError() {
return $this->errormsg;
}
/**
* This function will set the comment of the xmldb_object
* @param string $comment
*/
public function setComment($comment) {
$this->comment = $comment;
}
/**
* This function will set the previous of the xmldb_object
* @param xmldb_object $previous
*/
public function setPrevious($previous) {
$this->previous = $previous;
}
/**
* This function will set the next of the xmldb_object
* @param xmldb_object $next
*/
public function setNext($next) {
$this->next = $next;
}
/**
* This function will set the hash of the xmldb_object
* @param string $hash
*/
public function setHash($hash) {
$this->hash = $hash;
}
/**
* This function will set the loaded field of the xmldb_object
* @param bool $loaded
*/
public function setLoaded($loaded = true) {
$this->loaded = $loaded;
}
/**
* This function will set the changed field of the xmldb_object
* @param bool $changed
*/
public function setChanged($changed = true) {
$this->changed = $changed;
}
/**
* This function will set the name field of the xmldb_object
* @param string $name
*/
public function setName($name) {
$this->name = $name;
}
/**
* This function will check if one key name is ok or no (true/false)
* only lowercase a-z, 0-9 and _ are allowed
* @return bool
*/
public function checkName () {
$result = true;
if ($this->name != preg_replace('/[^a-z0-9_ -]/i', '', $this->name)) {
$result = false;
}
return $result;
}
/**
* This function will check that all the elements in one array
* have a correct name [a-z0-9_]
* @param array $arr
* @return bool
*/
public function checkNameValues($arr) {
$result = true;
// TODO: Perhaps, add support for reserved words
// Check the name only contains valid chars
if ($arr) {
foreach($arr as $element) {
if (!$element->checkName()) {
$result = false;
}
}
}
// Check there aren't duplicate names
if ($arr) {
$existing_fields = array();
foreach($arr as $element) {
if (in_array($element->getName(), $existing_fields)) {
debugging('Object ' . $element->getName() . ' is duplicated!', DEBUG_DEVELOPER);
$result = false;
}
$existing_fields[] = $element->getName();
}
}
return $result;
}
/**
* Reconstruct previous/next attributes.
* @param array $arr
* @return bool true if $arr modified
*/
public function fixPrevNext(&$arr) {
$tweaked = false;
$prev = null;
foreach ($arr as $key=>$el) {
$prev_value = $arr[$key]->previous;
$next_value = $arr[$key]->next;
$arr[$key]->next = null;
$arr[$key]->previous = null;
if ($prev !== null) {
$arr[$prev]->next = $arr[$key]->name;
$arr[$key]->previous = $arr[$prev]->name;
}
$prev = $key;
if ($prev_value != $arr[$key]->previous or $next_value != $arr[$key]->next) {
$tweaked = true;
}
}
return $tweaked;
}
/**
* This function will order all the elements in one array, following
* the previous/next rules
* @param array $arr
* @return array|bool
*/
public function orderElements($arr) {
$result = true;
// Create a new array
$newarr = array();
if (!empty($arr)) {
$currentelement = null;
// Get the element without previous
foreach($arr as $key => $element) {
if (!$element->getPrevious()) {
$currentelement = $arr[$key];
$newarr[0] = $arr[$key];
}
}
if (!$currentelement) {
$result = false;
}
// Follow the next rules
$counter = 1;
while ($result && $currentelement->getNext()) {
$i = $this->findObjectInArray($currentelement->getNext(), $arr);
$currentelement = $arr[$i];
$newarr[$counter] = $arr[$i];
$counter++;
}
// Compare number of elements between original and new array
if ($result && count($arr) != count($newarr)) {
$result = false;
} else if ($newarr) {
$result = $newarr;
} else {
$result = false;
}
} else {
$result = array();
}
return $result;
}
/**
* Returns the position of one object in the array.
* @param string $objectname
* @param array $arr
* @return mixed
*/
public function findObjectInArray($objectname, $arr) {
foreach ($arr as $i => $object) {
if ($objectname == $object->getName()) {
return $i;
}
}
return null;
}
/**
* This function will display a readable info about the xmldb_object
* (should be implemented inside each XMLDBxxx object)
* @return string
*/
public function readableInfo() {
return get_class($this);
}
/**
* This function will perform the central debug of all the XMLDB classes
* being called automatically every time one error is found. Apart from
* the main actions performed in it (XMLDB agnostic) it looks for one
* function called xmldb_debug() and invokes it, passing both the
* message code and the whole object.
* So, to perform custom debugging just add such function to your libs.
*
* Call to the external hook function can be disabled by request by
* defining XMLDB_SKIP_DEBUG_HOOK
* @param string $message
*/
public function debug($message) {
// Check for xmldb_debug($message, $xmldb_object)
$funcname = 'xmldb_debug';
// If exists and XMLDB_SKIP_DEBUG_HOOK is undefined
if (function_exists($funcname) && !defined('XMLDB_SKIP_DEBUG_HOOK')) {
$funcname($message, $this);
}
}
/**
* Returns one array of elements from one comma separated string,
* supporting quoted strings containing commas and concat function calls
* @param string $string
* @return array
*/
public function comma2array($string) {
$foundquotes = array();
$foundconcats = array();
// Extract all the concat elements from the string
preg_match_all("/(CONCAT\(.*?\))/is", $string, $matches);
foreach (array_unique($matches[0]) as $key=>$value) {
$foundconcats['<#'.$key.'#>'] = $value;
}
if (!empty($foundconcats)) {
$string = str_replace($foundconcats,array_keys($foundconcats),$string);
}
// Extract all the quoted elements from the string (skipping
// backslashed quotes that are part of the content.
preg_match_all("/(''|'.*?[^\\\\]')/is", $string, $matches);
foreach (array_unique($matches[0]) as $key=>$value) {
$foundquotes['<%'.$key.'%>'] = $value;
}
if (!empty($foundquotes)) {
$string = str_replace($foundquotes,array_keys($foundquotes),$string);
}
// Explode safely the string
$arr = explode (',', $string);
// Put the concat and quoted elements back again, trimming every element
if ($arr) {
foreach ($arr as $key => $element) {
// Clear some spaces
$element = trim($element);
// Replace the quoted elements if exists
if (!empty($foundquotes)) {
$element = str_replace(array_keys($foundquotes), $foundquotes, $element);
}
// Replace the concat elements if exists
if (!empty($foundconcats)) {
$element = str_replace(array_keys($foundconcats), $foundconcats, $element);
}
// Delete any backslash used for quotes. XMLDB stuff will add them before insert
$arr[$key] = str_replace("\\'", "'", $element);
}
}
return $arr;
}
/**
* Validates the definition of objects and returns error message.
*
* The error message should not be localised because it is intended for developers,
* end users and admins should never see these problems!
*
* @param xmldb_table $xmldb_table optional when object is table
* @return string null if ok, error message if problem found
*/
public function validateDefinition(xmldb_table $xmldb_table=null) {
return null;
}
}