1
0
mirror of synced 2024-12-05 03:06:05 +03:00

Connection refactoring to allow create/drop database functionality for sqlite. fixes #480

This commit is contained in:
jwage 2008-01-22 21:42:17 +00:00
parent 55bb4055e4
commit 689a4c6f45
18 changed files with 246 additions and 142 deletions

View File

@ -894,47 +894,7 @@ final class Doctrine
*/
public static function createDatabases($specifiedConnections = array())
{
if ( ! is_array($specifiedConnections)) {
$specifiedConnections = (array) $specifiedConnections;
}
$manager = Doctrine_Manager::getInstance();
$connections = $manager->getConnections();
$results = array();
foreach ($connections as $name => $connection) {
if ( ! empty($specifiedConnections) && !in_array($name, $specifiedConnections)) {
continue;
}
$info = $manager->parsePdoDsn($connection->getOption('dsn'));
$username = $connection->getOption('username');
$password = $connection->getOption('password');
// Make connection without database specified so we can create it
$connect = $manager->openConnection(new PDO($info['scheme'] . ':host=' . $info['host'], $username, $password), 'tmp_connection', false);
try {
// Create database
$connect->export->createDatabase($name);
// Close the tmp connection with no database
$manager->closeConnection($connect);
// Close original connection
$manager->closeConnection($connection);
// Reopen original connection with newly created database
$manager->openConnection(new PDO($info['dsn'], $username, $password), $name, true);
$results[$name] = true;
} catch (Exception $e) {
$results[$name] = false;
}
}
return $results;
return Doctrine_Manager::getInstance()->createDatabases($specifiedConnections);
}
/**
@ -947,31 +907,7 @@ final class Doctrine
*/
public static function dropDatabases($specifiedConnections = array())
{
if ( ! is_array($specifiedConnections)) {
$specifiedConnections = (array) $specifiedConnections;
}
$manager = Doctrine_Manager::getInstance();
$connections = $manager->getConnections();
$results = array();
foreach ($connections as $name => $connection) {
if ( ! empty($specifiedConnections) && !in_array($name, $specifiedConnections)) {
continue;
}
try {
$connection->export->dropDatabase($connection->getDatabaseName());
$results[$name] = true;
} catch (Exception $e) {
$results[$name] = false;
}
}
return $results;
return Doctrine_Manager::getInstance()->dropDatabases($specifiedConnections);
}
/**

View File

@ -75,6 +75,15 @@ abstract class Doctrine_Connection extends Doctrine_Configurable implements Coun
* @var array An array of mapper objects currently maintained by this connection.
*/
protected $_mappers = array();
/**
* $_name
*
* Name of the connection
*
* @var string $_name
*/
protected $_name;
/**
* @var string $driverName the name of this connection driver
@ -305,6 +314,16 @@ abstract class Doctrine_Connection extends Doctrine_Configurable implements Coun
* @return string the name of this driver
*/
public function getName()
{
return $this->_name;
}
public function setName($name)
{
$this->_name = $name;
}
public function getDriverName()
{
return $this->driverName;
}
@ -340,7 +359,7 @@ abstract class Doctrine_Connection extends Doctrine_Configurable implements Coun
$this->modules[$name] = new Doctrine_Formatter($this);
break;
default:
$class = 'Doctrine_' . ucwords($name) . '_' . $this->getName();
$class = 'Doctrine_' . ucwords($name) . '_' . $this->getDriverName();
$this->modules[$name] = new $class($this);
}
}
@ -1380,6 +1399,59 @@ abstract class Doctrine_Connection extends Doctrine_Configurable implements Coun
$this->transaction->rollback($savepoint);
}
/**
* createDatabase
*
* @return void
*/
public function createDatabase()
{
$manager = $this->getManager();
$info = $manager->parsePdoDsn($this->getOption('dsn'));
$username = $this->getOption('username');
$password = $this->getOption('password');
// Make connection without database specified so we can create it
$connect = $manager->openConnection(new PDO($info['scheme'] . ':host=' . $info['host'], $username, $password), 'tmp_connection', false);
try {
// Create database
$connect->export->createDatabase($info['dbname']);
// Close the tmp connection with no database
$manager->closeConnection($connect);
// Close original connection
$manager->closeConnection($this);
// Reopen original connection with newly created database
$manager->openConnection(new PDO($info['dsn'], $username, $password), $this->getName(), true);
return 'Successfully created database for connection "' . $this->getName() . '" named "' . $info['dbname'] . '"';
} catch (Exception $e) {
return $e;
}
}
/**
* dropDatabase
*
* @return void
*/
public function dropDatabase()
{
try {
$info = $this->getManager()->parsePdoDsn($this->getOption('dsn'));
$this->export->dropDatabase($info['dbname']);
return 'Successfully dropped database for connection "' . $this->getName() . '" named "' . $info['dbname'] . '"';
} catch (Exception $e) {
return $e;
}
}
/**
* returns a string representation of this object
* @return string

View File

@ -96,13 +96,40 @@ class Doctrine_Connection_Sqlite extends Doctrine_Connection_Common
}
/**
* getDatabaseFile
* createDatabase
*
* @param string $name the name of the database
* @return string
* @return void
*/
public function getDatabaseFile($name)
public function createDatabase()
{
return $name . '.db';
try {
$manager = $this->getManager();
$info = $manager->parseDsn($this->getOption('dsn'));
$this->export->createDatabase($info['database']);
return 'Successfully created database for connection "' . $this->getName() . '" at path "' . $info['database'] . '"';
} catch (Exception $e) {
return $e;
}
}
}
/**
* dropDatabase
*
* @return void
*/
public function dropDatabase()
{
try {
$info = $this->getManager()->parseDsn($this->getOption('dsn'));
$this->export->dropDatabase($info['database']);
return 'Successfully dropped database for connection "' . $this->getName() . '" at path "' . $info['database'] . '"';
} catch (Exception $e) {
return $e;
}
}
}

View File

@ -1056,6 +1056,10 @@ class Doctrine_Export extends Doctrine_Connection_Module
/**
* exportClasses
*
* FIXME: This method is a big huge hack. The sql needs to be executed in the correct order. I have some stupid logic to
* make sure they are in the right order.
*
* method for exporting Doctrine_Record classes to a schema
*
* @throws Doctrine_Connection_Exception if some error other than Doctrine::ERR_ALREADY_EXISTS
@ -1073,7 +1077,8 @@ class Doctrine_Export extends Doctrine_Connection_Module
if ( ! isset($connections[$connectionName])) {
$connections[$connectionName] = array();
$connections[$connectionName]['creates'] = array();
$connections[$connectionName]['create_tables'] = array();
$connections[$connectionName]['create_sequences'] = array();
$connections[$connectionName]['alters'] = array();
}
@ -1081,9 +1086,15 @@ class Doctrine_Export extends Doctrine_Connection_Module
// Build array of all the creates
// We need these to happen first
foreach ($sql as $key => $query) {
if (strstr($query, 'CREATE')) {
$connections[$connectionName]['creates'][] = $query;
// Unset the create from sql so we can have an array of everything else but creates
if (strstr($query, 'CREATE TABLE')) {
$connections[$connectionName]['create_tables'][] = $query;
unset($sql[$key]);
}
if (strstr($query, 'CREATE SEQUENCE')) {
$connections[$connectionName]['create_sequences'][] = $query;
unset($sql[$key]);
}
}
@ -1094,7 +1105,7 @@ class Doctrine_Export extends Doctrine_Connection_Module
// Loop over all the sql again to merge the creates and alters in to the same array, but so that the alters are at the bottom
$build = array();
foreach ($connections as $connectionName => $sql) {
$build[$connectionName] = array_merge($sql['creates'], $sql['alters']);
$build[$connectionName] = array_merge($sql['create_tables'], $sql['create_sequences'], $sql['alters']);
}
foreach ($build as $connectionName => $sql) {

View File

@ -34,25 +34,41 @@ Doctrine::autoload('Doctrine_Export');
class Doctrine_Export_Sqlite extends Doctrine_Export
{
/**
* dropDatabase
*
* drop an existing database
*
* @param string $name name of the database that should be dropped
* @param string $databaseFile Path of the database that should be dropped
* @throws Doctrine_Export_Exception if the database file does not exist
* @throws Doctrine_Export_Exception if something failed during the removal of the database file
* @return void
*/
public function dropDatabase($name)
public function dropDatabase($databaseFile)
{
$databaseFile = $this->conn->getDatabaseFile($name);
if ( ! @file_exists($databaseFile)) {
throw new Doctrine_Export_Exception('database does not exist');
}
$result = @unlink($databaseFile);
if ( ! $result) {
throw new Doctrine_Export_Exception('could not remove the database file');
}
}
/**
* createDatabase
*
* Create sqlite database file
*
* @param string $databaseFile Path of the database that should be dropped
* @return void
*/
public function createDatabase($databaseFile)
{
return new PDO('sqlite:' . $databaseFile);
}
/**
* Get the stucture of a field into an array
*

View File

@ -312,6 +312,7 @@ class Doctrine_Manager extends Doctrine_Configurable implements Countable, Itera
$className = $drivers[$driverName];
$conn = new $className($this, $adapter);
$conn->setName($name);
$this->_connections[$name] = $conn;
@ -345,10 +346,16 @@ class Doctrine_Manager extends Doctrine_Configurable implements Countable, Itera
$e = explode(';', $e[1]);
foreach ($e as $string) {
list($key, $value) = explode('=', $string);
$parts[$key] = $value;
if ($string) {
$e2 = explode('=', $string);
if (isset($e2[0]) && isset($e2[1])) {
list($key, $value) = $e2;
$parts[$key] = $value;
}
}
}
return $parts;
}
@ -360,9 +367,10 @@ class Doctrine_Manager extends Doctrine_Configurable implements Countable, Itera
*/
public function parseDsn($dsn)
{
//fix linux sqlite dsn so that it will parse correctly
$dsn = str_replace("///", "/", $dsn);
// fix sqlite dsn so that it will parse correctly
$dsn = str_replace("////", "/", $dsn);
$dsn = str_replace("///c:/", "//c:/", $dsn);
// silence any warnings
$parts = @parse_url($dsn);
@ -451,7 +459,6 @@ class Doctrine_Manager extends Doctrine_Configurable implements Countable, Itera
throw new Doctrine_Manager_Exception('Unknown driver '.$parts['scheme']);
}
return $parts;
}
@ -695,6 +702,60 @@ class Doctrine_Manager extends Doctrine_Configurable implements Countable, Itera
return $this->_connections[$i];
}
/**
* createDatabases
*
* Creates databases for connections
*
* @param string $specifiedConnections Array of connections you wish to create the database for
* @return void
*/
public function createDatabases($specifiedConnections = array())
{
if ( ! is_array($specifiedConnections)) {
$specifiedConnections = (array) $specifiedConnections;
}
$results = array();
foreach ($this as $name => $connection) {
if ( ! empty($specifiedConnections) && !in_array($name, $specifiedConnections)) {
continue;
}
$results[$name] = $connection->createDatabase();
}
return $results;
}
/**
* dropDatabases
*
* Drops databases for connections
*
* @param string $specifiedConnections Array of connections you wish to drop the database for
* @return void
*/
public function dropDatabases($specifiedConnections = array())
{
if ( ! is_array($specifiedConnections)) {
$specifiedConnections = (array) $specifiedConnections;
}
$results = array();
foreach ($this as $name => $connection) {
if ( ! empty($specifiedConnections) && !in_array($name, $specifiedConnections)) {
continue;
}
$results[$name] = $connection->dropDatabase();
}
return $results;
}
/**
* __toString
* returns a string representation of this object
@ -709,4 +770,4 @@ class Doctrine_Manager extends Doctrine_Configurable implements Countable, Itera
$r[] = "</pre>";
return implode("\n",$r);
}
}
}

View File

@ -377,7 +377,10 @@ class Doctrine_Query_Tokenizer
}
}
}
$term[$i - 1] = array($term[$i - 1], '');
if (isset($term[$i - 1])) {
$term[$i - 1] = array($term[$i - 1], '');
}
return $term;
}

View File

@ -39,8 +39,8 @@ class Doctrine_Task_CreateDb extends Doctrine_Task
{
$results = Doctrine::createDatabases();
foreach ($results as $dbName => $bool) {
$msg = $bool ? 'Successfully created database named: "' . $dbName . '"':'Could not create database named: "' .$dbName . '"';
foreach ($results as $name => $result) {
$msg = $result instanceof Exception ? 'Could not create database for connection: "' .$name . '." Failed with exception: ' . $result->getMessage():$result;
$this->notify($msg);
}

View File

@ -48,8 +48,8 @@ class Doctrine_Task_DropDb extends Doctrine_Task
$results = Doctrine::dropDatabases();
foreach ($results as $dbName => $bool) {
$msg = $bool ? 'Successfully dropped database named: "' . $dbName . '"':'Could not drop database named: "' .$dbName . '"';
foreach ($results as $name => $result) {
$msg = $result instanceof Exception ? 'Could not drop database for connection: "' .$name . '." Failed with exception: ' . $result->getMessage():$result;
$this->notify($msg);
}

View File

@ -6,9 +6,10 @@ class TreeLeaf extends Doctrine_Record
$this->hasColumn('name', 'string');
$this->hasColumn('parent_id', 'integer');
}
public function setUp()
{
$this->hasOne('TreeLeaf as Parent', 'TreeLeaf.parent_id');
$this->hasMany('TreeLeaf as Children', 'TreeLeaf.parent_id');
$this->hasOne('TreeLeaf as Parent', array('local' => 'parent_id', 'foreign' => 'id'));
$this->hasMany('TreeLeaf as Children', array('local' => 'id', 'foreign' => 'parent_id'));
}
}
}

View File

@ -32,23 +32,17 @@
*/
class Doctrine_Export_Sqlite_TestCase extends Doctrine_UnitTestCase
{
public function testCreateDatabaseDoesNotExecuteSql()
public function testCreateDatabaseDoesNotExecuteSqlAndCreatesSqliteFile()
{
try {
$this->export->createDatabase('db');
$this->fail();
} catch(Doctrine_Export_Exception $e) {
$this->pass();
}
$this->export->createDatabase('sqlite.db');
$this->assertTrue(file_exists('sqlite.db'));
}
public function testDropDatabaseDoesNotExecuteSql()
public function testDropDatabaseDoesNotExecuteSqlAndDeletesSqliteFile()
{
try {
$this->export->dropDatabase('db');
$this->fail();
} catch(Doctrine_Export_Exception $e) {
$this->pass();
}
$this->export->dropDatabase('sqlite.db');
$this->assertFalse(file_exists('sqlite.db'));
}
public function testCreateTableSupportsAutoincPks()
{
@ -171,24 +165,9 @@ class Doctrine_Export_Sqlite_TestCase extends Doctrine_UnitTestCase
$this->export->createTable('sometable', $fields, $options);
//removed this assertion and inserted the two below
// $this->assertEqual($this->adapter->pop(), 'CREATE TABLE sometable (id INTEGER PRIMARY KEY AUTOINCREMENT, name VARCHAR(4), INDEX myindex (id ASC, name DESC))');
$this->assertEqual($this->adapter->pop(),"CREATE INDEX myindex_idx ON sometable (id ASC, name DESC)");
$this->assertEqual($this->adapter->pop(), 'CREATE TABLE sometable (id INTEGER PRIMARY KEY AUTOINCREMENT, name VARCHAR(4) DEFAULT NULL)');
}
/**
public function testExportSupportsEmulationOfCascadingDeletes()
{
$r = new ForeignKeyTest;
$this->assertEqual($this->adapter->pop(), 'COMMIT');
$this->assertEqual($this->adapter->pop(), 'CREATE TRIGGER doctrine_foreign_key_test_cscd_delete AFTER DELETE ON foreign_key_test BEGIN DELETE FROM foreign_key_test WHERE parent_id = old.id;END;');
$this->assertEqual($this->adapter->pop(), 'CREATE TABLE foreign_key_test (id INTEGER PRIMARY KEY AUTOINCREMENT, name VARCHAR(2147483647), code INTEGER, content VARCHAR(4000), parent_id INTEGER)');
$this->assertEqual($this->adapter->pop(), 'BEGIN TRANSACTION');
}
*/
}
}

View File

@ -65,8 +65,8 @@ class Doctrine_Manager_TestCase extends Doctrine_UnitTestCase {
// sqlite://full/unix/path/to/file.db
// It expects only // since it thinks it is parsing a url
// The problem after that is that the dns is not valid when being passed to PDO
$sqlite = 'sqlite:///full/unix/path/to/file.db';
$sqlitewin = 'sqlite://c:/full/windows/path/to/file.db';
$sqlite = 'sqlite:////full/unix/path/to/file.db';
$sqlitewin = 'sqlite:///c:/full/windows/path/to/file.db';
$manager = Doctrine_Manager::getInstance();

View File

@ -45,8 +45,8 @@ class Doctrine_Ticket_480_TestCase extends Doctrine_UnitTestCase
{
public function testInit()
{
$this->dbh = new Doctrine_Adapter_Mock('oracle');
$this->conn = Doctrine_Manager::getInstance()->openConnection($this->dbh);
$this->dbh = new Doctrine_Adapter_Mock('oracle');
$this->conn = Doctrine_Manager::getInstance()->openConnection($this->dbh);
}
public function testTicket()

View File

@ -103,16 +103,15 @@ class Doctrine_TreeStructure_TestCase extends Doctrine_UnitTestCase
$o4->name = 'o4';
$o4->save();
$o1->Children;
$this->assertFalse(isset($o1->Parent));
$this->assertTrue(isset($o2->Parent));
$this->assertTrue($o2->Parent === $o1);
$this->assertFalse(isset($o4->Parent));
$this->assertTrue(count($o1->Children) == 2);
$this->assertTrue(count($o1->get('Children')) == 2);
$this->assertTrue(isset($o2->Parent));
$this->assertTrue($o2->Parent === $o1);
$this->assertTrue(count($o4->Children) == 0);
$this->assertFalse(isset($o4->Parent));
}
public function testTreeStructureFetchingWorksWithDql()
{

View File

@ -153,8 +153,8 @@ $data_types->addTestCase(new Doctrine_DataType_Boolean_TestCase());
$test->addTestCase($data_types);
// Utility components
$plugins = new GroupTest('Plugin tests: View, Validator, Hook','plugins');
//$utility->addTestCase(new Doctrine_PessimisticLocking_TestCase());
$plugins = new GroupTest('Plugin tests: View, Validator, Hook', 'plugins');
//$plugins->addTestCase(new Doctrine_PessimisticLocking_TestCase());
//$plugins->addTestCase(new Doctrine_Plugin_TestCase());
$plugins->addTestCase(new Doctrine_View_TestCase());
$plugins->addTestCase(new Doctrine_AuditLog_TestCase());

View File

@ -42,13 +42,12 @@ define('MIGRATIONS_PATH', SANDBOX_PATH . DIRECTORY_SEPARATOR . 'migrations');
define('SQL_PATH', SANDBOX_PATH . DIRECTORY_SEPARATOR . 'data' . DIRECTORY_SEPARATOR . 'sql');
define('YAML_SCHEMA_PATH', SANDBOX_PATH . DIRECTORY_SEPARATOR . 'schema');
define('DB_PATH', SANDBOX_PATH . DIRECTORY_SEPARATOR . 'sandbox.db');
define('DSN', 'sqlite:' . DB_PATH);
define('DSN', 'sqlite:///' . DB_PATH);
require_once(DOCTRINE_PATH . DIRECTORY_SEPARATOR . 'Doctrine.php');
spl_autoload_register(array('Doctrine', 'autoload'));
$pdo = new PDO(DSN);
Doctrine_Manager::connection($pdo, 'sandbox');
Doctrine_Manager::connection(DSN, 'sandbox');
Doctrine_Manager::getInstance()->setAttribute(Doctrine::ATTR_MODEL_LOADING, Doctrine::MODEL_LOADING_CONSERVATIVE);

View File

@ -10,4 +10,4 @@ $config = array('data_fixtures_path' => DATA_FIXTURES_PATH,
'yaml_schema_path' => YAML_SCHEMA_PATH);
$cli = new Doctrine_Cli($config);
$cli->run($_SERVER['argv']);
$cli->run($_SERVER['argv']);

Binary file not shown.