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']);
|
||||
}
|
||||
|
||||
// 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.
|
||||
$this->setPrefix(isset($connection_options['prefix']) ? $connection_options['prefix'] : '');
|
||||
|
||||
|
@ -863,10 +870,6 @@ abstract class Connection {
|
|||
*/
|
||||
public function getDriverClass($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;
|
||||
$this->driverClasses[$class] = class_exists($driver_class) ? $driver_class : $class;
|
||||
if ($this->driverClasses[$class] === 'Condition') {
|
||||
|
|
|
@ -214,6 +214,7 @@ abstract class Database {
|
|||
if (empty($info['driver'])) {
|
||||
$info = $info[mt_rand(0, count($info) - 1)];
|
||||
}
|
||||
|
||||
// Parse the prefix information.
|
||||
if (!isset($info['prefix'])) {
|
||||
// Default to an empty prefix.
|
||||
|
@ -227,6 +228,12 @@ abstract class Database {
|
|||
'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;
|
||||
}
|
||||
|
||||
|
@ -368,8 +375,7 @@ abstract class Database {
|
|||
throw new DriverNotSpecifiedException('Driver not specified for this database connection: ' . $key);
|
||||
}
|
||||
|
||||
$namespace = static::getDatabaseDriverNamespace(self::$databaseInfo[$key][$target]);
|
||||
$driver_class = $namespace . '\\Connection';
|
||||
$driver_class = self::$databaseInfo[$key][$target]['namespace'] . '\\Connection';
|
||||
|
||||
$pdo_connection = $driver_class::open(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'])) {
|
||||
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
|
||||
// to the connection options to make it easy for the connection class's
|
||||
|
@ -628,8 +634,14 @@ abstract class Database {
|
|||
*
|
||||
* @return string
|
||||
* 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) {
|
||||
@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'])) {
|
||||
return $connection_info['namespace'];
|
||||
}
|
||||
|
|
|
@ -38,13 +38,6 @@ class Log {
|
|||
*/
|
||||
protected $connectionKey = 'default';
|
||||
|
||||
/**
|
||||
* The PHP namespace of the database driver that this object is logging.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $driverNamespace;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
|
@ -152,6 +145,8 @@ class Log {
|
|||
public function findCaller() {
|
||||
$stack = $this->getDebugBacktrace();
|
||||
|
||||
$driver_namespace = Database::getConnectionInfo($this->connectionKey)['default']['namespace'];
|
||||
|
||||
// Starting from the very first entry processed during the request, find
|
||||
// the first function call that can be identified as a call to a
|
||||
// method/function in the database layer.
|
||||
|
@ -160,7 +155,7 @@ class Log {
|
|||
// it a default empty string value in that case.
|
||||
$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;
|
||||
}
|
||||
}
|
||||
|
@ -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.
|
||||
*
|
||||
|
|
|
@ -46,8 +46,9 @@ trait LoggedStatementsTrait {
|
|||
* {@inheritdoc}
|
||||
*/
|
||||
public function getDriverClass($class) {
|
||||
// Override because the base class uses reflection to determine namespace
|
||||
// based on object, which would break.
|
||||
// Override because the database driver copies in the
|
||||
// database_statement_monitoring_test module don't contain all the necessary
|
||||
// classes.
|
||||
$namespace = (new \ReflectionClass(get_parent_class($this)))->getNamespaceName();
|
||||
$driver_class = $namespace . '\\' . $class;
|
||||
if (class_exists($driver_class)) {
|
||||
|
|
|
@ -155,14 +155,13 @@ class LoggingTest extends DatabaseTestBase {
|
|||
public function testContribDriverLog($driver_namespace, $stack, array $expected_entry) {
|
||||
$mock_builder = $this->getMockBuilder(Log::class);
|
||||
$log = $mock_builder
|
||||
->setMethods(['getDriverNamespace', 'getDebugBacktrace'])
|
||||
->setMethods(['getDebugBacktrace'])
|
||||
->setConstructorArgs(['test'])
|
||||
->getMock();
|
||||
$log->expects($this->any())
|
||||
->method('getDriverNamespace')
|
||||
->will($this->returnValue($driver_namespace));
|
||||
$log->expects($this->once())
|
||||
->method('getDebugBacktrace')
|
||||
->will($this->returnValue($stack));
|
||||
Database::addConnectionInfo('test', 'default', ['driver' => 'mysql', 'namespace' => $driver_namespace]);
|
||||
|
||||
$result = $log->findCaller($stack);
|
||||
$this->assertEquals($expected_entry, $result);
|
||||
|
|
|
@ -432,4 +432,13 @@ class ConnectionTest extends UnitTestCase {
|
|||
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;
|
||||
|
||||
use Drupal\Core\Database\Query\Select;
|
||||
use Drupal\Tests\Core\Database\Stub\StubConnection;
|
||||
use Drupal\Tests\Core\Database\Stub\StubPDO;
|
||||
use Drupal\Tests\UnitTestCase;
|
||||
|
||||
/**
|
||||
|
@ -23,9 +25,8 @@ class OrderByTest extends UnitTestCase {
|
|||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp(): void {
|
||||
$connection = $this->getMockBuilder('Drupal\Core\Database\Connection')
|
||||
->disableOriginalConstructor()
|
||||
->getMockForAbstractClass();
|
||||
$mockPdo = $this->createMock(StubPDO::class);
|
||||
$connection = new StubConnection($mockPdo, []);
|
||||
$this->query = new Select($connection, 'test', NULL);
|
||||
}
|
||||
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
namespace Drupal\Tests\Core\Database\Stub;
|
||||
|
||||
use Drupal\Core\Database\Connection;
|
||||
use Drupal\Core\Database\Log;
|
||||
use Drupal\Core\Database\StatementEmpty;
|
||||
|
||||
/**
|
||||
|
@ -84,4 +85,14 @@ class StubConnection extends Connection {
|
|||
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