fields = array(); $this->keys = array(); $this->indexes = array(); } /** * Add one field to the table, allowing to specify the desired order * If it's not specified, then the field is added at the end */ function addField(&$field, $after=NULL) { /// Calculate the previous and next fields $prevfield = NULL; $nextfield = NULL; if (!$after) { $allfields =& $this->getFields(); if (!empty($allfields)) { end($allfields); $prevfield =& $allfields[key($allfields)]; } } else { $prevfield =& $this->getField($after); } if ($prevfield && $prevfield->getNext()) { $nextfield =& $this->getField($prevfield->getNext()); } /// Set current field previous and next attributes if ($prevfield) { $field->setPrevious($prevfield->getName()); $prevfield->setNext($field->getName()); } if ($nextfield) { $field->setNext($nextfield->getName()); $nextfield->setPrevious($field->getName()); } /// Some more attributes $field->setLoaded(true); $field->setChanged(true); /// Add the new field $this->fields[] = $field; /// Reorder the field $this->orderFields($this->fields); /// Recalculate the hash $this->calculateHash(true); /// We have one new field, so the table has changed $this->setChanged(true); return $field; } /** * Add one key to the table, allowing to specify the desired order * If it's not specified, then the key is added at the end */ function addKey(&$key, $after=NULL) { /// Calculate the previous and next keys $prevkey = NULL; $nextkey = NULL; if (!$after) { $allkeys =& $this->getKeys(); if (!empty($allkeys)) { end($allkeys); $prevkey =& $allkeys[key($allkeys)]; } } else { $prevkey =& $this->getKey($after); } if ($prevkey && $prevkey->getNext()) { $nextkey =& $this->getKey($prevkey->getNext()); } /// Set current key previous and next attributes if ($prevkey) { $key->setPrevious($prevkey->getName()); $prevkey->setNext($key->getName()); } if ($nextkey) { $key->setNext($nextkey->getName()); $nextkey->setPrevious($key->getName()); } /// Some more attributes $key->setLoaded(true); $key->setChanged(true); /// Add the new key $this->keys[] = $key; /// Reorder the keys $this->orderKeys($this->keys); /// Recalculate the hash $this->calculateHash(true); /// We have one new field, so the table has changed $this->setChanged(true); } /** * Add one index to the table, allowing to specify the desired order * If it's not specified, then the index is added at the end */ function addIndex(&$index, $after=NULL) { /// Calculate the previous and next indexes $previndex = NULL; $nextindex = NULL; if (!$after) { $allindexes =& $this->getIndexes(); if (!empty($allindexes)) { end($allindexes); $previndex =& $allindexes[key($allindexes)]; } } else { $previndex =& $this->getIndex($after); } if ($previndex && $previndex->getNext()) { $nextindex =& $this->getIndex($previndex->getNext()); } /// Set current index previous and next attributes if ($previndex) { $index->setPrevious($previndex->getName()); $previndex->setNext($index->getName()); } if ($nextindex) { $index->setNext($nextindex->getName()); $nextindex->setPrevious($index->getName()); } /// Some more attributes $index->setLoaded(true); $index->setChanged(true); /// Add the new index $this->indexes[] = $index; /// Reorder the indexes $this->orderIndexes($this->indexes); /// Recalculate the hash $this->calculateHash(true); /// We have one new index, so the table has changed $this->setChanged(true); } /** * This function will return the array of fields in the table */ function &getFields() { return $this->fields; } /** * This function will return the array of keys in the table */ function &getKeys() { return $this->keys; } /** * This function will return the array of indexes in the table */ function &getIndexes() { return $this->indexes; } /** * Returns one XMLDBField */ function &getField($fieldname) { $i = $this->findFieldInArray($fieldname); if ($i !== NULL) { return $this->fields[$i]; } $null = NULL; return $null; } /** * Returns the position of one field in the array. */ function &findFieldInArray($fieldname) { foreach ($this->fields as $i => $field) { if ($fieldname == $field->getName()) { return $i; } } $null = NULL; return $null; } /** * This function will reorder the array of fields */ function orderFields() { $result = $this->orderElements($this->fields); if ($result) { $this->setFields($result); return true; } else { return false; } } /** * Returns one XMLDBKey */ function &getKey($keyname) { $i = $this->findKeyInArray($keyname); if ($i !== NULL) { return $this->keys[$i]; } $null = NULL; return $null; } /** * Returns the position of one key in the array. */ function &findKeyInArray($keyname) { foreach ($this->keys as $i => $key) { if ($keyname == $key->getName()) { return $i; } } $null = NULL; return $null; } /** * This function will reorder the array of keys */ function orderKeys() { $result = $this->orderElements($this->keys); if ($result) { $this->setKeys($result); return true; } else { return false; } } /** * Returns one XMLDBIndex */ function &getIndex($indexname) { $i = $this->findIndexInArray($indexname); if ($i !== NULL) { return $this->indexes[$i]; } $null = NULL; return $null; } /** * Returns the position of one index in the array. */ function &findIndexInArray($indexname) { foreach ($this->indexes as $i => $index) { if ($indexname == $index->getName()) { return $i; } } $null = NULL; return $null; } /** * This function will reorder the array of indexes */ function orderIndexes() { $result = $this->orderElements($this->indexes); if ($result) { $this->setIndexes($result); return true; } else { return false; } } /** * This function will set the array of fields in the table */ function setFields($fields) { $this->fields = $fields; } /** * This function will set the array of keys in the table */ function setKeys($keys) { $this->keys = $keys; } /** * This function will set the array of indexes in the table */ function setIndexes($indexes) { $this->indexes = $indexes; } /** * Delete one field from the table */ function deleteField($fieldname) { $field =& $this->getField($fieldname); if ($field) { $i = $this->findFieldInArray($fieldname); $prevfield = NULL; $nextfield = NULL; /// Look for prev and next field $prevfield =& $this->getField($field->getPrevious()); $nextfield =& $this->getField($field->getNext()); /// Change their previous and next attributes if ($prevfield) { $prevfield->setNext($field->getNext()); } if ($nextfield) { $nextfield->setPrevious($field->getPrevious()); } /// Delete the field unset($this->fields[$i]); /// Reorder the whole structure $this->orderFields($this->fields); /// Recalculate the hash $this->calculateHash(true); /// We have one deleted field, so the table has changed $this->setChanged(true); } } /** * Delete one key from the table */ function deleteKey($keyname) { $key =& $this->getKey($keyname); if ($key) { $i = $this->findKeyInArray($keyname); $prevkey = NULL; $nextkey = NULL; /// Look for prev and next key $prevkey =& $this->getKey($key->getPrevious()); $nextkey =& $this->getKey($key->getNext()); /// Change their previous and next attributes if ($prevkey) { $prevkey->setNext($key->getNext()); } if ($nextkey) { $nextkey->setPrevious($key->getPrevious()); } /// Delete the key unset($this->keys[$i]); /// Reorder the Keys $this->orderKeys($this->keys); /// Recalculate the hash $this->calculateHash(true); /// We have one deleted key, so the table has changed $this->setChanged(true); } } /** * Delete one index from the table */ function deleteIndex($indexname) { $index =& $this->getIndex($indexname); if ($index) { $i = $this->findIndexInArray($indexname); $previndex = NULL; $nextindex = NULL; /// Look for prev and next index $previndex =& $this->getIndex($index->getPrevious()); $nextindex =& $this->getIndex($index->getNext()); /// Change their previous and next attributes if ($previndex) { $previndex->setNext($index->getNext()); } if ($nextindex) { $nextindex->setPrevious($index->getPrevious()); } /// Delete the index unset($this->indexes[$i]); /// Reorder the indexes $this->orderIndexes($this->indexes); /// Recalculate the hash $this->calculateHash(true); /// We have one deleted index, so the table has changed $this->setChanged(true); } } /** * Load data from XML to the table */ function arr2XMLDBTable($xmlarr) { global $CFG; $result = true; /// Debug the table /// traverse_xmlize($xmlarr); //Debug /// print_object ($GLOBALS['traverse_array']); //Debug /// $GLOBALS['traverse_array']=""; //Debug /// Process table attributes (name, comment, previoustable and nexttable) if (isset($xmlarr['@']['NAME'])) { $this->name = trim($xmlarr['@']['NAME']); } else { $this->errormsg = 'Missing NAME attribute'; $this->debug($this->errormsg); $result = false; } if (isset($xmlarr['@']['COMMENT'])) { $this->comment = trim($xmlarr['@']['COMMENT']); } else if (!empty($CFG->xmldbdisablecommentchecking)) { $this->comment = ''; } else { $this->errormsg = 'Missing COMMENT attribute'; $this->debug($this->errormsg); $result = false; } if (isset($xmlarr['@']['PREVIOUS'])) { $this->previous = trim($xmlarr['@']['PREVIOUS']); } if (isset($xmlarr['@']['NEXT'])) { $this->next = trim($xmlarr['@']['NEXT']); } /// Iterate over fields if (isset($xmlarr['#']['FIELDS']['0']['#']['FIELD'])) { foreach ($xmlarr['#']['FIELDS']['0']['#']['FIELD'] as $xmlfield) { if (!$result) { //Skip on error continue; } $name = trim($xmlfield['@']['NAME']); $field = new XMLDBField($name); $field->arr2XMLDBField($xmlfield); $this->fields[] = $field; if (!$field->isLoaded()) { $this->errormsg = 'Problem loading field ' . $name; $this->debug($this->errormsg); $result = false; } } } else { $this->errormsg = 'Missing FIELDS section'; $this->debug($this->errormsg); $result = false; } /// Perform some general checks over fields if ($result && $this->fields) { /// Check field names are ok (lowercase, a-z _-) if (!$this->checkNameValues($this->fields)) { $this->errormsg = 'Some FIELDS name values are incorrect'; $this->debug($this->errormsg); $result = false; } /// Check previous & next are ok (duplicates and existing fields) $this->fixPrevNext($this->fields); if ($result && !$this->checkPreviousNextValues($this->fields)) { $this->errormsg = 'Some FIELDS previous/next values are incorrect'; $this->debug($this->errormsg); $result = false; } /// Order fields if ($result && !$this->orderFields($this->fields)) { $this->errormsg = 'Error ordering the fields'; $this->debug($this->errormsg); $result = false; } } /// Iterate over keys if (isset($xmlarr['#']['KEYS']['0']['#']['KEY'])) { foreach ($xmlarr['#']['KEYS']['0']['#']['KEY'] as $xmlkey) { if (!$result) { //Skip on error continue; } $name = trim($xmlkey['@']['NAME']); $key = new XMLDBKey($name); $key->arr2XMLDBKey($xmlkey); $this->keys[] = $key; if (!$key->isLoaded()) { $this->errormsg = 'Problem loading key ' . $name; $this->debug($this->errormsg); $result = false; } } } else { $this->errormsg = 'Missing KEYS section (at least one PK must exist)'; $this->debug($this->errormsg); $result = false; } /// Perform some general checks over keys if ($result && $this->keys) { /// Check keys names are ok (lowercase, a-z _-) if (!$this->checkNameValues($this->keys)) { $this->errormsg = 'Some KEYS name values are incorrect'; $this->debug($this->errormsg); $result = false; } /// Check previous & next are ok (duplicates and existing keys) $this->fixPrevNext($this->keys); if ($result && !$this->checkPreviousNextValues($this->keys)) { $this->errormsg = 'Some KEYS previous/next values are incorrect'; $this->debug($this->errormsg); $result = false; } /// Order keys if ($result && !$this->orderKeys($this->keys)) { $this->errormsg = 'Error ordering the keys'; $this->debug($this->errormsg); $result = false; } /// TODO: Only one PK /// TODO: Not keys with repeated fields /// TODO: Check fields and reffieds exist in table } /// Iterate over indexes if (isset($xmlarr['#']['INDEXES']['0']['#']['INDEX'])) { foreach ($xmlarr['#']['INDEXES']['0']['#']['INDEX'] as $xmlindex) { if (!$result) { //Skip on error continue; } $name = trim($xmlindex['@']['NAME']); $index = new XMLDBIndex($name); $index->arr2XMLDBIndex($xmlindex); $this->indexes[] = $index; if (!$index->isLoaded()) { $this->errormsg = 'Problem loading index ' . $name; $this->debug($this->errormsg); $result = false; } } } /// Perform some general checks over indexes if ($result && $this->indexes) { /// Check field names are ok (lowercase, a-z _-) if (!$this->checkNameValues($this->indexes)) { $this->errormsg = 'Some INDEXES name values are incorrect'; $this->debug($this->errormsg); $result = false; } /// Check previous & next are ok (duplicates and existing INDEXES) $this->fixPrevNext($this->indexes); if ($result && !$this->checkPreviousNextValues($this->indexes)) { $this->errormsg = 'Some INDEXES previous/next values are incorrect'; $this->debug($this->errormsg); $result = false; } /// Order indexes if ($result && !$this->orderIndexes($this->indexes)) { $this->errormsg = 'Error ordering the indexes'; $this->debug($this->errormsg); $result = false; } /// TODO: Not indexes with repeated fields /// TODO: Check fields exist in table } /// Set some attributes if ($result) { $this->loaded = true; } $this->calculateHash(); return $result; } /** * This function calculate and set the hash of one XMLDBTable */ function calculateHash($recursive = false) { if (!$this->loaded) { $this->hash = NULL; } else { $key = $this->name . $this->comment; if ($this->fields) { foreach ($this->fields as $fie) { $field =& $this->getField($fie->getName()); if ($recursive) { $field->calculateHash($recursive); } $key .= $field->getHash(); } } if ($this->keys) { foreach ($this->keys as $ke) { $k =& $this->getKey($ke->getName()); if ($recursive) { $k->calculateHash($recursive); } $key .= $k->getHash(); } } if ($this->indexes) { foreach ($this->indexes as $in) { $index =& $this->getIndex($in->getName()); if ($recursive) { $index->calculateHash($recursive); } $key .= $index->getHash(); } } $this->hash = md5($key); } } /** * This function will output the XML text for one table */ function xmlOutput() { $o = ''; $o.= '