| // +----------------------------------------------------------------------+ // // $Id$ // require_once 'XML/Parser.php'; require_once 'MDB2/Schema/Validate.php'; if (empty($GLOBALS['_MDB2_Schema_Reserved'])) { $GLOBALS['_MDB2_Schema_Reserved'] = array(); } /** * Parses an XML schema file * * @package MDB2_Schema * @category Database * @access protected * @author Christian Dickmann */ class MDB2_Schema_Parser extends XML_Parser { var $database_definition = array('name' => '', 'create' => '', 'overwrite' => '', 'tables' => array(), 'sequences' => array()); var $elements = array(); var $element = ''; var $count = 0; var $table = array(); var $table_name = ''; var $field = array(); var $field_name = ''; var $init = array(); var $init_function = array(); var $init_expression = array(); var $init_field = array(); var $index = array(); var $index_name = ''; var $var_mode = false; var $variables = array(); var $sequence = array(); var $sequence_name = ''; var $error; var $structure = false; var $val; function __construct($variables, $fail_on_invalid_names = true, $structure = false, $valid_types = array(), $force_defaults = true) { // force ISO-8859-1 due to different defaults for PHP4 and PHP5 // todo: this probably needs to be investigated some more andcleaned up parent::XML_Parser('ISO-8859-1'); $this->variables = $variables; $this->structure = $structure; $this->val =& new MDB2_Schema_Validate($fail_on_invalid_names, $valid_types, $force_defaults); } function MDB2_Schema_Parser($variables, $fail_on_invalid_names = true, $structure = false, $valid_types = array(), $force_defaults = true) { $this->__construct($variables, $fail_on_invalid_names, $structure, $valid_types, $force_defaults); } function startHandler($xp, $element, $attribs) { if (strtolower($element) == 'variable') { $this->var_mode = true; return; } $this->elements[$this->count++] = strtolower($element); $this->element = implode('-', $this->elements); switch ($this->element) { /* Initialization */ case 'database-table-initialization': $this->table['initialization'] = array(); break; /* Insert */ /* insert: field+ */ case 'database-table-initialization-insert': $this->init = array('type' => 'insert', 'data' => array('field' => array())); break; /* Update */ /* update: field+, where? */ case 'database-table-initialization-update': $this->init = array('type' => 'update', 'data' => array('field' => array())); break; /* Delete */ /* delete: where */ case 'database-table-initialization-delete': $this->init = array('type' => 'delete', 'data' => array('where' => array())); break; /* Insert and Update */ case 'database-table-initialization-insert-field': case 'database-table-initialization-update-field': $this->init_field = array('name' => '', 'group' => array()); break; case 'database-table-initialization-insert-field-value': case 'database-table-initialization-update-field-value': /* if value tag is empty cdataHandler is not called so we must force value element creation here */ $this->init_field['group'] = array('type' => 'value', 'data' => ''); break; case 'database-table-initialization-insert-field-null': case 'database-table-initialization-update-field-null': $this->init_field['group'] = array('type' => 'null'); break; case 'database-table-initialization-insert-field-function': case 'database-table-initialization-update-field-function': $this->init_function = array(); break; case 'database-table-initialization-insert-field-expression': case 'database-table-initialization-update-field-expression': $this->init_expression = array(); break; /* Update and Delete */ case 'database-table-initialization-update-where': case 'database-table-initialization-delete-where': $this->init['data']['where'] = array('type' => '', 'data' => array()); break; case 'database-table-initialization-update-where-expression': case 'database-table-initialization-delete-where-expression': $this->init_expression = array(); break; /* One level simulation of expression-function recursion */ case 'database-table-initialization-insert-field-expression-function': case 'database-table-initialization-update-field-expression-function': case 'database-table-initialization-update-where-expression-function': case 'database-table-initialization-delete-where-expression-function': $this->init_function = array(); break; /* One level simulation of function-expression recursion */ case 'database-table-initialization-insert-field-function-expression': case 'database-table-initialization-update-field-function-expression': case 'database-table-initialization-update-where-function-expression': case 'database-table-initialization-delete-where-function-expression': $this->init_expression = array(); break; /* Definition */ case 'database-table': $this->table_name = ''; $this->table = array('fields' => array(), 'indexes' => array()); break; case 'database-table-declaration-field': $this->field_name = ''; $this->field = array(); break; case 'database-table-declaration-field-default': $this->field['default'] = ''; break; case 'database-table-declaration-index': $this->index_name = ''; $this->index = array('fields' => array()); break; case 'database-sequence': $this->sequence_name = ''; $this->sequence = array(); break; case 'database-table-declaration-index-field': $this->field_name = ''; $this->field = array(); break; } } function endHandler($xp, $element) { if (strtolower($element) == 'variable') { $this->var_mode = false; return; } switch ($this->element) { /* Initialization */ /* Insert and Delete */ case 'database-table-initialization-insert-field': case 'database-table-initialization-update-field': $result = $this->val->validateDataField($this->table['fields'], $this->init['data']['field'], $this->init_field); if (PEAR::isError($result)) { $this->raiseError($result->getUserinfo(), 0, $xp, $result->getCode()); } else { $this->init['data']['field'][] = $this->init_field; } break; case 'database-table-initialization-insert-field-function': case 'database-table-initialization-update-field-function': $this->init_field['group'] = array('type' => 'function', 'data' => $this->init_function); break; case 'database-table-initialization-insert-field-expression': case 'database-table-initialization-update-field-expression': $this->init_field['group'] = array('type' => 'expression', 'data' => $this->init_expression); break; /* Delete and Update */ case 'database-table-initialization-update-where-expression': case 'database-table-initialization-delete-where-expression': $this->init['data']['where']['type'] = 'expression'; $this->init['data']['where']['data'] = $this->init_expression; break; /* All */ case 'database-table-initialization-insert': case 'database-table-initialization-delete': case 'database-table-initialization-update': $this->table['initialization'][] = $this->init; break; /* One level simulation of expression-function recursion */ case 'database-table-initialization-insert-field-expression-function': case 'database-table-initialization-update-field-expression-function': case 'database-table-initialization-update-where-expression-function': case 'database-table-initialization-delete-where-expression-function': $this->init_expression['operants'][] = array('type' => 'function', 'data' => $this->init_function); break; /* One level simulation of function-expression recursion */ case 'database-table-initialization-insert-field-function-expression': case 'database-table-initialization-update-field-function-expression': case 'database-table-initialization-update-where-function-expression': case 'database-table-initialization-delete-where-function-expression': $this->init_function['arguments'][] = array('type' => 'expression', 'data' => $this->init_expression); break; /* Table definition */ case 'database-table': $result = $this->val->validateTable($this->database_definition['tables'], $this->table, $this->table_name); if (PEAR::isError($result)) { $this->raiseError($result->getUserinfo(), 0, $xp, $result->getCode()); } else { $this->database_definition['tables'][$this->table_name] = $this->table; } break; case 'database-table-name': if (isset($this->structure['tables'][$this->table_name])) { $this->table = $this->structure['tables'][$this->table_name]; } break; /* Field declaration */ case 'database-table-declaration-field': $result = $this->val->validateField($this->table['fields'], $this->field, $this->field_name); if (PEAR::isError($result)) { $this->raiseError($result->getUserinfo(), 0, $xp, $result->getCode()); } else { $this->table['fields'][$this->field_name] = $this->field; } break; /* Index declaration */ case 'database-table-declaration-index': $result = $this->val->validateIndex($this->table['indexes'], $this->index, $this->index_name); if (PEAR::isError($result)) { $this->raiseError($result->getUserinfo(), 0, $xp, $result->getCode()); } else { $this->table['indexes'][$this->index_name] = $this->index; } break; case 'database-table-declaration-index-field': $result = $this->val->validateIndexField($this->index['fields'], $this->field, $this->field_name); if (PEAR::isError($result)) { $this->raiseError($result->getUserinfo(), 0, $xp, $result->getCode()); } else { $this->index['fields'][$this->field_name] = $this->field; } break; /* Sequence declaration */ case 'database-sequence': $result = $this->val->validateSequence($this->database_definition['sequences'], $this->sequence, $this->sequence_name); if (PEAR::isError($result)) { $this->raiseError($result->getUserinfo(), 0, $xp, $result->getCode()); } else { $this->database_definition['sequences'][$this->sequence_name] = $this->sequence; } break; /* End of File */ case 'database': $result = $this->val->validateDatabase($this->database_definition); if (PEAR::isError($result)) { $this->raiseError($result->getUserinfo(), 0, $xp, $result->getCode()); } break; } unset($this->elements[--$this->count]); $this->element = implode('-', $this->elements); } function &raiseError($msg = null, $xmlecode = 0, $xp = null, $ecode = MDB2_SCHEMA_ERROR_PARSE) { if (is_null($this->error)) { $error = ''; if (is_resource($msg)) { $error.= 'Parser error: '.xml_error_string(xml_get_error_code($msg)); $xp = $msg; } else { $error.= 'Parser error: '.$msg; if (!is_resource($xp)) { $xp = $this->parser; } } if ($error_string = xml_error_string($xmlecode)) { $error.= ' - '.$error_string; } if (is_resource($xp)) { $byte = @xml_get_current_byte_index($xp); $line = @xml_get_current_line_number($xp); $column = @xml_get_current_column_number($xp); $error.= " - Byte: $byte; Line: $line; Col: $column"; } $error.= "\n"; $this->error =& MDB2_Schema::raiseError($ecode, null, null, $error); } return $this->error; } function cdataHandler($xp, $data) { if ($this->var_mode == true) { if (!isset($this->variables[$data])) { $this->raiseError('variable "'.$data.'" not found', null, $xp); return; } $data = $this->variables[$data]; } switch ($this->element) { /* Initialization */ /* Insert and Update */ case 'database-table-initialization-insert-field-name': case 'database-table-initialization-update-field-name': $this->init_field['name'] = $data; break; case 'database-table-initialization-insert-field-value': case 'database-table-initialization-update-field-value': $this->init_field['group'] = array('type' => 'value', 'data' => $data); break; case 'database-table-initialization-insert-field-function-name': case 'database-table-initialization-update-field-function-name': $this->init_function['name'] = $data; break; case 'database-table-initialization-insert-field-function-value': case 'database-table-initialization-update-field-function-value': $this->init_function['arguments'][] = array('type' => 'value', 'data' => $data); break; case 'database-table-initialization-insert-field-function-column': case 'database-table-initialization-update-field-function-column': $this->init_function['arguments'][] = array('type' => 'column', 'data' => $data); break; /* Update */ case 'database-table-initialization-update-field-column': $this->init_field['group'] = array('type' => 'column', 'data' => $data); break; /* All */ case 'database-table-initialization-insert-field-expression-operator': case 'database-table-initialization-update-field-expression-operator': case 'database-table-initialization-update-where-expression-operator': case 'database-table-initialization-delete-where-expression-operator': $this->init_expression['operator'] = $data; break; case 'database-table-initialization-insert-field-expression-value': case 'database-table-initialization-update-field-expression-value': case 'database-table-initialization-update-where-expression-value': case 'database-table-initialization-delete-where-expression-value': $this->init_expression['operants'][] = array('type' => 'value', 'data' => $data); break; case 'database-table-initialization-insert-field-expression-column': case 'database-table-initialization-update-field-expression-column': case 'database-table-initialization-update-where-expression-column': case 'database-table-initialization-delete-where-expression-column': $this->init_expression['operants'][] = array('type' => 'column', 'data' => $data); break; case 'database-table-initialization-insert-field-function-function': case 'database-table-initialization-insert-field-function-expression': case 'database-table-initialization-insert-field-expression-expression': case 'database-table-initialization-update-field-function-function': case 'database-table-initialization-update-field-function-expression': case 'database-table-initialization-update-field-expression-expression': case 'database-table-initialization-update-where-expression-expression': case 'database-table-initialization-delete-where-expression-expression': /* Recursion to be implemented yet */ break; /* One level simulation of expression-function recursion */ case 'database-table-initialization-insert-field-expression-function-name': case 'database-table-initialization-update-field-expression-function-name': case 'database-table-initialization-update-where-expression-function-name': case 'database-table-initialization-delete-where-expression-function-name': $this->init_function['name'] = $data; break; case 'database-table-initialization-insert-field-expression-function-value': case 'database-table-initialization-update-field-expression-function-value': case 'database-table-initialization-update-where-expression-function-value': case 'database-table-initialization-delete-where-expression-function-value': $this->init_function['arguments'][] = array('type' => 'value', 'data' => $data); break; case 'database-table-initialization-insert-field-expression-function-column': case 'database-table-initialization-update-field-expression-function-column': case 'database-table-initialization-update-where-expression-function-column': case 'database-table-initialization-delete-where-expression-function-column': $this->init_function['arguments'][] = array('type' => 'column', 'data' => $data); break; /* One level simulation of function-expression recursion */ case 'database-table-initialization-insert-field-function-expression-operator': case 'database-table-initialization-update-field-function-expression-operator': $this->init_expression['operator'] = $data; break; case 'database-table-initialization-insert-field-function-expression-value': case 'database-table-initialization-update-field-function-expression-value': $this->init_expression['operants'][] = array('type' => 'value', 'data' => $data); break; case 'database-table-initialization-insert-field-function-expression-column': case 'database-table-initialization-update-field-function-expression-column': $this->init_expression['operants'][] = array('type' => 'column', 'data' => $data); break; /* Database */ case 'database-name': if (isset($this->database_definition['name'])) { $this->database_definition['name'].= $data; } else { $this->database_definition['name'] = $data; } break; case 'database-create': if (isset($this->database_definition['create'])) { $this->database_definition['create'].= $data; } else { $this->database_definition['create'] = $data; } break; case 'database-overwrite': if (isset($this->database_definition['overwrite'])) { $this->database_definition['overwrite'].= $data; } else { $this->database_definition['overwrite'] = $data; } break; case 'database-table-name': if (isset($this->table_name)) { $this->table_name.= $data; } else { $this->table_name = $data; } break; case 'database-table-was': if (isset($this->table['was'])) { $this->table['was'].= $data; } else { $this->table['was'] = $data; } break; /* Field declaration */ case 'database-table-declaration-field-name': if (isset($this->field_name)) { $this->field_name.= $data; } else { $this->field_name = $data; } break; case 'database-table-declaration-field-type': if (isset($this->field['type'])) { $this->field['type'].= $data; } else { $this->field['type'] = $data; } break; case 'database-table-declaration-field-was': if (isset($this->field['was'])) { $this->field['was'].= $data; } else { $this->field['was'] = $data; } break; case 'database-table-declaration-field-notnull': if (isset($this->field['notnull'])) { $this->field['notnull'].= $data; } else { $this->field['notnull'] = $data; } break; case 'database-table-declaration-field-fixed': if (isset($this->field['fixed'])) { $this->field['fixed'].= $data; } else { $this->field['fixed'] = $data; } break; case 'database-table-declaration-field-unsigned': if (isset($this->field['unsigned'])) { $this->field['unsigned'].= $data; } else { $this->field['unsigned'] = $data; } break; case 'database-table-declaration-field-autoincrement': if (isset($this->field['autoincrement'])) { $this->field['autoincrement'].= $data; } else { $this->field['autoincrement'] = $data; } break; case 'database-table-declaration-field-default': if (isset($this->field['default'])) { $this->field['default'].= $data; } else { $this->field['default'] = $data; } break; case 'database-table-declaration-field-length': if (isset($this->field['length'])) { $this->field['length'].= $data; } else { $this->field['length'] = $data; } break; /* Index declaration */ case 'database-table-declaration-index-name': if (isset($this->index_name)) { $this->index_name.= $data; } else { $this->index_name = $data; } break; case 'database-table-declaration-index-primary': if (isset($this->index['primary'])) { $this->index['primary'].= $data; } else { $this->index['primary'] = $data; } break; case 'database-table-declaration-index-unique': if (isset($this->index['unique'])) { $this->index['unique'].= $data; } else { $this->index['unique'] = $data; } break; case 'database-table-declaration-index-was': if (isset($this->index['was'])) { $this->index['was'].= $data; } else { $this->index['was'] = $data; } break; case 'database-table-declaration-index-field-name': if (isset($this->field_name)) { $this->field_name.= $data; } else { $this->field_name = $data; } break; case 'database-table-declaration-index-field-sorting': if (isset($this->field['sorting'])) { $this->field['sorting'].= $data; } else { $this->field['sorting'] = $data; } break; /* Add by Leoncx */ case 'database-table-declaration-index-field-length': if (isset($this->field['length'])) { $this->field['length'].= $data; } else { $this->field['length'] = $data; } break; /* Sequence declaration */ case 'database-sequence-name': if (isset($this->sequence_name)) { $this->sequence_name.= $data; } else { $this->sequence_name = $data; } break; case 'database-sequence-was': if (isset($this->sequence['was'])) { $this->sequence['was'].= $data; } else { $this->sequence['was'] = $data; } break; case 'database-sequence-start': if (isset($this->sequence['start'])) { $this->sequence['start'].= $data; } else { $this->sequence['start'] = $data; } break; case 'database-sequence-on-table': if (isset($this->sequence['on']['table'])) { $this->sequence['on']['table'].= $data; } else { $this->sequence['on']['table'] = $data; } break; case 'database-sequence-on-field': if (isset($this->sequence['on']['field'])) { $this->sequence['on']['field'].= $data; } else { $this->sequence['on']['field'] = $data; } break; } } } ?>