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