diff --git a/core/modules/user/src/Plugin/LanguageNegotiation/LanguageNegotiationUserAdmin.php b/core/modules/user/src/Plugin/LanguageNegotiation/LanguageNegotiationUserAdmin.php index cc0bfb5..cdd2695 100644 --- a/core/modules/user/src/Plugin/LanguageNegotiation/LanguageNegotiationUserAdmin.php +++ b/core/modules/user/src/Plugin/LanguageNegotiation/LanguageNegotiationUserAdmin.php @@ -7,12 +7,14 @@ namespace Drupal\user\Plugin\LanguageNegotiation; +use Drupal\Core\PathProcessor\PathProcessorManager; use Drupal\Core\Plugin\ContainerFactoryPluginInterface; use Drupal\Core\Routing\AdminContext; use Drupal\language\LanguageNegotiationMethodBase; use Symfony\Cmf\Component\Routing\RouteObjectInterface; use Symfony\Component\DependencyInjection\ContainerInterface; use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\Routing\Exception\ResourceNotFoundException; use Symfony\Component\Routing\Matcher\UrlMatcherInterface; /** @@ -51,16 +53,26 @@ class LanguageNegotiationUserAdmin extends LanguageNegotiationMethodBase impleme protected $router; /** + * The path processor manager. + * + * @var \Drupal\Core\PathProcessor\PathProcessorManager + */ + protected $pathProcessorManager; + + /** * Constructs a new LanguageNegotiationUserAdmin instance. * * @param \Drupal\Core\Routing\AdminContext $admin_context * The admin context. * @param \Symfony\Component\Routing\Matcher\UrlMatcherInterface $router * The router. + * @param \Drupal\Core\PathProcessor\PathProcessorManager $path_processor_manager + * The path processor manager. */ - public function __construct(AdminContext $admin_context, UrlMatcherInterface $router) { + public function __construct(AdminContext $admin_context, UrlMatcherInterface $router, PathProcessorManager $path_processor_manager) { $this->adminContext = $admin_context; $this->router = $router; + $this->pathProcessorManager = $path_processor_manager; } /** @@ -69,7 +81,8 @@ public function __construct(AdminContext $admin_context, UrlMatcherInterface $ro public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) { return new static( $container->get('router.admin_context'), - $container->get('router') + $container->get('router'), + $container->get('path_processor_manager') ); } @@ -105,10 +118,20 @@ public function getLangcode(Request $request = NULL) { public function isAdminPath(Request $request) { $result = FALSE; if ($request && $this->adminContext) { - // If called from an event subscriber, the request may not the route info - // yet, so use the router to look up the path first. + // If called from an event subscriber, the request may not have the route + // object yet (it is still being built), so use the router to look up + // based on the path. if (!$route_object = $request->attributes->get(RouteObjectInterface::ROUTE_OBJECT)) { - $attributes = $this->router->match('/' . urldecode(trim($request->getPathInfo(), '/'))); + try { + // Process the path as an inbound path. This will remove any language + // prefixes and other path components that inbound processing would + // clear out, so we can attempt to load the route clearly. + $path = $this->pathProcessorManager->processInbound(urldecode(trim($request->getPathInfo(), '/')), $request); + $attributes = $this->router->match('/' . $path); + } + catch (ResourceNotFoundException $e) { + return FALSE; + } $route_object = $attributes[RouteObjectInterface::ROUTE_OBJECT]; } $result = $this->adminContext->isAdminRoute($route_object); diff --git a/core/modules/user/src/Tests/UserAdminLanguageTest.php b/core/modules/user/src/Tests/UserAdminLanguageTest.php index be7a6cc..d2b08b7 100644 --- a/core/modules/user/src/Tests/UserAdminLanguageTest.php +++ b/core/modules/user/src/Tests/UserAdminLanguageTest.php @@ -36,7 +36,7 @@ class UserAdminLanguageTest extends WebTestBase { * * @var array */ - public static $modules = array('user', 'language'); + public static $modules = array('user', 'language', 'language_test'); public function setUp() { parent::setUp(); @@ -106,16 +106,59 @@ function testUserAdminLanguageConfigurationAvailableIfAdminLanguageNegotiationIs } /** + * Tests the actual language negotiation. + */ + function testActualNegotiation() { + $this->drupalLogin($this->adminUser); + $this->addCustomLanguage(); + $this->setLanguageNegotiation(); + + // Even though we have admin language negotiation, so long as the user has + // no preference set, negotiation will fall back further. + $path = 'user/' . $this->adminUser->id() . '/edit'; + $this->drupalGet($path); + $this->assertText('Language negotiation method: language-default'); + + // Set a preferred language code for the user. + $path = 'user/' . $this->adminUser->id() . '/edit'; + $edit = array(); + $edit['preferred_admin_langcode'] = 'xx'; + $this->drupalPostForm($path, $edit, t('Save')); + + // Test negotiation with the URL method first. The admin method will only + // be used if the URL method did not match. + $path = 'user/' . $this->adminUser->id() . '/edit'; + $this->drupalGet($path); + $this->assertText('Language negotiation method: language-user-admin'); + $path = 'xx/user/' . $this->adminUser->id() . '/edit'; + $this->drupalGet($path); + $this->assertText('Language negotiation method: language-url'); + + // Test negotiation with the admin language method first. The admin method + // will be used at all times. + $this->setLanguageNegotiation(TRUE); + $path = 'user/' . $this->adminUser->id() . '/edit'; + $this->drupalGet($path); + $this->assertText('Language negotiation method: language-user-admin'); + $path = 'xx/user/' . $this->adminUser->id() . '/edit'; + $this->drupalGet($path); + $this->assertText('Language negotiation method: language-user-admin'); + } + + /** * Sets the User interface negotiation detection method. * + * @param bool $admin_first + * Whether the admin negotiation should be first. + * * Enables the "Account preference for administration pages" language * detection method for the User interface language negotiation type. */ - function setLanguageNegotiation() { + function setLanguageNegotiation($admin_first = FALSE) { $edit = array( 'language_interface[enabled][language-user-admin]' => TRUE, 'language_interface[enabled][language-url]' => TRUE, - 'language_interface[weight][language-user-admin]' => -8, + 'language_interface[weight][language-user-admin]' => ($admin_first ? -12 : -8), 'language_interface[weight][language-url]' => -10, ); $this->drupalPostForm('admin/config/regional/language/detection', $edit, t('Save settings'));