diff --git a/core/core.services.yml b/core/core.services.yml index 640440b..70810a5 100644 --- a/core/core.services.yml +++ b/core/core.services.yml @@ -332,7 +332,8 @@ services: - { name: route_enhancer, priority: 10 } controller.page: class: Drupal\Core\Controller\HtmlPageController - arguments: ['@http_kernel'] + calls: + - [setContainer, ['@service_container']] controller.dialog: class: Drupal\Core\Controller\DialogController arguments: ['@http_kernel'] diff --git a/core/includes/bootstrap.inc b/core/includes/bootstrap.inc index f7ab2d7..37ef268 100644 --- a/core/includes/bootstrap.inc +++ b/core/includes/bootstrap.inc @@ -202,11 +202,6 @@ define('REQUEST_TIME', (int) $_SERVER['REQUEST_TIME']); /** - * Flag for drupal_set_title(); text is not sanitized, so run check_plain(). - */ -const CHECK_PLAIN = 0; - -/** * Flag for drupal_set_title(); text has already been sanitized. */ const PASS_THROUGH = -1; @@ -1722,7 +1717,7 @@ function drupal_get_title() { * @return * The updated title of the current page. */ -function drupal_set_title($title = NULL, $output = CHECK_PLAIN) { +function drupal_set_title($title = NULL, $output = String::CHECK_PLAIN) { $stored_title = &drupal_static(__FUNCTION__); if (isset($title)) { diff --git a/core/includes/common.inc b/core/includes/common.inc index dfd20fa..603f7c7 100644 --- a/core/includes/common.inc +++ b/core/includes/common.inc @@ -3628,6 +3628,11 @@ function drupal_pre_render_dropbutton($element) { function drupal_render_page($page) { $main_content_display = &drupal_static('system_main_content_added', FALSE); + // Pull out the page title to set it back later. + if (is_array($page) && isset($page['#title'])) { + $title = $page['#title']; + } + // Allow menu callbacks to return strings or arbitrary arrays to render. // If the array returned is not of #type page directly, we need to fill // in the page with defaults. @@ -3652,6 +3657,11 @@ function drupal_render_page($page) { $page['content']['system_main'] = drupal_set_page_content(); } + // Set back the previously stored title. + if (isset($title)) { + $page['#title'] = $title; + } + return drupal_render($page); } diff --git a/core/includes/theme.inc b/core/includes/theme.inc index 2a2de1f..b86bbe3 100644 --- a/core/includes/theme.inc +++ b/core/includes/theme.inc @@ -2624,8 +2624,14 @@ function template_preprocess_html(&$variables) { } $site_config = config('system.site'); - // Construct page title. - if (drupal_get_title()) { + // Construct page title + if (isset($variables['page']['#title'])) { + $head_title = array( + 'title' => strip_tags($variables['page']['#title']), + 'name' => check_plain($site_config->get('name')), + ); + } + elseif(drupal_get_title()) { $head_title = array( 'title' => strip_tags(drupal_get_title()), 'name' => check_plain($site_config->get('name')), @@ -2800,6 +2806,11 @@ function template_process_page(&$variables) { '#breadcrumb' => \Drupal::service('breadcrumb')->build(\Drupal::service('request')->attributes->all()), ); } + + // Allow the page to define a title. + if (isset($variables['page']['#title'])) { + $variables['title'] = $variables['page']['#title']; + } if (!isset($variables['title'])) { $variables['title'] = drupal_get_title(); } @@ -2828,6 +2839,13 @@ function template_process_html(&$variables) { $variables['css'] = drupal_add_css(); $variables['styles'] = drupal_get_css(); $variables['scripts'] = drupal_get_js(); + // Allow the page to define a title. + if (isset($variables['page']['#title'])) { + $variables['title'] = $variables['page']['#title']; + } + if (!isset($variables['title'])) { + $variables['title'] = drupal_get_title(); + } } /** @@ -2950,7 +2968,13 @@ function template_preprocess_maintenance_page(&$variables) { $site_slogan = $site_config->get('slogan'); // Construct page title - if (drupal_get_title()) { + if (isset($variables['page']['#title'])) { + $head_title = array( + 'title' => strip_tags($variables['page']['#title']), + 'name' => check_plain($site_name), + ); + } + elseif(drupal_get_title()) { $head_title = array( 'title' => strip_tags(drupal_get_title()), 'name' => check_plain($site_name), diff --git a/core/lib/Drupal/Component/Utility/String.php b/core/lib/Drupal/Component/Utility/String.php index 3cd6472..44d6915 100644 --- a/core/lib/Drupal/Component/Utility/String.php +++ b/core/lib/Drupal/Component/Utility/String.php @@ -13,6 +13,11 @@ class String { /** + * Flag for drupal_set_title(); text is not sanitized, so run String::checkPlain(). + */ + const CHECK_PLAIN = 0; + + /** * Encodes special characters in a plain-text string for display as HTML. * * Also validates strings as UTF-8. diff --git a/core/lib/Drupal/Core/Controller/ControllerResolver.php b/core/lib/Drupal/Core/Controller/ControllerResolver.php index 385f198..1c0cbbd 100644 --- a/core/lib/Drupal/Core/Controller/ControllerResolver.php +++ b/core/lib/Drupal/Core/Controller/ControllerResolver.php @@ -65,7 +65,7 @@ public function __construct(ContainerInterface $container, LoggerInterface $logg * @throws \InvalidArgumentException * If the controller class does not exist */ - protected function createController($controller) { + public function createController($controller) { // Controller in the service:method notation. $count = substr_count($controller, ':'); if ($count == 1) { diff --git a/core/lib/Drupal/Core/Controller/HtmlPageController.php b/core/lib/Drupal/Core/Controller/HtmlPageController.php index fd89081..5c88e59 100644 --- a/core/lib/Drupal/Core/Controller/HtmlPageController.php +++ b/core/lib/Drupal/Core/Controller/HtmlPageController.php @@ -7,6 +7,8 @@ namespace Drupal\Core\Controller; +use Symfony\Component\DependencyInjection\ContainerInterface; +use Symfony\Component\DependencyInjection\ContainerAwareInterface; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpKernel\HttpKernelInterface; @@ -14,22 +16,23 @@ /** * Default controller for most HTML pages. */ -class HtmlPageController { +class HtmlPageController implements ContainerAwareInterface { /** - * The HttpKernel object to use for subrequests. + * The injection container for this object. * - * @var \Symfony\Component\HttpKernel\HttpKernelInterface + * @var \Symfony\Component\DependencyInjection\ContainerInterface */ - protected $httpKernel; + protected $container; /** - * Constructs a new HtmlPageController. + * Injects the service container used by this object. * - * @param \Symfony\Component\HttpKernel\HttpKernelInterface $kernel + * @param \Symfony\Component\DependencyInjection\ContainerInterface $container + * The service container this object should use. */ - public function __construct(HttpKernelInterface $kernel) { - $this->httpKernel = $kernel; + public function setContainer(ContainerInterface $container = NULL) { + $this->container = $container; } /** @@ -44,28 +47,22 @@ public function __construct(HttpKernelInterface $kernel) { * A response object. */ public function content(Request $request, $_content) { - - // @todo When we have a Generator, we can replace the forward() call with - // a render() call, which would handle ESI and hInclude as well. That will - // require an _internal route. For examples, see: - // https://github.com/symfony/symfony/blob/master/src/Symfony/Bundle/FrameworkBundle/Resources/config/routing/internal.xml - // https://github.com/symfony/symfony/blob/master/src/Symfony/Bundle/FrameworkBundle/Controller/InternalController.php - $attributes = clone $request->attributes; - $controller = $_content; - - // We need to clean off the derived information and such so that the - // subrequest can be processed properly without leaking data through. - $attributes->remove('system_path'); - $attributes->remove('_content'); - - $response = $this->httpKernel->forward($controller, $attributes->all(), $request->query->all()); - - // For successful (HTTP status 200) responses, decorate with blocks. - if ($response->isOk()) { - $page_content = $response->getContent(); - $response = new Response(drupal_render_page($page_content)); + $resolver = $this->container->get('controller_resolver'); + $callable = $resolver->createController($_content); + $arguments = $resolver->getArguments($request, $callable); + $page_content = call_user_func_array($callable, $arguments); + if ($page_content instanceof Response) { + return $page_content; } - + if (!is_array($page_content)) { + $page_content = array( + '#markup' => $page_content, + ); + } + if (!isset($page_content['#title']) && $request->attributes->has('_title')) { + $page_content['#title'] = $request->attributes->get('_title'); + } + $response = new Response(drupal_render_page($page_content)); return $response; } } diff --git a/core/modules/block/block.routing.yml b/core/modules/block/block.routing.yml index cabd4cb..a2ca6e5 100644 --- a/core/modules/block/block.routing.yml +++ b/core/modules/block/block.routing.yml @@ -24,5 +24,6 @@ block_admin_add: pattern: '/admin/structure/block/add/{plugin_id}/{theme}' defaults: _content: '\Drupal\block\Controller\BlockAddController::blockAddConfigureForm' + _title: 'Configure block' requirements: _permission: 'administer blocks' diff --git a/core/modules/block/lib/Drupal/block/Controller/BlockAddController.php b/core/modules/block/lib/Drupal/block/Controller/BlockAddController.php index f7f4e38..88fac95 100644 --- a/core/modules/block/lib/Drupal/block/Controller/BlockAddController.php +++ b/core/modules/block/lib/Drupal/block/Controller/BlockAddController.php @@ -47,9 +47,6 @@ public static function create(ContainerInterface $container) { * The block instance edit form. */ public function blockAddConfigureForm($plugin_id, $theme) { - // Set the page title. - drupal_set_title(t('Configure block')); - // Create a block entity. $entity = $this->entityManager->getStorageController('block')->create(array('plugin' => $plugin_id, 'theme' => $theme)); diff --git a/core/modules/system/lib/Drupal/system/Tests/System/PageTitleFilteringTest.php b/core/modules/system/lib/Drupal/system/Tests/System/PageTitleTest.php similarity index 89% rename from core/modules/system/lib/Drupal/system/Tests/System/PageTitleFilteringTest.php rename to core/modules/system/lib/Drupal/system/Tests/System/PageTitleTest.php index 9d96be8..22b26f8 100644 --- a/core/modules/system/lib/Drupal/system/Tests/System/PageTitleFilteringTest.php +++ b/core/modules/system/lib/Drupal/system/Tests/System/PageTitleTest.php @@ -7,17 +7,18 @@ namespace Drupal\system\Tests\System; +use Drupal\Component\Utility\String; use Drupal\Core\Language\Language; use Drupal\simpletest\WebTestBase; -class PageTitleFilteringTest extends WebTestBase { +class PageTitleTest extends WebTestBase { /** * Modules to enable. * * @var array */ - public static $modules = array('node'); + public static $modules = array('node', 'test_page_test'); protected $content_user; protected $saved_title; @@ -27,7 +28,7 @@ class PageTitleFilteringTest extends WebTestBase { */ public static function getInfo() { return array( - 'name' => 'HTML in page titles', + 'name' => 'Page titles', 'description' => 'Tests correct handling or conversion by drupal_set_title() and drupal_get_title() and checks the correct escaping of site name and slogan.', 'group' => 'System' ); @@ -63,7 +64,7 @@ function testTitleTags() { $title = "string with HTML"; // drupal_set_title's $filter is CHECK_PLAIN by default, so the title should be // returned with check_plain(). - drupal_set_title($title, CHECK_PLAIN); + drupal_set_title($title, String::CHECK_PLAIN); $this->assertTrue(strpos(drupal_get_title(), '') === FALSE, 'Tags in title converted to entities when $output is CHECK_PLAIN.'); // drupal_set_title's $filter is passed as PASS_THROUGH, so the title should be // returned with HTML. @@ -122,4 +123,15 @@ function testTitleXSS() { $this->assertNoRaw($slogan, 'Check for the unfiltered version of the slogan.'); $this->assertRaw($slogan_filtered, 'Check for the filtered version of the slogan.'); } + + /** + * Tests the page title of render arrays. + * + * @see \Drupal\test_page_test\Controller\Test::renderTitle() + */ + public function testRenderTitle() { + $this->drupalGet('test-render-title'); + $this->assertTitle('Foo | Drupal'); + } + } 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 new file mode 100644 index 0000000..611b53f --- /dev/null +++ b/core/modules/system/tests/modules/test_page_test/lib/Drupal/test_page_test/Controller/Test.php @@ -0,0 +1,26 @@ +