parent
24b10be762
commit
5686183e43
@ -0,0 +1,220 @@ |
||||
<?php |
||||
/** |
||||
* Copyright (c) 2012 Bart Visscher <bartv@thisnet.nl> |
||||
* This file is licensed under the Affero General Public License version 3 or |
||||
* later. |
||||
* See the COPYING-README file. |
||||
*/ |
||||
|
||||
class OC_DB_MDB2SchemaReader { |
||||
static protected $DBNAME; |
||||
static protected $DBTABLEPREFIX; |
||||
|
||||
public static function loadSchemaFromFile($file) { |
||||
self::$DBNAME = OC_Config::getValue( "dbname", "owncloud" ); |
||||
self::$DBTABLEPREFIX = OC_Config::getValue( "dbtableprefix", "oc_" ); |
||||
$schema = new \Doctrine\DBAL\Schema\Schema(); |
||||
$xml = simplexml_load_file($file); |
||||
foreach($xml->children() as $child) { |
||||
switch($child->getName()) { |
||||
case 'name': |
||||
$name = (string)$child; |
||||
$name = str_replace( '*dbname*', self::$DBNAME, $name ); |
||||
break; |
||||
case 'create': |
||||
case 'overwrite': |
||||
case 'charset': |
||||
break; |
||||
case 'table': |
||||
self::loadTable($schema, $child); |
||||
break; |
||||
default: |
||||
var_dump($child->getName()); |
||||
|
||||
} |
||||
} |
||||
return $schema; |
||||
} |
||||
|
||||
private static function loadTable($schema, $xml) { |
||||
foreach($xml->children() as $child) { |
||||
switch($child->getName()) { |
||||
case 'name': |
||||
$name = (string)$child; |
||||
$name = str_replace( '*dbprefix*', self::$DBTABLEPREFIX, $name ); |
||||
$table = $schema->createTable($name); |
||||
break; |
||||
case 'create': |
||||
case 'overwrite': |
||||
case 'charset': |
||||
break; |
||||
case 'declaration': |
||||
self::loadDeclaration($table, $child); |
||||
break; |
||||
default: |
||||
var_dump($child->getName()); |
||||
|
||||
} |
||||
} |
||||
} |
||||
|
||||
private static function loadDeclaration($table, $xml) { |
||||
foreach($xml->children() as $child) { |
||||
switch($child->getName()) { |
||||
case 'field': |
||||
self::loadField($table, $child); |
||||
break; |
||||
case 'index': |
||||
self::loadIndex($table, $child); |
||||
break; |
||||
default: |
||||
var_dump($child->getName()); |
||||
|
||||
} |
||||
} |
||||
} |
||||
|
||||
private static function loadField($table, $xml) { |
||||
$options = array(); |
||||
foreach($xml->children() as $child) { |
||||
switch($child->getName()) { |
||||
case 'name': |
||||
$name = (string)$child; |
||||
break; |
||||
case 'type': |
||||
$type = (string)$child; |
||||
switch($type) { |
||||
case 'text': |
||||
$type = 'string'; |
||||
break; |
||||
case 'clob': |
||||
$type = 'text'; |
||||
break; |
||||
case 'timestamp': |
||||
$type = 'datetime'; |
||||
break; |
||||
// TODO |
||||
return; |
||||
} |
||||
break; |
||||
case 'length': |
||||
$length = (string)$child; |
||||
$options['length'] = $length; |
||||
break; |
||||
case 'unsigned': |
||||
$unsigned = self::asBool($child); |
||||
$options['unsigned'] = $unsigned; |
||||
break; |
||||
case 'notnull': |
||||
$notnull = self::asBool($child); |
||||
$options['notnull'] = $notnull; |
||||
break; |
||||
case 'autoincrement': |
||||
$autoincrement = self::asBool($child); |
||||
$options['autoincrement'] = $autoincrement; |
||||
break; |
||||
case 'default': |
||||
$default = (string)$child; |
||||
$options['default'] = $default; |
||||
break; |
||||
default: |
||||
var_dump($child->getName()); |
||||
|
||||
} |
||||
} |
||||
if (isset($name) && isset($type)) { |
||||
if ($name == 'x') { |
||||
var_dump($name, $type, $options); |
||||
echo '<pre>'; |
||||
debug_print_backtrace(); |
||||
} |
||||
if (empty($options['default'])) { |
||||
if ($type == 'integer') { |
||||
if (empty($options['default'])) { |
||||
$options['default'] = 0; |
||||
} |
||||
} |
||||
if (!empty($options['autoincrement'])) { |
||||
unset($options['default']); |
||||
} |
||||
} |
||||
if ($type == 'integer') { |
||||
$length = $options['length']; |
||||
if ($length == 1) { |
||||
$type = 'boolean'; |
||||
} |
||||
else if ($length < 4) { |
||||
$type = 'smallint'; |
||||
} |
||||
else if ($length > 4) { |
||||
$type = 'bigint'; |
||||
} |
||||
} |
||||
$table->addColumn($name, $type, $options); |
||||
if (!empty($options['autoincrement']) |
||||
&& !empty($options['notnull'])) { |
||||
$table->setPrimaryKey(array($name)); |
||||
} |
||||
} |
||||
} |
||||
|
||||
private static function loadIndex($table, $xml) { |
||||
$name = null; |
||||
$fields = array(); |
||||
foreach($xml->children() as $child) { |
||||
switch($child->getName()) { |
||||
case 'name': |
||||
$name = (string)$child; |
||||
break; |
||||
case 'primary': |
||||
$primary = self::asBool($child); |
||||
break; |
||||
case 'unique': |
||||
$unique = self::asBool($child); |
||||
break; |
||||
case 'field': |
||||
foreach($child->children() as $field) { |
||||
switch($field->getName()) { |
||||
case 'name': |
||||
$field_name = (string)$field; |
||||
$fields[] = $field_name; |
||||
break; |
||||
case 'sorting': |
||||
break; |
||||
default: |
||||
var_dump($field->getName()); |
||||
|
||||
} |
||||
} |
||||
break; |
||||
default: |
||||
var_dump($child->getName()); |
||||
|
||||
} |
||||
} |
||||
if (!empty($fields)) { |
||||
if (isset($primary) && $primary) { |
||||
$table->setPrimaryKey($fields, $name); |
||||
} else |
||||
if (isset($unique) && $unique) { |
||||
$table->addUniqueIndex($fields, $name); |
||||
} else { |
||||
$table->addIndex($fields, $name); |
||||
} |
||||
} else { |
||||
var_dump($name, $fields); |
||||
} |
||||
} |
||||
|
||||
private static function asBool($xml) { |
||||
$result = (string)$xml; |
||||
if ($result == 'true') { |
||||
$result = true; |
||||
} else |
||||
if ($result == 'false') { |
||||
$result = false; |
||||
} |
||||
return (bool)$result; |
||||
} |
||||
|
||||
} |
@ -0,0 +1,128 @@ |
||||
<?php |
||||
/** |
||||
* Copyright (c) 2012 Bart Visscher <bartv@thisnet.nl> |
||||
* This file is licensed under the Affero General Public License version 3 or |
||||
* later. |
||||
* See the COPYING-README file. |
||||
*/ |
||||
|
||||
class OC_DB_Schema { |
||||
private static $DBNAME; |
||||
private static $DBTABLEPREFIX; |
||||
|
||||
/** |
||||
* @brief saves database scheme to xml file |
||||
* @param string $file name of file |
||||
* @param int $mode |
||||
* @return bool |
||||
* |
||||
* TODO: write more documentation |
||||
*/ |
||||
public static function getDbStructure( $conn, $file ,$mode=MDB2_SCHEMA_DUMP_STRUCTURE) { |
||||
$sm = $conn->getSchemaManager(); |
||||
$fromSchema = $sm->createSchema(); |
||||
|
||||
return OC_DB_MDB2SchemaWriter::saveSchemaToFile($file); |
||||
} |
||||
|
||||
/** |
||||
* @brief Creates tables from XML file |
||||
* @param string $file file to read structure from |
||||
* @return bool |
||||
* |
||||
* TODO: write more documentation |
||||
*/ |
||||
public static function createDbFromStructure( $conn, $file ) { |
||||
$toSchema = OC_DB_MDB2SchemaReader::loadSchemaFromFile($file); |
||||
return self::executeSchemaChange($conn, $toSchema); |
||||
} |
||||
|
||||
/** |
||||
* @brief update the database scheme |
||||
* @param string $file file to read structure from |
||||
* @return bool |
||||
*/ |
||||
public static function updateDbFromStructure($conn, $file) { |
||||
$sm = $conn->getSchemaManager(); |
||||
$fromSchema = $sm->createSchema(); |
||||
|
||||
$toSchema = OC_DB_MDB2SchemaReader::loadSchemaFromFile($file); |
||||
|
||||
// remove tables we don't know about |
||||
foreach($fromSchema->getTables() as $table) { |
||||
if (!$toSchema->hasTable($table->getName())) { |
||||
$fromSchema->dropTable($table->getName()); |
||||
} |
||||
} |
||||
|
||||
$comparator = new \Doctrine\DBAL\Schema\Comparator(); |
||||
$schemaDiff = $comparator->compare($fromSchema, $toSchema); |
||||
|
||||
//$from = $fromSchema->toSql($conn->getDatabasePlatform()); |
||||
//$to = $toSchema->toSql($conn->getDatabasePlatform()); |
||||
//echo($from[9]); |
||||
//echo '<br>'; |
||||
//echo($to[9]); |
||||
//var_dump($from, $to); |
||||
return self::executeSchemaChange($conn, $schemaDiff); |
||||
} |
||||
|
||||
/** |
||||
* @brief drop a table |
||||
* @param string $tableName the table to drop |
||||
*/ |
||||
public static function dropTable($conn, $tableName) { |
||||
$sm = $conn->getSchemaManager(); |
||||
$fromSchema = $sm->createSchema(); |
||||
$toSchema = clone $fromSchema; |
||||
$toSchema->dropTable('user'); |
||||
$sql = $fromSchema->getMigrateToSql($toSchema, $conn->getDatabasePlatform()); |
||||
var_dump($sql); |
||||
die; |
||||
$conn->execute($sql); |
||||
} |
||||
|
||||
/** |
||||
* remove all tables defined in a database structure xml file |
||||
* @param string $file the xml file describing the tables |
||||
*/ |
||||
public static function removeDBStructure($conn, $file) { |
||||
$fromSchema = OC_DB_MDB2SchemaReader::loadSchemaFromFile($file); |
||||
$toSchema = clone $fromSchema; |
||||
foreach($toSchema->getTables() as $table) { |
||||
$toSchema->dropTable($table->getName()); |
||||
} |
||||
$comparator = new \Doctrine\DBAL\Schema\Comparator(); |
||||
$schemaDiff = $comparator->compare($fromSchema, $toSchema); |
||||
self::executeSchemaChange($conn, $schemaDiff); |
||||
} |
||||
|
||||
/** |
||||
* @brief replaces the owncloud tables with a new set |
||||
* @param $file string path to the MDB2 xml db export file |
||||
*/ |
||||
public static function replaceDB( $conn, $file ) { |
||||
$apps = OC_App::getAllApps(); |
||||
self::beginTransaction(); |
||||
// Delete the old tables |
||||
self::removeDBStructure( OC::$SERVERROOT . '/db_structure.xml' ); |
||||
|
||||
foreach($apps as $app) { |
||||
$path = OC_App::getAppPath($app).'/appinfo/database.xml'; |
||||
if(file_exists($path)) { |
||||
self::removeDBStructure( $path ); |
||||
} |
||||
} |
||||
|
||||
// Create new tables |
||||
self::commit(); |
||||
} |
||||
|
||||
private static function executeSchemaChange($conn, $schema) { |
||||
$conn->beginTransaction(); |
||||
foreach($schema->toSql($conn->getDatabasePlatform()) as $sql) { |
||||
$conn->query($sql); |
||||
} |
||||
$conn->commit(); |
||||
} |
||||
} |
Loading…
Reference in new issue