diff --git a/core/lib/Drupal/Core/Controller/HtmlPageController.php b/core/lib/Drupal/Core/Controller/HtmlPageController.php index d87b3ed..f5649dc 100644 --- a/core/lib/Drupal/Core/Controller/HtmlPageController.php +++ b/core/lib/Drupal/Core/Controller/HtmlPageController.php @@ -66,8 +66,18 @@ public function content(Request $request, $_content) { ); } // If no title was returned fall back to one defined in the route. - if (!isset($page_content['#title']) && $request->attributes->has('_title')) { - $page_content['#title'] = $request->attributes->get('_title'); + if (!isset($page_content['#title'])) { + // A dynamic title takes priority. + if ($request->attributes->has('_title_callback')) { + $callback = $request->attributes->get('_title_callback'); + $callable = $this->controllerResolver->getControllerFromDefinition($callback); + $arguments = $this->controllerResolver->getArguments($request, $callable); + $page_content['#title'] = call_user_func_array($callable, $arguments); + } + elseif ($request->attributes->has('_title')) { + // Fall back to a static string from the route. + $page_content['#title'] = $request->attributes->get('_title'); + } } $response = new Response(drupal_render_page($page_content)); diff --git a/core/modules/aggregator/aggregator.module b/core/modules/aggregator/aggregator.module index e5321d4..4fcb546 100644 --- a/core/modules/aggregator/aggregator.module +++ b/core/modules/aggregator/aggregator.module @@ -90,7 +90,6 @@ function aggregator_theme() { */ function aggregator_menu() { $items['admin/config/services/aggregator'] = array( - 'title' => 'Feed aggregator', 'description' => "Configure which content your site aggregates from other sites, how often it polls them, and how they're categorized.", 'route_name' => 'aggregator_admin_overview', 'weight' => 10, diff --git a/core/modules/aggregator/aggregator.routing.yml b/core/modules/aggregator/aggregator.routing.yml index cadbb14..f5ff870 100644 --- a/core/modules/aggregator/aggregator.routing.yml +++ b/core/modules/aggregator/aggregator.routing.yml @@ -2,6 +2,7 @@ aggregator_admin_overview: pattern: 'admin/config/services/aggregator' defaults: _content: '\Drupal\aggregator\Controller\AggregatorController::adminOverview' + _title: 'Feed aggregator' requirements: _permission: 'administer news feeds' diff --git a/core/modules/system/lib/Drupal/system/Tests/System/PageTitleTest.php b/core/modules/system/lib/Drupal/system/Tests/System/PageTitleTest.php index 942fa9e..08b8691 100644 --- a/core/modules/system/lib/Drupal/system/Tests/System/PageTitleTest.php +++ b/core/modules/system/lib/Drupal/system/Tests/System/PageTitleTest.php @@ -128,14 +128,29 @@ function testTitleXSS() { /** * Tests the page title of render arrays. * - * @see \Drupal\test_page_test\Controller\Test::renderTitle() + * @see \Drupal\test_page_test\Controller\Test */ - public function testRenderTitle() { + public function testRoutingTitle() { + // Test the '#title' render array attribute. $this->drupalGet('test-render-title'); $this->assertTitle('Foo | Drupal'); $result = $this->xpath('//h1'); $this->assertEqual('Foo', (string) $result[0]); + + // Test the static '_title' route option. + $this->drupalGet('test-static-title'); + + $this->assertTitle('Static title | Drupal'); + $result = $this->xpath('//h1'); + $this->assertEqual('Static title', (string) $result[0]); + + // Test the dynamic '_title_callback' route option. + $this->drupalGet('test-dynamic-title'); + + $this->assertTitle('Dynamic title | Drupal'); + $result = $this->xpath('//h1'); + $this->assertEqual('Dynamic title', (string) $result[0]); } } diff --git a/core/modules/system/tests/modules/test_page_test/lib/Drupal/test_page_test/Controller/Test.php b/core/modules/system/tests/modules/test_page_test/lib/Drupal/test_page_test/Controller/Test.php index 850ca2d..d73838c 100644 --- a/core/modules/system/tests/modules/test_page_test/lib/Drupal/test_page_test/Controller/Test.php +++ b/core/modules/system/tests/modules/test_page_test/lib/Drupal/test_page_test/Controller/Test.php @@ -26,4 +26,26 @@ public function renderTitle() { return $build; } + /** + * Returns a 'dynamic' title for the '_title_callback' route option. + * + * @return string + * The page title. + */ + public function dynamicTitle() { + return 'Dynamic title'; + } + + /** + * Returns a generic page render array for title tests. + * + * @return array + * A render array as expected by drupal_render() + */ + public function renderPage() { + return array( + '#markup' => 'Content', + ); + } + } diff --git a/core/modules/system/tests/modules/test_page_test/test_page_test.routing.yml b/core/modules/system/tests/modules/test_page_test/test_page_test.routing.yml index 0f45d10..2afeb19 100644 --- a/core/modules/system/tests/modules/test_page_test/test_page_test.routing.yml +++ b/core/modules/system/tests/modules/test_page_test/test_page_test.routing.yml @@ -4,3 +4,19 @@ test_page_render_title: _content: 'Drupal\test_page_test\Controller\Test::renderTitle' requirements: _access: 'TRUE' + +test_page_static_title: + pattern: '/test-static-title' + defaults: + _content: 'Drupal\test_page_test\Controller\Test::renderPage' + _title: 'Static title' + requirements: + _access: 'TRUE' + +test_page_dynamic_title: + pattern: '/test-dynamic-title' + defaults: + _content: 'Drupal\test_page_test\Controller\Test::renderPage' + _title_callback: 'Drupal\test_page_test\Controller\Test::dynamicTitle' + requirements: + _access: 'TRUE' diff --git a/core/modules/user/lib/Drupal/user/Controller/UserController.php b/core/modules/user/lib/Drupal/user/Controller/UserController.php index cd63cb0..1254060 100644 --- a/core/modules/user/lib/Drupal/user/Controller/UserController.php +++ b/core/modules/user/lib/Drupal/user/Controller/UserController.php @@ -7,7 +7,9 @@ namespace Drupal\user\Controller; +use Drupal\Core\Entity\EntityInterface; use Drupal\user\Form\UserLoginForm; +use Drupal\Component\Utility\Xss; use Symfony\Component\DependencyInjection\ContainerAware; use Symfony\Component\HttpFoundation\RedirectResponse; use Symfony\Component\HttpFoundation\Request; @@ -42,6 +44,19 @@ public function userPage(Request $request) { } /** + * Route title callback. + * + * @param \Drupal\Core\Entity\EntityInterface $user + * The user account. + * + * @return string + * The user account name. + */ + public function userTitle(EntityInterface $user = NULL) { + return $user ? Xss::filter($user->getUsername()) : ''; + } + + /** * Logs the current user out. * * @param \Symfony\Component\HttpFoundation\Request $request diff --git a/core/modules/user/user.module b/core/modules/user/user.module index 91e7ee1..ee9f519 100644 --- a/core/modules/user/user.module +++ b/core/modules/user/user.module @@ -915,13 +915,9 @@ function user_menu() { $items['user/%user'] = array( 'title' => 'My account', - 'title callback' => 'user_page_title', - 'title arguments' => array(1), - 'page callback' => 'user_view_page', - 'page arguments' => array(1), - 'access callback' => 'entity_page_access', - 'access arguments' => array(1), + 'route_name' => 'user_view', ); + $items['user/%user/view'] = array( 'title' => 'View', 'type' => MENU_DEFAULT_LOCAL_TASK, @@ -1079,13 +1075,6 @@ function user_menu_title() { } /** - * Menu item title callback - use the user name. - */ -function user_page_title(UserInterface $account = NULL) { - return $account ? $account->getUsername() : ''; -} - -/** * Try to validate the user's login credentials locally. * * @param $name diff --git a/core/modules/user/user.routing.yml b/core/modules/user/user.routing.yml index 90570ea..6539a7c 100644 --- a/core/modules/user/user.routing.yml +++ b/core/modules/user/user.routing.yml @@ -96,6 +96,14 @@ user_page: requirements: _access: 'TRUE' +user_view: + pattern: '/user/{user}' + defaults: + _entity_view: 'user.full' + _title_callback: 'Drupal\user\Controller\UserController::userTitle' + requirements: + _entity_access: 'user.view' + user_login: pattern: '/user/login' defaults: