diff --git a/core/modules/language/src/LanguageNegotiator.php b/core/modules/language/src/LanguageNegotiator.php index c4e083ab1a3..72bf83cea9e 100644 --- a/core/modules/language/src/LanguageNegotiator.php +++ b/core/modules/language/src/LanguageNegotiator.php @@ -2,8 +2,10 @@ namespace Drupal\language; +use Drupal\Component\Plugin\Exception\PluginNotFoundException; use Drupal\Component\Plugin\PluginManagerInterface; use Drupal\Core\Config\ConfigFactoryInterface; +use Drupal\Core\Logger\LoggerChannelTrait; use Drupal\Core\Session\AccountInterface; use Drupal\Core\Site\Settings; use Drupal\language\Plugin\LanguageNegotiation\LanguageNegotiationUI; @@ -13,6 +15,7 @@ use Symfony\Component\HttpFoundation\RequestStack; * Class responsible for performing language negotiation. */ class LanguageNegotiator implements LanguageNegotiatorInterface { + use LoggerChannelTrait; /** * The language negotiation method plugin manager. @@ -76,7 +79,7 @@ class LanguageNegotiator implements LanguageNegotiatorInterface { * @param \Drupal\language\ConfigurableLanguageManagerInterface $language_manager * The language manager. * @param \Drupal\Component\Plugin\PluginManagerInterface $negotiator_manager - * The language negotiation methods plugin manager + * The language negotiation methods plugin manager. * @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory * The configuration factory. * @param \Drupal\Core\Site\Settings $settings @@ -130,7 +133,13 @@ class LanguageNegotiator implements LanguageNegotiatorInterface { // and return the first valid language found. foreach ($this->getEnabledNegotiators($type) as $method_id => $info) { if (!isset($this->negotiatedLanguages[$method_id])) { - $this->negotiatedLanguages[$method_id] = $this->negotiateLanguage($type, $method_id); + try { + $this->negotiatedLanguages[$method_id] = $this->negotiateLanguage($type, $method_id); + } + catch (PluginNotFoundException $e) { + // If a plugin is not found, log the error so user can handle it. + $this->getLogger('language')->error($e->getMessage()); + } } // Since objects are references, we need to return a clone to prevent diff --git a/core/modules/language/tests/src/Kernel/LanguageNegotiatorPluginTest.php b/core/modules/language/tests/src/Kernel/LanguageNegotiatorPluginTest.php new file mode 100644 index 00000000000..a355071da57 --- /dev/null +++ b/core/modules/language/tests/src/Kernel/LanguageNegotiatorPluginTest.php @@ -0,0 +1,54 @@ +createMock(LoggerChannelFactory::class); + $logger_factory->expects($this->once()) + ->method('get') + ->with('language') + ->willReturn($logger); + $this->container->set('logger.factory', $logger_factory); + $this->installEntitySchema('user'); + + // Test unavailable plugin. + $config = $this->config('language.types'); + $config->set('configurable', [LanguageInterface::TYPE_URL]); + $config->set('negotiation.language_url.enabled', [ + self::CLASS => -3, + ]); + $config->save(); + $languageNegotiator = $this->container->get('language_negotiator'); + $languageNegotiator->setCurrentUser($this->prophesize('Drupal\Core\Session\AccountInterface')->reveal()); + try { + $languageNegotiator->initializeType(LanguageInterface::TYPE_URL); + } + catch (PluginNotFoundException $exception) { + $this->fail('Plugin not found exception unhandled.'); + } + $this->assertTrue($logger->hasErrorThatContains('The "Drupal\Tests\language\Kernel\LanguageNegotiatorPluginTest" plugin does not exist.')); + } + +}