Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
D
doctrine-dbal
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Tomáš Trávníček
doctrine-dbal
Commits
4a85a587
Commit
4a85a587
authored
Sep 09, 2016
by
Marco Pivetta
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'fix/#2287-#1183-parse-schemaless-connection-uris'
Close #2287 Close #1183
parents
27e2687b
d9db0bbc
Changes
5
Show whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
220 additions
and
26 deletions
+220
-26
DBALException.php
lib/Doctrine/DBAL/DBALException.php
+13
-1
DriverManager.php
lib/Doctrine/DBAL/DriverManager.php
+128
-24
DBALExceptionTest.php
tests/Doctrine/Tests/DBAL/DBALExceptionTest.php
+16
-0
DriverManagerTest.php
tests/Doctrine/Tests/DBAL/DriverManagerTest.php
+53
-1
PDOMock.php
tests/Doctrine/Tests/Mocks/PDOMock.php
+10
-0
No files found.
lib/Doctrine/DBAL/DBALException.php
View file @
4a85a587
...
@@ -77,10 +77,22 @@ class DBALException extends \Exception
...
@@ -77,10 +77,22 @@ class DBALException extends \Exception
}
}
/**
/**
* @param string|null $url The URL that was provided in the connection parameters (if any).
*
* @return \Doctrine\DBAL\DBALException
* @return \Doctrine\DBAL\DBALException
*/
*/
public
static
function
driverRequired
()
public
static
function
driverRequired
(
$url
=
null
)
{
{
if
(
$url
)
{
return
new
self
(
sprintf
(
"The options 'driver' or 'driverClass' are mandatory if a connection URL without scheme "
.
"is given to DriverManager::getConnection(). Given URL: %s"
,
$url
)
);
}
return
new
self
(
"The options 'driver' or 'driverClass' are mandatory if no PDO "
.
return
new
self
(
"The options 'driver' or 'driverClass' are mandatory if no PDO "
.
"instance is given to DriverManager::getConnection()."
);
"instance is given to DriverManager::getConnection()."
);
}
}
...
...
lib/Doctrine/DBAL/DriverManager.php
View file @
4a85a587
...
@@ -212,6 +212,19 @@ final class DriverManager
...
@@ -212,6 +212,19 @@ final class DriverManager
}
}
}
}
/**
* Normalizes the given connection URL path.
*
* @param string $urlPath
*
* @return string The normalized connection URL path
*/
private
static
function
normalizeDatabaseUrlPath
(
$urlPath
)
{
// Trim leading slash from URL path.
return
substr
(
$urlPath
,
1
);
}
/**
/**
* Extracts parts from a database URL, if present, and returns an
* Extracts parts from a database URL, if present, and returns an
* updated list of parameters.
* updated list of parameters.
...
@@ -232,18 +245,25 @@ final class DriverManager
...
@@ -232,18 +245,25 @@ final class DriverManager
// (pdo_)?sqlite3?:///... => (pdo_)?sqlite3?://localhost/... or else the URL will be invalid
// (pdo_)?sqlite3?:///... => (pdo_)?sqlite3?://localhost/... or else the URL will be invalid
$url
=
preg_replace
(
'#^((?:pdo_)?sqlite3?):///#'
,
'$1://localhost/'
,
$params
[
'url'
]);
$url
=
preg_replace
(
'#^((?:pdo_)?sqlite3?):///#'
,
'$1://localhost/'
,
$params
[
'url'
]);
// PHP < 5.4.8 doesn't parse schemeless urls properly.
// See: https://php.net/parse-url#refsect1-function.parse-url-changelog
if
(
PHP_VERSION_ID
<
50408
&&
strpos
(
$url
,
'//'
)
===
0
)
{
$url
=
parse_url
(
'fake:'
.
$url
);
unset
(
$url
[
'scheme'
]);
}
else
{
$url
=
parse_url
(
$url
);
$url
=
parse_url
(
$url
);
}
if
(
$url
===
false
)
{
if
(
$url
===
false
)
{
throw
new
DBALException
(
'Malformed parameter "url".'
);
throw
new
DBALException
(
'Malformed parameter "url".'
);
}
}
if
(
isset
(
$url
[
'scheme'
]))
{
// If we have a connection URL, we have to unset the default PDO instance connection parameter (if any)
$params
[
'driver'
]
=
str_replace
(
'-'
,
'_'
,
$url
[
'scheme'
]);
// URL schemes must not contain underscores, but dashes are ok
// as we cannot merge connection details from the URL into the PDO instance (URL takes precedence).
if
(
isset
(
self
::
$driverSchemeAliases
[
$params
[
'driver'
]]))
{
unset
(
$params
[
'pdo'
]);
$params
[
'driver'
]
=
self
::
$driverSchemeAliases
[
$params
[
'driver'
]];
// use alias like "postgres", else we just let checkParams decide later if the driver exists (for literal "pdo-pgsql" etc)
}
$params
=
self
::
parseDatabaseUrlScheme
(
$url
,
$params
);
}
if
(
isset
(
$url
[
'host'
]))
{
if
(
isset
(
$url
[
'host'
]))
{
$params
[
'host'
]
=
$url
[
'host'
];
$params
[
'host'
]
=
$url
[
'host'
];
...
@@ -258,53 +278,97 @@ final class DriverManager
...
@@ -258,53 +278,97 @@ final class DriverManager
$params
[
'password'
]
=
$url
[
'pass'
];
$params
[
'password'
]
=
$url
[
'pass'
];
}
}
if
(
isset
(
$url
[
'path'
]))
{
$params
=
self
::
parseDatabaseUrlPath
(
$url
,
$params
);
$params
=
self
::
parseDatabaseUrlPath
(
$url
,
$params
);
}
$params
=
self
::
parseDatabaseUrlQuery
(
$url
,
$params
);
if
(
isset
(
$url
[
'query'
]))
{
$query
=
array
();
parse_str
(
$url
[
'query'
],
$query
);
// simply ingest query as extra params, e.g. charset or sslmode
$params
=
array_merge
(
$params
,
$query
);
// parse_str wipes existing array elements
}
return
$params
;
return
$params
;
}
}
/**
/**
* Parses the given URL and resolves the given connection parameters.
* Parses the given connection URL and resolves the given connection parameters.
*
* Assumes that the connection URL scheme is already parsed and resolved into the given connection parameters
* via {@link parseDatabaseUrlScheme}.
*
*
* @param array $url The URL parts to evaluate.
* @param array $url The URL parts to evaluate.
* @param array $params The connection parameters to resolve.
* @param array $params The connection parameters to resolve.
*
*
* @return array The resolved connection parameters.
* @return array The resolved connection parameters.
*
* @see parseDatabaseUrlScheme
*/
*/
private
static
function
parseDatabaseUrlPath
(
array
$url
,
array
$params
)
private
static
function
parseDatabaseUrlPath
(
array
$url
,
array
$params
)
{
{
if
(
!
isset
(
$url
[
'scheme'
]))
{
if
(
!
isset
(
$url
[
'path'
]))
{
$params
[
'dbname'
]
=
$url
[
'path'
];
return
$params
;
return
$params
;
}
}
$url
[
'path'
]
=
s
ubstr
(
$url
[
'path'
],
1
);
$url
[
'path'
]
=
s
elf
::
normalizeDatabaseUrlPath
(
$url
[
'path'
]
);
if
(
strpos
(
$url
[
'scheme'
],
'sqlite'
)
!==
false
)
{
// If we do not have a known DBAL driver, we do not know any connection URL path semantics to evaluate
// and therefore treat the path as regular DBAL connection URL path.
if
(
!
isset
(
$params
[
'driver'
]))
{
return
self
::
parseRegularDatabaseUrlPath
(
$url
,
$params
);
}
if
(
strpos
(
$params
[
'driver'
],
'sqlite'
)
!==
false
)
{
return
self
::
parseSqliteDatabaseUrlPath
(
$url
,
$params
);
return
self
::
parseSqliteDatabaseUrlPath
(
$url
,
$params
);
}
}
return
self
::
parseRegularDatabaseUrlPath
(
$url
,
$params
);
}
/**
* Parses the query part of the given connection URL and resolves the given connection parameters.
*
* @param array $url The connection URL parts to evaluate.
* @param array $params The connection parameters to resolve.
*
* @return array The resolved connection parameters.
*/
private
static
function
parseDatabaseUrlQuery
(
array
$url
,
array
$params
)
{
if
(
!
isset
(
$url
[
'query'
]))
{
return
$params
;
}
$query
=
array
();
parse_str
(
$url
[
'query'
],
$query
);
// simply ingest query as extra params, e.g. charset or sslmode
return
array_merge
(
$params
,
$query
);
// parse_str wipes existing array elements
}
/**
* Parses the given regular connection URL and resolves the given connection parameters.
*
* Assumes that the "path" URL part is already normalized via {@link normalizeDatabaseUrlPath}.
*
* @param array $url The regular connection URL parts to evaluate.
* @param array $params The connection parameters to resolve.
*
* @return array The resolved connection parameters.
*
* @see normalizeDatabaseUrlPath
*/
private
static
function
parseRegularDatabaseUrlPath
(
array
$url
,
array
$params
)
{
$params
[
'dbname'
]
=
$url
[
'path'
];
$params
[
'dbname'
]
=
$url
[
'path'
];
return
$params
;
return
$params
;
}
}
/**
/**
* Parses the given SQLite URL and resolves the given connection parameters.
* Parses the given SQLite
connection
URL and resolves the given connection parameters.
*
*
* @param array $url The SQLite URL parts to evaluate.
* Assumes that the "path" URL part is already normalized via {@link normalizeDatabaseUrlPath}.
*
* @param array $url The SQLite connection URL parts to evaluate.
* @param array $params The connection parameters to resolve.
* @param array $params The connection parameters to resolve.
*
*
* @return array The resolved connection parameters.
* @return array The resolved connection parameters.
*
* @see normalizeDatabaseUrlPath
*/
*/
private
static
function
parseSqliteDatabaseUrlPath
(
array
$url
,
array
$params
)
private
static
function
parseSqliteDatabaseUrlPath
(
array
$url
,
array
$params
)
{
{
...
@@ -318,4 +382,44 @@ final class DriverManager
...
@@ -318,4 +382,44 @@ final class DriverManager
return
$params
;
return
$params
;
}
}
/**
* Parses the scheme part from given connection URL and resolves the given connection parameters.
*
* @param array $url The connection URL parts to evaluate.
* @param array $params The connection parameters to resolve.
*
* @return array The resolved connection parameters.
*
* @throws DBALException if parsing failed or resolution is not possible.
*/
private
static
function
parseDatabaseUrlScheme
(
array
$url
,
array
$params
)
{
if
(
isset
(
$url
[
'scheme'
]))
{
// The requested driver from the URL scheme takes precedence
// over the default custom driver from the connection parameters (if any).
unset
(
$params
[
'driverClass'
]);
// URL schemes must not contain underscores, but dashes are ok
$driver
=
str_replace
(
'-'
,
'_'
,
$url
[
'scheme'
]);
// The requested driver from the URL scheme takes precedence
// over the default driver from the connection parameters (if any).
$params
[
'driver'
]
=
isset
(
self
::
$driverSchemeAliases
[
$driver
])
// use alias like "postgres", else we just let checkParams decide later
// if the driver exists (for literal "pdo-pgsql" etc)
?
self
::
$driverSchemeAliases
[
$driver
]
:
$driver
;
return
$params
;
}
// If a schemeless connection URL is given, we require a default driver or default custom driver
// as connection parameter.
if
(
!
isset
(
$params
[
'driverClass'
])
&&
!
isset
(
$params
[
'driver'
]))
{
throw
DBALException
::
driverRequired
(
$params
[
'url'
]);
}
return
$params
;
}
}
}
tests/Doctrine/Tests/DBAL/DBALExceptionTest.php
View file @
4a85a587
...
@@ -21,4 +21,20 @@ class DBALExceptionTest extends \Doctrine\Tests\DbalTestCase
...
@@ -21,4 +21,20 @@ class DBALExceptionTest extends \Doctrine\Tests\DbalTestCase
$e
=
DBALException
::
driverExceptionDuringQuery
(
$driver
,
$ex
,
''
);
$e
=
DBALException
::
driverExceptionDuringQuery
(
$driver
,
$ex
,
''
);
$this
->
assertSame
(
$ex
,
$e
);
$this
->
assertSame
(
$ex
,
$e
);
}
}
public
function
testDriverRequiredWithUrl
()
{
$url
=
'mysql://localhost'
;
$exception
=
DBALException
::
driverRequired
(
$url
);
$this
->
assertInstanceOf
(
'Doctrine\DBAL\DBALException'
,
$exception
);
$this
->
assertSame
(
sprintf
(
"The options 'driver' or 'driverClass' are mandatory if a connection URL without scheme "
.
"is given to DriverManager::getConnection(). Given URL: %s"
,
$url
),
$exception
->
getMessage
()
);
}
}
}
tests/Doctrine/Tests/DBAL/DriverManagerTest.php
View file @
4a85a587
...
@@ -130,7 +130,7 @@ class DriverManagerTest extends \Doctrine\Tests\DbalTestCase
...
@@ -130,7 +130,7 @@ class DriverManagerTest extends \Doctrine\Tests\DbalTestCase
$params
=
$conn
->
getParams
();
$params
=
$conn
->
getParams
();
foreach
(
$expected
as
$key
=>
$value
)
{
foreach
(
$expected
as
$key
=>
$value
)
{
if
(
$key
==
'driver'
)
{
if
(
in_array
(
$key
,
array
(
'pdo'
,
'driver'
,
'driverClass'
),
true
)
)
{
$this
->
assertInstanceOf
(
$value
,
$conn
->
getDriver
());
$this
->
assertInstanceOf
(
$value
,
$conn
->
getDriver
());
}
else
{
}
else
{
$this
->
assertEquals
(
$value
,
$params
[
$key
]);
$this
->
assertEquals
(
$value
,
$params
[
$key
]);
...
@@ -140,6 +140,8 @@ class DriverManagerTest extends \Doctrine\Tests\DbalTestCase
...
@@ -140,6 +140,8 @@ class DriverManagerTest extends \Doctrine\Tests\DbalTestCase
public
function
databaseUrls
()
public
function
databaseUrls
()
{
{
$pdoMock
=
$this
->
getMock
(
'Doctrine\Tests\Mocks\PDOMock'
);
return
array
(
return
array
(
'simple URL'
=>
array
(
'simple URL'
=>
array
(
'mysql://foo:bar@localhost/baz'
,
'mysql://foo:bar@localhost/baz'
,
...
@@ -197,6 +199,56 @@ class DriverManagerTest extends \Doctrine\Tests\DbalTestCase
...
@@ -197,6 +199,56 @@ class DriverManagerTest extends \Doctrine\Tests\DbalTestCase
'drizzle-pdo-mysql://foo:bar@localhost/baz'
,
'drizzle-pdo-mysql://foo:bar@localhost/baz'
,
array
(
'user'
=>
'foo'
,
'password'
=>
'bar'
,
'host'
=>
'localhost'
,
'dbname'
=>
'baz'
,
'driver'
=>
'Doctrine\DBAL\Driver\DrizzlePDOMySql\Driver'
),
array
(
'user'
=>
'foo'
,
'password'
=>
'bar'
,
'host'
=>
'localhost'
,
'dbname'
=>
'baz'
,
'driver'
=>
'Doctrine\DBAL\Driver\DrizzlePDOMySql\Driver'
),
),
),
// DBAL-1234
'URL without scheme and without any driver information'
=>
array
(
array
(
'url'
=>
'//foo:bar@localhost/baz'
),
false
,
),
'URL without scheme but default PDO driver'
=>
array
(
array
(
'url'
=>
'//foo:bar@localhost/baz'
,
'pdo'
=>
$pdoMock
),
false
,
),
'URL without scheme but default driver'
=>
array
(
array
(
'url'
=>
'//foo:bar@localhost/baz'
,
'driver'
=>
'pdo_mysql'
),
array
(
'user'
=>
'foo'
,
'password'
=>
'bar'
,
'host'
=>
'localhost'
,
'dbname'
=>
'baz'
,
'driver'
=>
'Doctrine\DBAL\Driver\PDOMySQL\Driver'
),
),
'URL without scheme but custom driver'
=>
array
(
array
(
'url'
=>
'//foo:bar@localhost/baz'
,
'driverClass'
=>
'Doctrine\Tests\Mocks\DriverMock'
),
array
(
'user'
=>
'foo'
,
'password'
=>
'bar'
,
'host'
=>
'localhost'
,
'dbname'
=>
'baz'
,
'driverClass'
=>
'Doctrine\Tests\Mocks\DriverMock'
),
),
'URL without scheme but default PDO driver and default driver'
=>
array
(
array
(
'url'
=>
'//foo:bar@localhost/baz'
,
'pdo'
=>
$pdoMock
,
'driver'
=>
'pdo_mysql'
),
array
(
'user'
=>
'foo'
,
'password'
=>
'bar'
,
'host'
=>
'localhost'
,
'dbname'
=>
'baz'
,
'driver'
=>
'Doctrine\DBAL\Driver\PDOMySQL\Driver'
),
),
'URL without scheme but driver and custom driver'
=>
array
(
array
(
'url'
=>
'//foo:bar@localhost/baz'
,
'driver'
=>
'pdo_mysql'
,
'driverClass'
=>
'Doctrine\Tests\Mocks\DriverMock'
),
array
(
'user'
=>
'foo'
,
'password'
=>
'bar'
,
'host'
=>
'localhost'
,
'dbname'
=>
'baz'
,
'driverClass'
=>
'Doctrine\Tests\Mocks\DriverMock'
),
),
'URL with default PDO driver'
=>
array
(
array
(
'url'
=>
'mysql://foo:bar@localhost/baz'
,
'pdo'
=>
$pdoMock
),
array
(
'user'
=>
'foo'
,
'password'
=>
'bar'
,
'host'
=>
'localhost'
,
'dbname'
=>
'baz'
,
'driver'
=>
'Doctrine\DBAL\Driver\PDOMySQL\Driver'
),
),
'URL with default driver'
=>
array
(
array
(
'url'
=>
'mysql://foo:bar@localhost/baz'
,
'driver'
=>
'sqlite'
),
array
(
'user'
=>
'foo'
,
'password'
=>
'bar'
,
'host'
=>
'localhost'
,
'dbname'
=>
'baz'
,
'driver'
=>
'Doctrine\DBAL\Driver\PDOMySQL\Driver'
),
),
'URL with default custom driver'
=>
array
(
array
(
'url'
=>
'mysql://foo:bar@localhost/baz'
,
'driverClass'
=>
'Doctrine\Tests\Mocks\DriverMock'
),
array
(
'user'
=>
'foo'
,
'password'
=>
'bar'
,
'host'
=>
'localhost'
,
'dbname'
=>
'baz'
,
'driver'
=>
'Doctrine\DBAL\Driver\PDOMySQL\Driver'
),
),
'URL with default PDO driver and default driver'
=>
array
(
array
(
'url'
=>
'mysql://foo:bar@localhost/baz'
,
'pdo'
=>
$pdoMock
,
'driver'
=>
'sqlite'
),
array
(
'user'
=>
'foo'
,
'password'
=>
'bar'
,
'host'
=>
'localhost'
,
'dbname'
=>
'baz'
,
'driver'
=>
'Doctrine\DBAL\Driver\PDOMySQL\Driver'
),
),
'URL with default driver and default custom driver'
=>
array
(
array
(
'url'
=>
'mysql://foo:bar@localhost/baz'
,
'driver'
=>
'sqlite'
,
'driverClass'
=>
'Doctrine\Tests\Mocks\DriverMock'
),
array
(
'user'
=>
'foo'
,
'password'
=>
'bar'
,
'host'
=>
'localhost'
,
'dbname'
=>
'baz'
,
'driver'
=>
'Doctrine\DBAL\Driver\PDOMySQL\Driver'
),
),
'URL with default PDO driver and default driver and default custom driver'
=>
array
(
array
(
'url'
=>
'mysql://foo:bar@localhost/baz'
,
'pdo'
=>
$pdoMock
,
'driver'
=>
'sqlite'
,
'driverClass'
=>
'Doctrine\Tests\Mocks\DriverMock'
),
array
(
'user'
=>
'foo'
,
'password'
=>
'bar'
,
'host'
=>
'localhost'
,
'dbname'
=>
'baz'
,
'driver'
=>
'Doctrine\DBAL\Driver\PDOMySQL\Driver'
),
),
);
);
}
}
}
}
tests/Doctrine/Tests/Mocks/PDOMock.php
0 → 100644
View file @
4a85a587
<?php
namespace
Doctrine\Tests\Mocks
;
class
PDOMock
extends
\PDO
{
public
function
__construct
()
{
}
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment