2 // This file is part of Moodle - http://moodle.org/
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.
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.
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/>.
18 * This class represent the XMLDB base class where all the common pieces are defined
21 * @copyright 1999 onwards Martin Dougiamas http://dougiamas.com
22 * 2001-3001 Eloy Lafuente (stronk7) http://contiento.com
23 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
26 defined('MOODLE_INTERNAL') ||
die();
31 /** @var string name of obejct */
34 /** @var string comment on object */
37 /** @var xmldb_object */
40 /** @var xmldb_object */
43 /** @var string hash of object */
46 /** @var bool is it loaded yet */
49 /** @var bool was object changed */
52 /** @var string error message */
56 * Creates one new xmldb_object
59 public function __construct($name) {
61 $this->comment
= null;
62 $this->previous
= null;
65 $this->loaded
= false;
66 $this->changed
= false;
67 $this->errormsg
= null;
71 * This function returns true/false, if the xmldb_object has been loaded
74 public function isLoaded() {
79 * This function returns true/false, if the xmldb_object has changed
82 public function hasChanged() {
83 return $this->changed
;
87 * This function returns the comment of one xmldb_object
90 public function getComment() {
91 return $this->comment
;
95 * This function returns the hash of one xmldb_object
98 public function getHash() {
103 * This function will return the name of the previous xmldb_object
104 * @return xmldb_object
106 public function getPrevious() {
107 return $this->previous
;
111 * This function will return the name of the next xmldb_object
112 * @return xmldb_object
114 public function getNext() {
119 * This function will return the name of the xmldb_object
122 public function getName() {
127 * This function will return the error detected in the object
130 public function getError() {
131 return $this->errormsg
;
135 * This function will set the comment of the xmldb_object
136 * @param string $comment
138 public function setComment($comment) {
139 $this->comment
= $comment;
143 * This function will set the previous of the xmldb_object
144 * @param xmldb_object $previous
146 public function setPrevious($previous) {
147 $this->previous
= $previous;
151 * This function will set the next of the xmldb_object
152 * @param xmldb_object $next
154 public function setNext($next) {
159 * This function will set the hash of the xmldb_object
160 * @param string $hash
162 public function setHash($hash) {
167 * This function will set the loaded field of the xmldb_object
168 * @param bool $loaded
170 public function setLoaded($loaded = true) {
171 $this->loaded
= $loaded;
175 * This function will set the changed field of the xmldb_object
176 * @param bool $changed
178 public function setChanged($changed = true) {
179 $this->changed
= $changed;
182 * This function will set the name field of the xmldb_object
183 * @param string $name
185 public function setName($name) {
191 * This function will check if one key name is ok or no (true/false)
192 * only lowercase a-z, 0-9 and _ are allowed
195 public function checkName () {
198 if ($this->name
!= preg_replace('/[^a-z0-9_ -]/i', '', $this->name
)) {
205 * This function will check that all the elements in one array
206 * have a correct name [a-z0-9_]
210 public function checkNameValues($arr) {
212 // TODO: Perhaps, add support for reserved words
214 // Check the name only contains valid chars
216 foreach($arr as $element) {
217 if (!$element->checkName()) {
222 // Check there aren't duplicate names
224 $existing_fields = array();
225 foreach($arr as $element) {
226 if (in_array($element->getName(), $existing_fields)) {
227 debugging('Object ' . $element->getName() . ' is duplicated!', DEBUG_DEVELOPER
);
230 $existing_fields[] = $element->getName();
237 * Reconstruct previous/next attributes.
239 * @return bool true if $arr modified
241 public function fixPrevNext(&$arr) {
245 foreach ($arr as $key=>$el) {
246 $prev_value = $arr[$key]->previous
;
247 $next_value = $arr[$key]->next
;
249 $arr[$key]->next
= null;
250 $arr[$key]->previous
= null;
251 if ($prev !== null) {
252 $arr[$prev]->next
= $arr[$key]->name
;
253 $arr[$key]->previous
= $arr[$prev]->name
;
257 if ($prev_value != $arr[$key]->previous
or $next_value != $arr[$key]->next
) {
266 * This function will order all the elements in one array, following
267 * the previous/next rules
271 public function orderElements($arr) {
274 // Create a new array
277 $currentelement = null;
278 // Get the element without previous
279 foreach($arr as $key => $element) {
280 if (!$element->getPrevious()) {
281 $currentelement = $arr[$key];
282 $newarr[0] = $arr[$key];
285 if (!$currentelement) {
288 // Follow the next rules
290 while ($result && $currentelement->getNext()) {
291 $i = $this->findObjectInArray($currentelement->getNext(), $arr);
292 $currentelement = $arr[$i];
293 $newarr[$counter] = $arr[$i];
296 // Compare number of elements between original and new array
297 if ($result && count($arr) != count($newarr)) {
299 } else if ($newarr) {
311 * Returns the position of one object in the array.
312 * @param string $objectname
316 public function findObjectInArray($objectname, $arr) {
317 foreach ($arr as $i => $object) {
318 if ($objectname == $object->getName()) {
326 * This function will display a readable info about the xmldb_object
327 * (should be implemented inside each XMLDBxxx object)
330 public function readableInfo() {
331 return get_class($this);
335 * This function will perform the central debug of all the XMLDB classes
336 * being called automatically every time one error is found. Apart from
337 * the main actions performed in it (XMLDB agnostic) it looks for one
338 * function called xmldb_debug() and invokes it, passing both the
339 * message code and the whole object.
340 * So, to perform custom debugging just add such function to your libs.
342 * Call to the external hook function can be disabled by request by
343 * defining XMLDB_SKIP_DEBUG_HOOK
344 * @param string $message
346 public function debug($message) {
348 // Check for xmldb_debug($message, $xmldb_object)
349 $funcname = 'xmldb_debug';
350 // If exists and XMLDB_SKIP_DEBUG_HOOK is undefined
351 if (function_exists($funcname) && !defined('XMLDB_SKIP_DEBUG_HOOK')) {
352 $funcname($message, $this);
357 * Returns one array of elements from one comma separated string,
358 * supporting quoted strings containing commas and concat function calls
359 * @param string $string
362 public function comma2array($string) {
364 $foundquotes = array();
365 $foundconcats = array();
367 // Extract all the concat elements from the string
368 preg_match_all("/(CONCAT\(.*?\))/is", $string, $matches);
369 foreach (array_unique($matches[0]) as $key=>$value) {
370 $foundconcats['<#'.$key.'#>'] = $value;
372 if (!empty($foundconcats)) {
373 $string = str_replace($foundconcats,array_keys($foundconcats),$string);
376 // Extract all the quoted elements from the string (skipping
377 // backslashed quotes that are part of the content.
378 preg_match_all("/(''|'.*?[^\\\\]')/is", $string, $matches);
379 foreach (array_unique($matches[0]) as $key=>$value) {
380 $foundquotes['<%'.$key.'%>'] = $value;
382 if (!empty($foundquotes)) {
383 $string = str_replace($foundquotes,array_keys($foundquotes),$string);
386 // Explode safely the string
387 $arr = explode (',', $string);
389 // Put the concat and quoted elements back again, trimming every element
391 foreach ($arr as $key => $element) {
393 $element = trim($element);
394 // Replace the quoted elements if exists
395 if (!empty($foundquotes)) {
396 $element = str_replace(array_keys($foundquotes), $foundquotes, $element);
398 // Replace the concat elements if exists
399 if (!empty($foundconcats)) {
400 $element = str_replace(array_keys($foundconcats), $foundconcats, $element);
402 // Delete any backslash used for quotes. XMLDB stuff will add them before insert
403 $arr[$key] = str_replace("\\'", "'", $element);
411 * Validates the definition of objects and returns error message.
413 * The error message should not be localised because it is intended for developers,
414 * end users and admins should never see these problems!
416 * @param xmldb_table $xmldb_table optional when object is table
417 * @return string null if ok, error message if problem found
419 public function validateDefinition(xmldb_table
$xmldb_table=null) {