Commit e7207972 authored by catch's avatar catch
Browse files

Issue #3518917 by penyaskito: Invalid service alias for backend_overridable...

Issue #3518917 by penyaskito: Invalid service alias for backend_overridable services in some cases when default_backend is set
parent e62e8422
Loading
Loading
Loading
Loading
Loading
+2 −3
Original line number Diff line number Diff line
@@ -37,7 +37,6 @@ class BackendCompilerPass implements CompilerPassInterface {
   * {@inheritdoc}
   */
  public function process(ContainerBuilder $container): void {
    $driver_backend = NULL;
    if ($container->hasParameter('default_backend')) {
      $default_backend = $container->getParameter('default_backend');
      // Opt out from the default backend.
@@ -64,10 +63,10 @@ public function process(ContainerBuilder $container): void {
      if ($container->hasAlias($id)) {
        continue;
      }
      if ($container->hasDefinition("$driver_backend.$id") || $container->hasAlias("$driver_backend.$id")) {
      if (isset($driver_backend) && ($container->hasDefinition("$driver_backend.$id") || $container->hasAlias("$driver_backend.$id"))) {
        $container->setAlias($id, new Alias("$driver_backend.$id"));
      }
      elseif ($container->hasDefinition("$default_backend.$id") || $container->hasAlias("$default_backend.$id")) {
      elseif (!empty($default_backend) && ($container->hasDefinition("$default_backend.$id") || $container->hasAlias("$default_backend.$id"))) {
        $container->setAlias($id, new Alias("$default_backend.$id"));
      }
    }
+88 −0
Original line number Diff line number Diff line
@@ -4,8 +4,10 @@

namespace Drupal\Tests\Core\DependencyInjection\Compiler;

use Drupal\Core\Database\Connection;
use Drupal\Core\DependencyInjection\Compiler\BackendCompilerPass;
use Drupal\Tests\UnitTestCase;
use PHPUnit\Framework\MockObject\MockObject;
use Symfony\Component\DependencyInjection\Alias;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Definition;
@@ -92,6 +94,16 @@ public function testProcess(): void {
    $container->setDefinition('DriverTestMysql.service', new Definition(__NAMESPACE__ . '\\ServiceClassDriverTestMysql'));
    $this->backendPass->process($container);
    $this->assertEquals($prefix . 'DriverTestMysql', get_class($container->get('service')));

    // Verify that if the container has a default_backend parameter,
    // and there is a service named ".my-service", the right alias is created.
    $container = $this->getMockDriverContainerWithDefaultBackendParameterArgumentAndDotPrefixedService();
    $this->backendPass->process($container);

    // Verify that if the db service returns no driver, no invalid aliases are
    // created.
    $container = $this->getMockDriverContainerWithNullDriverBackend();
    $this->backendPass->process($container);
  }

  /**
@@ -154,6 +166,82 @@ protected function getDriverTestMysqlContainer($service) {
    return $container;
  }

  /**
   * Creates a container with a database mock definition in it.
   *
   * This mock won't declare a driver nor databaseType to ensure no invalid
   * aliases are set.
   *
   * @return \Symfony\Component\DependencyInjection\ContainerBuilder
   *   The container with a mock database service in it.
   */
  protected function getMockDriverContainerWithNullDriverBackend(): ContainerBuilder&MockObject {
    $container = $this->getMockBuilder(ContainerBuilder::class)->getMock();
    $mock = $this->getMockBuilder(Connection::class)->disableOriginalConstructor()->getMock();
    $mock->expects($this->once())
      ->method('driver')
      ->willReturn(NULL);
    $mock->expects($this->once())
      ->method('databaseType')
      ->willReturn(NULL);
    $container->expects($this->any())
      ->method('get')
      ->with('database')
      ->willReturn($mock);
    $container->expects($this->once())
      ->method('findTaggedServiceIds')
      ->willReturn(['fakeService' => ['class' => 'fakeServiceClass']]);
    $container->expects($this->never())
      ->method('hasDefinition')
      ->with('.fakeService')
      ->willReturn(TRUE);
    $container->expects($this->never())
      ->method('setAlias');
    return $container;
  }

  /**
   * Creates a container with a database mock definition in it.
   *
   * This mock container has a default_backend parameter and a dot-prefixed
   * service to verify the right aliases are set.
   *
   * @return \Symfony\Component\DependencyInjection\ContainerBuilder
   *   The container with a mock database service in it.
   */
  protected function getMockDriverContainerWithDefaultBackendParameterArgumentAndDotPrefixedService(): ContainerBuilder&MockObject {
    $container = $this->getMockBuilder(ContainerBuilder::class)->getMock();
    $container->expects($this->once())
      ->method('hasParameter')
      ->with('default_backend')
      ->willReturn(TRUE);
    $container->expects($this->once())
      ->method('getParameter')
      ->with('default_backend')
      ->willReturn('a_valid_default_backend');

    $mock = $this->getMockBuilder(Connection::class)->disableOriginalConstructor()->getMock();
    $mock->expects($this->never())
      ->method('driver');
    $mock->expects($this->never())
      ->method('databaseType');
    $container->expects($this->any())
      ->method('get')
      ->with('database')
      ->willReturn($mock);
    $container->expects($this->once())
      ->method('findTaggedServiceIds')
      ->willReturn(['fakeService' => ['class' => 'fakeServiceClass']]);
    $container->expects($this->once())
      ->method('hasDefinition')
      ->with('a_valid_default_backend.fakeService')
      ->willReturn(TRUE);
    $container->expects($this->once())
      ->method('setAlias')
      ->with('fakeService', new Alias('a_valid_default_backend.fakeService'));
    return $container;
  }

}

/**