3 ///////////////////////////////////////////////////////////////////////////
5 // NOTICE OF COPYRIGHT //
7 // Moodle - Modular Object-Oriented Dynamic Learning Environment //
8 // http://moodle.com //
10 // Copyright (C) 1999 onwards Martin Dougiamas http://dougiamas.com //
11 // (C) 2001-3001 Eloy Lafuente (stronk7) http://contiento.com //
13 // This program is free software; you can redistribute it and/or modify //
14 // it under the terms of the GNU General Public License as published by //
15 // the Free Software Foundation; either version 2 of the License, or //
16 // (at your option) any later version. //
18 // This program is distributed in the hope that it will be useful, //
19 // but WITHOUT ANY WARRANTY; without even the implied warranty of //
20 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
21 // GNU General Public License for more details: //
23 // http://www.gnu.org/copyleft/gpl.html //
25 ///////////////////////////////////////////////////////////////////////////
27 /// This class represent the XMLDB base class where all the common piezes
42 * Creates one new XMLDBObject
44 function XMLDBObject($name) {
46 $this->comment
= NULL;
47 $this->previous
= NULL;
50 $this->loaded
= false;
51 $this->changed
= false;
52 $this->errormsg
= NULL;
56 * This function returns true/false, if the XMLDBObject has been loaded
63 * This function returns true/false, if the XMLDBObject has changed
65 function hasChanged() {
66 return $this->changed
;
70 * This function returns the comment of one XMLDBObject
72 function getComment() {
73 return $this->comment
;
77 * This function returns the hash of one XMLDBObject
84 * This function will return the name of the previous XMLDBObject
86 function getPrevious() {
87 return $this->previous
;
91 * This function will return the name of the next XMLDBObject
98 * This function will return the name of the XMLDBObject
105 * This function will return the error detected in the object
107 function getError() {
108 return $this->errormsg
;
112 * This function will set the comment of the XMLDB object
114 function setComment($comment) {
115 $this->comment
= $comment;
119 * This function will set the previous of the XMLDB object
121 function setPrevious($previous) {
122 $this->previous
= $previous;
126 * This function will set the next of the XMLDB object
128 function setNext($next) {
133 * This function will set the hash of the XMLDB object
135 function setHash($hash) {
140 * This function will set the loaded field of the XMLDB object
142 function setLoaded($loaded = true) {
143 $this->loaded
= $loaded;
147 * This function will set the changed field of the XMLDB object
149 function setChanged($changed = true) {
150 $this->changed
= $changed;
153 * This function will set the name field of the XMLDB object
155 function setName($name) {
161 * This function will check if one key name is ok or no (true/false)
162 * only lowercase a-z, 0-9 and _ are allowed
164 function checkName () {
167 if ($this->name
!= eregi_replace('[^a-z0-9_ -]', '', $this->name
)) {
174 * This function will check that all the elements in one array
175 * have a correct name [a-z0-9_]
177 function checkNameValues(&$arr) {
179 /// TODO: Perhaps, add support for reserved words
181 /// Check the name only contains valid chars
183 foreach($arr as $element) {
184 if (!$element->checkName()) {
193 * Reconstruct previous/next attributes.
195 function fixPrevNext(&$arr) {
198 if (empty($CFG->xmldbreconstructprevnext
)) {
204 foreach ($arr as $key=>$el) {
205 $prev_value = $arr[$key]->previous
;
206 $next_value = $arr[$key]->next
;
208 $arr[$key]->next
= null;
209 $arr[$key]->previous
= null;
210 if ($prev !== null) {
211 $arr[$prev]->next
= $arr[$key]->name
;
212 $arr[$key]->previous
= $arr[$prev]->name
;
216 if ($prev_value != $arr[$key]->previous
or $next_value != $arr[$key]->next
) {
225 * This function will check that all the elements in one array
226 * have a consistent info in their previous/next fields
228 function checkPreviousNextValues(&$arr) {
230 if (!empty($CFG->xmldbdisablenextprevchecking
)) {
234 /// Check that only one element has the previous not set
237 foreach($arr as $element) {
238 if (!$element->getPrevious()) {
246 /// Check that only one element has the next not set
247 if ($result && $arr) {
249 foreach($arr as $element) {
250 if (!$element->getNext()) {
258 /// Check that all the previous elements are existing elements
259 if ($result && $arr) {
260 foreach($arr as $element) {
261 if ($element->getPrevious()) {
262 $i = $this->findObjectInArray($element->getPrevious(), $arr);
269 /// Check that all the next elements are existing elements
270 if ($result && $arr) {
271 foreach($arr as $element) {
272 if ($element->getNext()) {
273 $i = $this->findObjectInArray($element->getNext(), $arr);
280 /// Check that there aren't duplicates in the previous values
281 if ($result && $arr) {
283 foreach($arr as $element) {
284 if (in_array($element->getPrevious(), $existarr)) {
287 $existarr[] = $element->getPrevious();
291 /// Check that there aren't duplicates in the next values
292 if ($result && $arr) {
294 foreach($arr as $element) {
295 if (in_array($element->getNext(), $existarr)) {
298 $existarr[] = $element->getNext();
306 * This function will order all the elements in one array, following
307 * the previous/next rules
309 function orderElements($arr) {
312 if (!empty($CFG->xmldbdisablenextprevchecking
)) {
315 /// Create a new array
318 $currentelement = NULL;
319 /// Get the element without previous
320 foreach($arr as $key => $element) {
321 if (!$element->getPrevious()) {
322 $currentelement = $arr[$key];
323 $newarr[0] = $arr[$key];
326 if (!$currentelement) {
329 /// Follow the next rules
331 while ($result && $currentelement->getNext()) {
332 $i = $this->findObjectInArray($currentelement->getNext(), $arr);
333 $currentelement = $arr[$i];
334 $newarr[$counter] = $arr[$i];
337 /// Compare number of elements between original and new array
338 if ($result && count($arr) != count($newarr)) {
341 /// Check that previous/next is ok (redundant but...)
342 if ($this->checkPreviousNextValues($newarr)) {
354 * Returns the position of one object in the array.
356 function &findObjectInArray($objectname, $arr) {
357 foreach ($arr as $i => $object) {
358 if ($objectname == $object->getName()) {
367 * This function will display a readable info about the XMLDBObject
368 * (should be implemented inside each XMLDBxxx object)
370 function readableInfo() {
371 return get_class($this);
375 * This function will perform the central debug of all the XMLDB classes
376 * being called automatically every time one error is found. Apart from
377 * the main actions performed in it (XMLDB agnostic) it looks for one
378 * function called xmldb_debug() and invokes it, passing both the
379 * message code and the whole object.
380 * So, to perform custom debugging just add such function to your libs.
382 * Call to the external hook function can be disabled by request by
383 * defining XMLDB_SKIP_DEBUG_HOOK
385 function debug($message) {
387 /// Check for xmldb_debug($message, $xmldb_object)
388 $funcname = 'xmldb_debug';
389 /// If exists and XMLDB_SKIP_DEBUG_HOOK is undefined
390 if (function_exists($funcname) && !defined('XMLDB_SKIP_DEBUG_HOOK')) {
391 $funcname($message, $this);
396 * Returns one array of elements from one comma separated string,
397 * supporting quoted strings containing commas and concat function calls
399 function comma2array($string) {
403 $foundquotes = array();
404 $foundconcats = array();
406 /// Extract all the concat elements from the string
407 preg_match_all("/(CONCAT\(.*?\))/is", $string, $matches);
408 foreach (array_unique($matches[0]) as $key=>$value) {
409 $foundconcats['<#'.$key.'#>'] = $value;
411 if (!empty($foundconcats)) {
412 $string = str_replace($foundconcats,array_keys($foundconcats),$string);
415 /// Extract all the quoted elements from the string (skipping
416 /// backslashed quotes that are part of the content.
417 preg_match_all("/('.*?[^\\\]')/is", $string, $matches);
418 foreach (array_unique($matches[0]) as $key=>$value) {
419 $foundquotes['<%'.$key.'%>'] = $value;
421 if (!empty($foundquotes)) {
422 $string = str_replace($foundquotes,array_keys($foundquotes),$string);
425 /// Explode safely the string
426 $arr = explode (',', $string);
428 /// Put the concat and quoted elements back again, triming every element
430 foreach ($arr as $key => $element) {
431 /// Clear some spaces
432 $element = trim($element);
433 /// Replace the quoted elements if exists
434 if (!empty($foundquotes)) {
435 $element = str_replace(array_keys($foundquotes), $foundquotes, $element);
437 /// Replace the concat elements if exists
438 if (!empty($foundconcats)) {
439 $element = str_replace(array_keys($foundconcats), $foundconcats, $element);
441 /// Delete any backslash used for quotes. XMLDB stuff will add them before insert
442 $arr[$key] = str_replace("\\'", "'", $element);