Commit 9d3ad415 authored by catch's avatar catch
Browse files

Issue #3294695 by daffie, longwave, mkalkbrenner, pandaski: Drupal 8 BC for...

Issue #3294695 by daffie, longwave, mkalkbrenner, pandaski: Drupal 8 BC for database driver namespace fails for replicas

(cherry picked from commit 363292fb)
parent cfb2f77a
Loading
Loading
Loading
Loading
+60 −7
Original line number Diff line number Diff line
@@ -256,9 +256,41 @@ final public static function parseConnectionInfo(array $info) {
      $info['prefix'] = $prefix;
    }

    // Fallback for Drupal 7 settings.php if namespace is not provided.
    if (empty($info['namespace'])) {
      $info['namespace'] = 'Drupal\\' . $info['driver'] . '\\Driver\\Database\\' . $info['driver'];
    // Backwards compatibility layer for Drupal 8 style database connection
    // arrays. Those have the wrong 'namespace' key set, or not set at all
    // for core supported database drivers.
    if (empty($info['namespace']) || (strpos($info['namespace'], 'Drupal\\Core\\Database\\Driver\\') === 0)) {
      switch (strtolower($info['driver'])) {
        case 'mysql':
          $info['namespace'] = 'Drupal\\mysql\\Driver\\Database\\mysql';
          break;

        case 'pgsql':
          $info['namespace'] = 'Drupal\\pgsql\\Driver\\Database\\pgsql';
          break;

        case 'sqlite':
          $info['namespace'] = 'Drupal\\sqlite\\Driver\\Database\\sqlite';
          break;
      }
    }
    // Backwards compatibility layer for Drupal 8 style database connection
    // arrays. Those do not have the 'autoload' key set for core database
    // drivers.
    if (empty($info['autoload'])) {
      switch (trim($info['namespace'], '\\')) {
        case "Drupal\\mysql\\Driver\\Database\\mysql":
          $info['autoload'] = "core/modules/mysql/src/Driver/Database/mysql/";
          break;

        case "Drupal\\pgsql\\Driver\\Database\\pgsql":
          $info['autoload'] = "core/modules/pgsql/src/Driver/Database/pgsql/";
          break;

        case "Drupal\\sqlite\\Driver\\Database\\sqlite":
          $info['autoload'] = "core/modules/sqlite/src/Driver/Database/sqlite/";
          break;
      }
    }

    return $info;
@@ -286,12 +318,28 @@ final public static function parseConnectionInfo(array $info) {
   *   The database connection information, as defined in settings.php. The
   *   structure of this array depends on the database driver it is connecting
   *   to.
   * @param \Composer\Autoload\ClassLoader $class_loader
   *   The class loader. Used for adding the database driver to the autoloader
   *   if $info['autoload'] is set.
   * @param string $app_root
   *   The app root.
   *
   * @see \Drupal\Core\Database\Database::setActiveConnection
   */
  final public static function addConnectionInfo($key, $target, array $info) {
  final public static function addConnectionInfo($key, $target, array $info, $class_loader = NULL, $app_root = NULL) {
    if (empty(self::$databaseInfo[$key][$target])) {
      self::$databaseInfo[$key][$target] = self::parseConnectionInfo($info);
      $info = self::parseConnectionInfo($info);
      self::$databaseInfo[$key][$target] = $info;

      // If the database driver is provided by a module, then its code may need
      // to be instantiated prior to when the module's root namespace is added
      // to the autoloader, because that happens during service container
      // initialization but the container definition is likely in the database.
      // Therefore, allow the connection info to specify an autoload directory
      // for the driver.
      if (isset($info['autoload']) && $class_loader && $app_root) {
        $class_loader->addPsr4($info['namespace'] . '\\', $app_root . '/' . $info['autoload']);
      }
    }
  }

@@ -324,11 +372,16 @@ final public static function getAllConnectionInfo() {
   * @param array $databases
   *   A multi-dimensional array specifying database connection parameters, as
   *   defined in settings.php.
   * @param \Composer\Autoload\ClassLoader $class_loader
   *   The class loader. Used for adding the database driver(s) to the
   *   autoloader if $databases[$key][$target]['autoload'] is set.
   * @param string $app_root
   *   The app root.
   */
  final public static function setMultipleConnectionInfo(array $databases) {
  final public static function setMultipleConnectionInfo(array $databases, $class_loader = NULL, $app_root = NULL) {
    foreach ($databases as $key => $targets) {
      foreach ($targets as $target => $info) {
        self::addConnectionInfo($key, $target, $info);
        self::addConnectionInfo($key, $target, $info, $class_loader, $app_root);
      }
    }
  }
+1 −51
Original line number Diff line number Diff line
@@ -160,57 +160,7 @@ public static function initialize($app_root, $site_path, &$class_loader) {
    self::handleDeprecations($settings);

    // Initialize databases.
    foreach ($databases as $key => $targets) {
      foreach ($targets as $target => $info) {
        // Backwards compatibility layer for Drupal 8 style database connection
        // arrays. Those have the wrong 'namespace' key set, or not set at all
        // for core supported database drivers.
        if (empty($info['namespace']) || (strpos($info['namespace'], 'Drupal\\Core\\Database\\Driver\\') === 0)) {
          switch (strtolower($info['driver'])) {
            case 'mysql':
              $info['namespace'] = 'Drupal\\mysql\\Driver\\Database\\mysql';
              break;

            case 'pgsql':
              $info['namespace'] = 'Drupal\\pgsql\\Driver\\Database\\pgsql';
              break;

            case 'sqlite':
              $info['namespace'] = 'Drupal\\sqlite\\Driver\\Database\\sqlite';
              break;
          }
        }
        // Backwards compatibility layer for Drupal 8 style database connection
        // arrays. Those do not have the 'autoload' key set for core database
        // drivers.
        if (empty($info['autoload'])) {
          switch (trim($info['namespace'], '\\')) {
            case "Drupal\\mysql\\Driver\\Database\\mysql":
              $info['autoload'] = "core/modules/mysql/src/Driver/Database/mysql/";
              break;

            case "Drupal\\pgsql\\Driver\\Database\\pgsql":
              $info['autoload'] = "core/modules/pgsql/src/Driver/Database/pgsql/";
              break;

            case "Drupal\\sqlite\\Driver\\Database\\sqlite":
              $info['autoload'] = "core/modules/sqlite/src/Driver/Database/sqlite/";
              break;
          }
        }

        Database::addConnectionInfo($key, $target, $info);
        // If the database driver is provided by a module, then its code may
        // need to be instantiated prior to when the module's root namespace
        // is added to the autoloader, because that happens during service
        // container initialization but the container definition is likely in
        // the database. Therefore, allow the connection info to specify an
        // autoload directory for the driver.
        if (isset($info['autoload'])) {
          $class_loader->addPsr4($info['namespace'] . '\\', $app_root . '/' . $info['autoload']);
        }
      }
    }
    Database::setMultipleConnectionInfo($databases, $class_loader, $app_root);

    // Initialize Settings.
    new Settings($settings);
+24 −0
Original line number Diff line number Diff line
@@ -2,6 +2,7 @@

namespace Drupal\FunctionalTests;

use Drupal\Core\Database\Connection;
use Drupal\Core\Database\Database;
use Drupal\Tests\BrowserTestBase;

@@ -35,6 +36,19 @@ protected function setUp(): void {
    $namespace_search = "'namespace' => 'Drupal\\\\$driver\\\\Driver\\\\Database\\\\$driver',";
    $namespace_replace = "'namespace' => 'Drupal\\\\Core\\\\Database\\\\Driver\\\\$driver',";
    $contents = str_replace($namespace_search, $namespace_replace, $contents);

    // Add a replica connection to the database settings.
    $contents .= "\$databases['default']['replica'][] = array (\n";
    $contents .= "  'database' => 'db',\n";
    $contents .= "  'username' => 'db',\n";
    $contents .= "  'password' => 'db',\n";
    $contents .= "  'prefix' => 'test22806835',\n";
    $contents .= "  'host' => 'db',\n";
    $contents .= "  'port' => 3306,\n";
    $contents .= "  $namespace_replace\n";
    $contents .= "  'driver' => 'mysql',\n";
    $contents .= ");\n";

    file_put_contents($filename, $contents);
  }

@@ -56,4 +70,14 @@ public function testExistingDrupal8StyleDatabaseConnectionInSettingsPhp() {
    $this->assertStringNotContainsString("'autoload' => 'core/modules/$driver/src/Driver/Database/$driver/", $contents);
  }

  /**
   * Confirms that the replica database connection works.
   */
  public function testReplicaDrupal8StyleDatabaseConnectionInSettingsPhp() {
    $this->drupalLogin($this->drupalCreateUser());

    $replica = Database::getConnection('replica', 'default');
    $this->assertInstanceOf(Connection::class, $replica);
  }

}