Issue #3112476 by alexpott, Neslee Canil Pinto, mondrake, daffie, salah1, neelam_wadhwani: Always set $info['namespace'] on database connection info
parent
4994ca42d1
commit
2989dd00ba
|
@ -214,6 +214,13 @@ abstract class Connection {
|
||||||
unset($connection_options['transactions']);
|
unset($connection_options['transactions']);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Work out the database driver namespace if none is provided. This normally
|
||||||
|
// written to setting.php by installer or set by
|
||||||
|
// \Drupal\Core\Database\Database::parseConnectionInfo().
|
||||||
|
if (empty($connection_options['namespace'])) {
|
||||||
|
$connection_options['namespace'] = (new \ReflectionObject($this))->getNamespaceName();
|
||||||
|
}
|
||||||
|
|
||||||
// Initialize and prepare the connection prefix.
|
// Initialize and prepare the connection prefix.
|
||||||
$this->setPrefix(isset($connection_options['prefix']) ? $connection_options['prefix'] : '');
|
$this->setPrefix(isset($connection_options['prefix']) ? $connection_options['prefix'] : '');
|
||||||
|
|
||||||
|
@ -863,10 +870,6 @@ abstract class Connection {
|
||||||
*/
|
*/
|
||||||
public function getDriverClass($class) {
|
public function getDriverClass($class) {
|
||||||
if (empty($this->driverClasses[$class])) {
|
if (empty($this->driverClasses[$class])) {
|
||||||
if (empty($this->connectionOptions['namespace'])) {
|
|
||||||
// Fallback for Drupal 7 settings.php and the test runner script.
|
|
||||||
$this->connectionOptions['namespace'] = (new \ReflectionObject($this))->getNamespaceName();
|
|
||||||
}
|
|
||||||
$driver_class = $this->connectionOptions['namespace'] . '\\' . $class;
|
$driver_class = $this->connectionOptions['namespace'] . '\\' . $class;
|
||||||
$this->driverClasses[$class] = class_exists($driver_class) ? $driver_class : $class;
|
$this->driverClasses[$class] = class_exists($driver_class) ? $driver_class : $class;
|
||||||
if ($this->driverClasses[$class] === 'Condition') {
|
if ($this->driverClasses[$class] === 'Condition') {
|
||||||
|
|
|
@ -214,6 +214,7 @@ abstract class Database {
|
||||||
if (empty($info['driver'])) {
|
if (empty($info['driver'])) {
|
||||||
$info = $info[mt_rand(0, count($info) - 1)];
|
$info = $info[mt_rand(0, count($info) - 1)];
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse the prefix information.
|
// Parse the prefix information.
|
||||||
if (!isset($info['prefix'])) {
|
if (!isset($info['prefix'])) {
|
||||||
// Default to an empty prefix.
|
// Default to an empty prefix.
|
||||||
|
@ -227,6 +228,12 @@ abstract class Database {
|
||||||
'default' => $info['prefix'],
|
'default' => $info['prefix'],
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Fallback for Drupal 7 settings.php if namespace is not provided.
|
||||||
|
if (empty($info['namespace'])) {
|
||||||
|
$info['namespace'] = 'Drupal\\Core\\Database\\Driver\\' . $info['driver'];
|
||||||
|
}
|
||||||
|
|
||||||
return $info;
|
return $info;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -368,8 +375,7 @@ abstract class Database {
|
||||||
throw new DriverNotSpecifiedException('Driver not specified for this database connection: ' . $key);
|
throw new DriverNotSpecifiedException('Driver not specified for this database connection: ' . $key);
|
||||||
}
|
}
|
||||||
|
|
||||||
$namespace = static::getDatabaseDriverNamespace(self::$databaseInfo[$key][$target]);
|
$driver_class = self::$databaseInfo[$key][$target]['namespace'] . '\\Connection';
|
||||||
$driver_class = $namespace . '\\Connection';
|
|
||||||
|
|
||||||
$pdo_connection = $driver_class::open(self::$databaseInfo[$key][$target]);
|
$pdo_connection = $driver_class::open(self::$databaseInfo[$key][$target]);
|
||||||
$new_connection = new $driver_class($pdo_connection, self::$databaseInfo[$key][$target]);
|
$new_connection = new $driver_class($pdo_connection, self::$databaseInfo[$key][$target]);
|
||||||
|
@ -605,7 +611,7 @@ abstract class Database {
|
||||||
if (empty($db_info) || empty($db_info['default'])) {
|
if (empty($db_info) || empty($db_info['default'])) {
|
||||||
throw new \RuntimeException("Database connection $key not defined or missing the 'default' settings");
|
throw new \RuntimeException("Database connection $key not defined or missing the 'default' settings");
|
||||||
}
|
}
|
||||||
$namespace = static::getDatabaseDriverNamespace($db_info['default']);
|
$namespace = $db_info['default']['namespace'];
|
||||||
|
|
||||||
// If the driver namespace is within a Drupal module, add the module name
|
// If the driver namespace is within a Drupal module, add the module name
|
||||||
// to the connection options to make it easy for the connection class's
|
// to the connection options to make it easy for the connection class's
|
||||||
|
@ -628,8 +634,14 @@ abstract class Database {
|
||||||
*
|
*
|
||||||
* @return string
|
* @return string
|
||||||
* The PHP namespace of the driver's database.
|
* The PHP namespace of the driver's database.
|
||||||
|
*
|
||||||
|
* @deprecated in drupal:9.1.0 and is removed from drupal:10.0.0. There is no
|
||||||
|
* replacement as $connection_info['namespace'] is always set.
|
||||||
|
*
|
||||||
|
* @see https://www.drupal.org/node/3127769
|
||||||
*/
|
*/
|
||||||
protected static function getDatabaseDriverNamespace(array $connection_info) {
|
protected static function getDatabaseDriverNamespace(array $connection_info) {
|
||||||
|
@trigger_error(__METHOD__ . " is deprecated in drupal:9.1.0 and is removed from drupal:10.0.0. There is no replacement as \$connection_info['namespace'] is always set. See https://www.drupal.org/node/3127769.", E_USER_DEPRECATED);
|
||||||
if (isset($connection_info['namespace'])) {
|
if (isset($connection_info['namespace'])) {
|
||||||
return $connection_info['namespace'];
|
return $connection_info['namespace'];
|
||||||
}
|
}
|
||||||
|
|
|
@ -38,13 +38,6 @@ class Log {
|
||||||
*/
|
*/
|
||||||
protected $connectionKey = 'default';
|
protected $connectionKey = 'default';
|
||||||
|
|
||||||
/**
|
|
||||||
* The PHP namespace of the database driver that this object is logging.
|
|
||||||
*
|
|
||||||
* @var string
|
|
||||||
*/
|
|
||||||
protected $driverNamespace;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor.
|
* Constructor.
|
||||||
*
|
*
|
||||||
|
@ -152,6 +145,8 @@ class Log {
|
||||||
public function findCaller() {
|
public function findCaller() {
|
||||||
$stack = $this->getDebugBacktrace();
|
$stack = $this->getDebugBacktrace();
|
||||||
|
|
||||||
|
$driver_namespace = Database::getConnectionInfo($this->connectionKey)['default']['namespace'];
|
||||||
|
|
||||||
// Starting from the very first entry processed during the request, find
|
// Starting from the very first entry processed during the request, find
|
||||||
// the first function call that can be identified as a call to a
|
// the first function call that can be identified as a call to a
|
||||||
// method/function in the database layer.
|
// method/function in the database layer.
|
||||||
|
@ -160,7 +155,7 @@ class Log {
|
||||||
// it a default empty string value in that case.
|
// it a default empty string value in that case.
|
||||||
$class = $stack[$n]['class'] ?? '';
|
$class = $stack[$n]['class'] ?? '';
|
||||||
|
|
||||||
if (strpos($class, __NAMESPACE__, 0) === 0 || strpos($class, $this->getDriverNamespace(), 0) === 0) {
|
if (strpos($class, __NAMESPACE__, 0) === 0 || strpos($class, $driver_namespace, 0) === 0) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -181,20 +176,6 @@ class Log {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the namespace of the database driver.
|
|
||||||
*
|
|
||||||
* @return string|null
|
|
||||||
* Namespace of the database driver, or NULL if the connection is
|
|
||||||
* missing.
|
|
||||||
*/
|
|
||||||
protected function getDriverNamespace() {
|
|
||||||
if (!isset($this->driverNamespace)) {
|
|
||||||
$this->driverNamespace = (new \ReflectionObject(Database::getConnection('default', $this->connectionKey)))->getNamespaceName();
|
|
||||||
}
|
|
||||||
return $this->driverNamespace;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the debug backtrace.
|
* Gets the debug backtrace.
|
||||||
*
|
*
|
||||||
|
|
|
@ -46,8 +46,9 @@ trait LoggedStatementsTrait {
|
||||||
* {@inheritdoc}
|
* {@inheritdoc}
|
||||||
*/
|
*/
|
||||||
public function getDriverClass($class) {
|
public function getDriverClass($class) {
|
||||||
// Override because the base class uses reflection to determine namespace
|
// Override because the database driver copies in the
|
||||||
// based on object, which would break.
|
// database_statement_monitoring_test module don't contain all the necessary
|
||||||
|
// classes.
|
||||||
$namespace = (new \ReflectionClass(get_parent_class($this)))->getNamespaceName();
|
$namespace = (new \ReflectionClass(get_parent_class($this)))->getNamespaceName();
|
||||||
$driver_class = $namespace . '\\' . $class;
|
$driver_class = $namespace . '\\' . $class;
|
||||||
if (class_exists($driver_class)) {
|
if (class_exists($driver_class)) {
|
||||||
|
|
|
@ -155,14 +155,13 @@ class LoggingTest extends DatabaseTestBase {
|
||||||
public function testContribDriverLog($driver_namespace, $stack, array $expected_entry) {
|
public function testContribDriverLog($driver_namespace, $stack, array $expected_entry) {
|
||||||
$mock_builder = $this->getMockBuilder(Log::class);
|
$mock_builder = $this->getMockBuilder(Log::class);
|
||||||
$log = $mock_builder
|
$log = $mock_builder
|
||||||
->setMethods(['getDriverNamespace', 'getDebugBacktrace'])
|
->setMethods(['getDebugBacktrace'])
|
||||||
|
->setConstructorArgs(['test'])
|
||||||
->getMock();
|
->getMock();
|
||||||
$log->expects($this->any())
|
|
||||||
->method('getDriverNamespace')
|
|
||||||
->will($this->returnValue($driver_namespace));
|
|
||||||
$log->expects($this->once())
|
$log->expects($this->once())
|
||||||
->method('getDebugBacktrace')
|
->method('getDebugBacktrace')
|
||||||
->will($this->returnValue($stack));
|
->will($this->returnValue($stack));
|
||||||
|
Database::addConnectionInfo('test', 'default', ['driver' => 'mysql', 'namespace' => $driver_namespace]);
|
||||||
|
|
||||||
$result = $log->findCaller($stack);
|
$result = $log->findCaller($stack);
|
||||||
$this->assertEquals($expected_entry, $result);
|
$this->assertEquals($expected_entry, $result);
|
||||||
|
|
|
@ -432,4 +432,13 @@ class ConnectionTest extends UnitTestCase {
|
||||||
new StubConnection($mock_pdo, [], [0, '1']);
|
new StubConnection($mock_pdo, [], [0, '1']);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @covers ::__construct
|
||||||
|
*/
|
||||||
|
public function testNamespaceDefault() {
|
||||||
|
$mock_pdo = $this->createMock(StubPDO::class);
|
||||||
|
$connection = new StubConnection($mock_pdo, []);
|
||||||
|
$this->assertSame('Drupal\Tests\Core\Database\Stub', $connection->getConnectionOptions()['namespace']);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,55 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Drupal\Tests\Core\Database;
|
||||||
|
|
||||||
|
use Drupal\Core\Database\Database;
|
||||||
|
use Drupal\Core\Database\Log;
|
||||||
|
use Drupal\Tests\Core\Database\Stub\StubConnection;
|
||||||
|
use Drupal\Tests\Core\Database\Stub\StubPDO;
|
||||||
|
use Drupal\Tests\UnitTestCase;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests the Log class.
|
||||||
|
*
|
||||||
|
* @group Database
|
||||||
|
* @runTestsInSeparateProcesses
|
||||||
|
* @preserveGlobalState disabled
|
||||||
|
* @coversDefaultClass \Drupal\Core\Database\Log
|
||||||
|
*/
|
||||||
|
class LogTest extends UnitTestCase {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests that a log called by a custom database driver returns proper caller.
|
||||||
|
*
|
||||||
|
* @covers ::findCaller
|
||||||
|
*/
|
||||||
|
public function testContribDriverLog() {
|
||||||
|
Database::addConnectionInfo('default', 'default', [
|
||||||
|
'driver' => 'test',
|
||||||
|
'namespace' => 'Drupal\Tests\Core\Database\Stub',
|
||||||
|
]);
|
||||||
|
|
||||||
|
$pdo = $this->prophesize(StubPDO::class)->reveal();
|
||||||
|
$result = (new StubConnection($pdo, []))->testLogCaller();
|
||||||
|
$this->assertSame([
|
||||||
|
'file' => __FILE__,
|
||||||
|
'line' => 33,
|
||||||
|
'function' => 'testContribDriverLog',
|
||||||
|
'class' => 'Drupal\Tests\Core\Database\LogTest',
|
||||||
|
'type' => '->',
|
||||||
|
'args' => [],
|
||||||
|
], $result);
|
||||||
|
|
||||||
|
// Test calling the database log from outside of database code.
|
||||||
|
$result = (new Log())->findCaller();
|
||||||
|
$this->assertSame([
|
||||||
|
'file' => __FILE__,
|
||||||
|
'line' => 44,
|
||||||
|
'function' => 'testContribDriverLog',
|
||||||
|
'class' => 'Drupal\Tests\Core\Database\LogTest',
|
||||||
|
'type' => '->',
|
||||||
|
'args' => [],
|
||||||
|
], $result);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -3,6 +3,8 @@
|
||||||
namespace Drupal\Tests\Core\Database;
|
namespace Drupal\Tests\Core\Database;
|
||||||
|
|
||||||
use Drupal\Core\Database\Query\Select;
|
use Drupal\Core\Database\Query\Select;
|
||||||
|
use Drupal\Tests\Core\Database\Stub\StubConnection;
|
||||||
|
use Drupal\Tests\Core\Database\Stub\StubPDO;
|
||||||
use Drupal\Tests\UnitTestCase;
|
use Drupal\Tests\UnitTestCase;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -23,9 +25,8 @@ class OrderByTest extends UnitTestCase {
|
||||||
* {@inheritdoc}
|
* {@inheritdoc}
|
||||||
*/
|
*/
|
||||||
protected function setUp(): void {
|
protected function setUp(): void {
|
||||||
$connection = $this->getMockBuilder('Drupal\Core\Database\Connection')
|
$mockPdo = $this->createMock(StubPDO::class);
|
||||||
->disableOriginalConstructor()
|
$connection = new StubConnection($mockPdo, []);
|
||||||
->getMockForAbstractClass();
|
|
||||||
$this->query = new Select($connection, 'test', NULL);
|
$this->query = new Select($connection, 'test', NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
namespace Drupal\Tests\Core\Database\Stub;
|
namespace Drupal\Tests\Core\Database\Stub;
|
||||||
|
|
||||||
use Drupal\Core\Database\Connection;
|
use Drupal\Core\Database\Connection;
|
||||||
|
use Drupal\Core\Database\Log;
|
||||||
use Drupal\Core\Database\StatementEmpty;
|
use Drupal\Core\Database\StatementEmpty;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -84,4 +85,14 @@ class StubConnection extends Connection {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper method to test database classes are not included in backtraces.
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
* The caller stack entry.
|
||||||
|
*/
|
||||||
|
public function testLogCaller() {
|
||||||
|
return (new Log())->findCaller();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue