diff --git a/Doctrine/DB/Exception.php b/Doctrine/DB/Exception.php new file mode 100644 index 000000000..e4d4d7eba --- /dev/null +++ b/Doctrine/DB/Exception.php @@ -0,0 +1,2 @@ + - * phptype(dbsyntax)://username:password@protocol+hostspec/database?option=8&another=true - * - * - * Most variations are allowed: - * - * phptype://username:password@protocol+hostspec:110//usr/db_file.db?mode=0644 - * phptype://username:password@hostspec/database_name - * phptype://username:password@hostspec - * phptype://username@hostspec - * phptype://hostspec/database - * phptype://hostspec - * phptype(dbsyntax) - * phptype - * - * - * @param string Data Source Name to be parsed - * - * @return array an associative array with the following keys: - * + phptype: Database backend used in PHP (mysql, odbc etc.) - * + dbsyntax: Database used with regards to SQL syntax etc. - * + protocol: Communication protocol to use (tcp, unix etc.) - * + hostspec: Host specification (hostname[:port]) - * + database: Database to use on the DBMS server - * + username: User name for login - * + password: Password for login - * - * @access public - * @author Tomas V.V.Cox - */ - public static function parseDSN($dsn) { - // Find phptype and dbsyntax - if (($pos = strpos($dsn, '://')) !== false) { - $str = substr($dsn, 0, $pos); - $dsn = substr($dsn, $pos + 3); - } else { - $str = $dsn; - $dsn = null; - } - - // Get phptype and dbsyntax - // $str => phptype(dbsyntax) - if (preg_match('|^(.+?)\((.*?)\)$|', $str, $arr)) { - $parsed['phptype'] = $arr[1]; - $parsed['dbsyntax'] = !$arr[2] ? $arr[1] : $arr[2]; - } else { - $parsed['phptype'] = $str; - $parsed['dbsyntax'] = $str; - } - - if (!count($dsn)) { - return $parsed; - } - - // Get (if found): username and password - // $dsn => username:password@protocol+hostspec/database - if (($at = strrpos($dsn,'@')) !== false) { - $str = substr($dsn, 0, $at); - $dsn = substr($dsn, $at + 1); - if (($pos = strpos($str, ':')) !== false) { - $parsed['username'] = rawurldecode(substr($str, 0, $pos)); - $parsed['password'] = rawurldecode(substr($str, $pos + 1)); - } else { - $parsed['username'] = rawurldecode($str); - } - } - - // Find protocol and hostspec - - // $dsn => proto(proto_opts)/database - if (preg_match('|^([^(]+)\((.*?)\)/?(.*?)$|', $dsn, $match)) { - $proto = $match[1]; - $proto_opts = $match[2] ? $match[2] : false; - $dsn = $match[3]; - - // $dsn => protocol+hostspec/database (old format) - } else { - if (strpos($dsn, '+') !== false) { - list($proto, $dsn) = explode('+', $dsn, 2); - } - if (strpos($dsn, '/') !== false) { - list($proto_opts, $dsn) = explode('/', $dsn, 2); - } else { - $proto_opts = $dsn; - $dsn = null; - } - } - - // process the different protocol options - $parsed['protocol'] = (!empty($proto)) ? $proto : 'tcp'; - $proto_opts = rawurldecode($proto_opts); - if (strpos($proto_opts, ':') !== false) { - list($proto_opts, $parsed['port']) = explode(':', $proto_opts); - } - if ($parsed['protocol'] == 'tcp') { - $parsed['hostspec'] = $proto_opts; - } elseif ($parsed['protocol'] == 'unix') { - $parsed['socket'] = $proto_opts; - } - - // Get dabase if any - // $dsn => database - if ($dsn) { - // /database - if (($pos = strpos($dsn, '?')) === false) { - $parsed['database'] = $dsn; - // /database?param1=value1¶m2=value2 - } else { - $parsed['database'] = substr($dsn, 0, $pos); - $dsn = substr($dsn, $pos + 1); - if (strpos($dsn, '&') !== false) { - $opts = explode('&', $dsn); - } else { // database?param1=value1 - $opts = array($dsn); - } - foreach ($opts as $opt) { - list($key, $value) = explode('=', $opt); - if (!isset($parsed[$key])) { - // don't allow params overwrite - $parsed[$key] = rawurldecode($value); - } - } - } - } - - return $parsed; - } - - /** - * Here is my version of parseDSN. It is a bit leaner than the one above, but you can choose either one. - * This one relies on the built in functionality more than replicating it in userland code so it should - * be more efficient. Not completely compatible with the parser above, but it is easy to add in - * the phptype/dbsyntax and protocol/hostspec parts if need be. - * - * @author Elliot Anderson - * * @param string $dsn * @return array Parsed contents of DSN */ - function parseDSNnew ( $dsn ) - { - $parts = parse_url ( $dsn ); - $parsed = array ( ); - - if ( count ( $parts ) == 0 ) return false; - - if ( isset ( $parts ['scheme'] ) ) - $parsed ['phptype'] = - $parsed ['dbsyntax'] = $parts ['scheme']; - - if ( isset ( $parts ['host'] ) ) - { - if ( strpos ( $parts ['host'], '+' ) ) - { - $tmp = explode ( '+', $parts ['host'] ); - - $parsed ['protocol'] = $tmp [ 0 ]; - $parsed ['hostspec'] = $tmp [ 1 ]; - } - else - { - $parsed ['hostspec'] = $parts ['host']; - } - } - - if ( isset ( $parts ['path'] ) ) $parsed ['database'] = substr ( $parts ['path'], 1 ); - - if ( isset ( $parts ['user'] ) ) $parsed ['username'] = $parts ['user']; - if ( isset ( $parts ['pass'] ) ) $parsed ['password'] = $parts ['pass']; - - if ( isset ( $parts ['query'] ) ) parse_str ( $parts ['query'], $parsed ['options'] ); - - return $parsed; + function parseDSN($dsn) { + $parts = @parse_url($dsn); + + $names = array('scheme', 'host', 'port', 'user', 'pass', 'path', 'query', 'fragment'); + + foreach($names as $name) { + if( ! isset($parts[$name])) + $parts[$name] = null; + } + + if(count($parts) == 0 || ! isset($parts['scheme'])) + throw new Doctrine_DB_Exception('Empty data source name'); + + $drivers = self::getAvailableDrivers(); + + if( ! in_array($parts['scheme'], $drivers)) + throw new Doctrine_DB_Exception('Driver '.$parts['scheme'].' not availible or extension not loaded'); + + switch($parts['scheme']) { + case 'sqlite': + if(isset($parts['host']) && $parts['host'] == ':memory') { + $parts['database'] = ':memory:'; + $parts['dsn'] = 'sqlite::memory:'; + } + + break; + case 'mysql': + case 'informix': + case 'oci8': + case 'mssql': + case 'firebird': + case 'pgsql': + case 'odbc': + if( ! isset($parts['path']) || $parts['path'] == '/') + throw new Doctrine_DB_Exception('No database availible in data source name'); + + if(isset($parts['path'])) + $parts['database'] = substr($parts['path'], 1); + + if( ! isset($parts['host'])) + throw new Doctrine_DB_Exception('No hostname set in data source name'); + + $parts['dsn'] = $parts["scheme"].":host=".$parts["host"].";dbname=".$parts["database"]; + break; + default: + throw new Doctrine_DB_Exception('Unknown driver '.$parts['scheme']); + } + + return $parts; } } diff --git a/tests/DBTestCase.php b/tests/DBTestCase.php new file mode 100644 index 000000000..81be660a1 --- /dev/null +++ b/tests/DBTestCase.php @@ -0,0 +1,70 @@ +fail(); + } catch(Doctrine_DB_Exception $e) { + $this->pass(); + } + try { + $conn = Doctrine_DB2::getConnection('unknown'); + $this->fail(); + } catch(Doctrine_DB_Exception $e) { + $this->pass(); + } + try { + $conn = Doctrine_DB2::getConnection(0); + $this->fail(); + } catch(Doctrine_DB_Exception $e) { + $this->pass(); + } + } + public function testInvalidScheme() { + try { + $conn = Doctrine_DB2::getConnection('unknown://:memory:'); + $this->fail(); + } catch(Doctrine_DB_Exception $e) { + $this->pass(); + } + } + public function testInvalidHost() { + try { + $conn = Doctrine_DB2::getConnection('mysql://user:password@'); + $this->fail(); + } catch(Doctrine_DB_Exception $e) { + $this->pass(); + } + } + public function testInvalidDatabase() { + try { + $conn = Doctrine_DB2::getConnection('mysql://user:password@host/'); + $this->fail(); + } catch(Doctrine_DB_Exception $e) { + $this->pass(); + } + } + + public function testGetConnection() { + $conn = Doctrine_DB2::getConnection('mysql://zYne:password@localhost/test'); + $this->assertEqual($conn->getDSN(), 'mysql:host=localhost;dbname=test'); + $this->assertEqual($conn->getUsername(), 'zYne'); + $this->assertEqual($conn->getPassword(), 'password'); + + + + $conn = Doctrine_DB2::getConnection('sqlite://:memory:'); + + $this->assertEqual($conn->getDSN(), 'sqlite::memory:'); + $this->assertEqual($conn->getUsername(), null); + $this->assertEqual($conn->getPassword(), null); + } + +} +?>