Commit 42daa83c authored by alexpott's avatar alexpott

Issue #1911728 by ParisLiakos, Xano, dawehner, jibran, David_Rothstein: Remove hook_init().

parent 17c06e0c
......@@ -27,9 +27,8 @@
* Global flag to identify update.php and authorize.php runs.
*
* Identifies update.php and authorize.php runs, avoiding unwanted operations
* such as hook_init() invocations, css/js preprocessing and
* translation, and solves some theming issues. The flag is checked in other
* places in Drupal code (not just authorize.php).
* such as css/js preprocessing and translation, and solves some theming issues.
* The flag is checked in other places in Drupal code (not just authorize.php).
*/
const MAINTENANCE_MODE = 'update';
......
......@@ -427,3 +427,7 @@ services:
batch.storage:
class: Drupal\Core\Utility\BatchStorage
arguments: ['@database']
slave_database_ignore__subscriber:
class: Drupal\Core\EventSubscriber\SlaveDatabaseIgnoreSubscriber
tags:
- {name: event_subscriber}
......@@ -1888,7 +1888,7 @@ function drupal_add_html_head_link($attributes, $header = FALSE) {
* all typical visitors and most pages of a site. It is critical that all
* preprocessed files are added unconditionally on every page, even if the
* files do not happen to be needed on a page. This is normally done by calling
* drupal_add_css() in a hook_init() implementation.
* drupal_add_css() in a hook_page_build() implementation.
*
* Non-preprocessed files should only be added to the page when they are
* actually needed.
......@@ -1943,14 +1943,15 @@ function drupal_add_html_head_link($attributes, $header = FALSE) {
* enabled, this should be set to TRUE if the stylesheet is present on every
* page of the website for users for whom it is present at all. This
* defaults to FALSE. It is set to TRUE for stylesheets added via module and
* theme .info.yml files. Modules that add stylesheets within hook_init()
* implementations, or from other code that ensures that the stylesheet is
* added to all website pages, should also set this flag to TRUE. All
* stylesheets within the same group that have the 'every_page' flag set to
* TRUE and do not have 'preprocess' set to FALSE are aggregated together
* into a single aggregate file, and that aggregate file can be reused
* across a user's entire site visit, leading to faster navigation between
* pages. However, stylesheets that are only needed on pages less frequently
* theme .info.yml files. Modules that add stylesheets within
* hook_page_build() implementations, or from other code that ensures that
* the stylesheet is added to all website pages, should also set this flag
* to TRUE. All stylesheets within the same group that have the 'every_page'
* flag set to TRUE and do not have 'preprocess' set to FALSE are aggregated
* together into a single aggregate file, and that aggregate file can be
* reused across a user's entire site visit, leading to faster navigation
* between pages.
* However, stylesheets that are only needed on pages less frequently
* visited, can be added by code that only runs for those particular pages,
* and that code should not set the 'every_page' flag. This minimizes the
* size of the aggregate file that the user needs to download when first
......@@ -3036,7 +3037,7 @@ function drupal_region_class($region) {
* all typical visitors and most pages of a site. It is critical that all
* preprocessed files are added unconditionally on every page, even if the
* files are not needed on a page. This is normally done by calling
* drupal_add_js() in a hook_init() implementation.
* drupal_add_js() in a hook_page_build() implementation.
*
* Non-preprocessed files should only be added to the page when they are
* actually needed.
......@@ -3079,9 +3080,9 @@ function drupal_region_class($region) {
* page of the website for users for whom it is present at all. This
* defaults to FALSE. It is set to TRUE for JavaScript files that are added
* via module and theme .info.yml files. Modules that add JavaScript within
* hook_init() implementations, or from other code that ensures that the
* JavaScript is added to all website pages, should also set this flag to
* TRUE. All JavaScript files within the same group and that have the
* hook_page_build() implementations, or from other code that ensures that
* the JavaScript is added to all website pages, should also set this flag
* to TRUE. All JavaScript files within the same group and that have the
* 'every_page' flag set to TRUE and do not have 'preprocess' set to FALSE
* are aggregated together into a single aggregate file, and that aggregate
* file can be reused across a user's entire site visit, leading to faster
......@@ -4365,16 +4366,8 @@ function _drupal_bootstrap_full($skip = FALSE) {
// Let all modules take action before the menu system handles the request.
// We do not want this while running update.php.
if (!defined('MAINTENANCE_MODE') || MAINTENANCE_MODE != 'update') {
// Prior to invoking hook_init(), initialize the theme (potentially a custom
// one for this page), so that:
// - Modules with hook_init() implementations that call theme() or
// theme_get_registry() don't initialize the incorrect theme.
// - The theme can have hook_*_alter() implementations affect page building
// (e.g., hook_form_alter(), hook_node_view_alter(), hook_page_alter()),
// ahead of when rendering starts.
menu_set_custom_theme();
drupal_theme_initialize();
module_invoke_all('init');
}
}
......
......@@ -27,16 +27,8 @@ class LegacyRequestSubscriber implements EventSubscriberInterface {
*/
public function onKernelRequestLegacy(GetResponseEvent $event) {
if ($event->getRequestType() == HttpKernelInterface::MASTER_REQUEST) {
// Prior to invoking hook_init(), initialize the theme (potentially a
// custom one for this page), so that:
// - Modules with hook_init() implementations that call theme() or
// theme_get_registry() don't initialize the incorrect theme.
// - The theme can have hook_*_alter() implementations affect page
// building (e.g., hook_form_alter(), hook_node_view_alter(),
// hook_page_alter()), ahead of when rendering starts.
menu_set_custom_theme();
drupal_theme_initialize();
module_invoke_all('init');
// Tell Drupal it is now fully bootstrapped (for the benefit of code that
// calls drupal_get_bootstrap_phase()), but without having
......
<?php
/**
* @file
* Contains \Drupal\Core\EventSubscriber\SlaveDatabaseIgnoreSubscriber.
*/
namespace Drupal\Core\EventSubscriber;
use Drupal\Core\Database\Database;
use Symfony\Component\HttpKernel\KernelEvents;
use Symfony\Component\HttpKernel\Event\GetResponseEvent;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
/**
* System subscriber for controller requests.
*/
class SlaveDatabaseIgnoreSubscriber implements EventSubscriberInterface {
/**
* Checks and disables the slave database server if appropriate.
*
* @param \Symfony\Component\HttpKernel\Event\GetResponseEvent $event
* The Event to process.
*/
public function checkSlaveServer(GetResponseEvent $event) {
// Ignore slave database servers for this request.
//
// In Drupal's distributed database structure, new data is written to the
// master and then propagated to the slave servers. This means there is a
// lag between when data is written to the master and when it is available
// on the slave. At these times, we will want to avoid using a slave server
// temporarily. For example, if a user posts a new node then we want to
// disable the slave server for that user temporarily to allow the slave
// server to catch up.
// That way, that user will see their changes immediately while for other
// users we still get the benefits of having a slave server, just with
// slightly stale data. Code that wants to disable the slave server should
// use the db_set_ignore_slave() function to set
// $_SESSION['ignore_slave_server'] to the timestamp after which the slave
// can be re-enabled.
if (isset($_SESSION['ignore_slave_server'])) {
if ($_SESSION['ignore_slave_server'] >= REQUEST_TIME) {
Database::ignoreTarget('default', 'slave');
}
else {
unset($_SESSION['ignore_slave_server']);
}
}
}
/**
* {@inheritdoc}
*/
static function getSubscribedEvents() {
$events[KernelEvents::REQUEST][] = array('checkSlaveServer');
return $events;
}
}
......@@ -20,9 +20,12 @@ function action_loop_test_watchdog(array $log_entry) {
}
/**
* Implements hook_init().
* Implements hook_custom_theme().
*
* We need to check wheter a loop should be triggered and we do this as early
* possible, in the first hook that fires.
*/
function action_loop_test_init() {
function action_loop_test_custom_theme() {
if (!empty($_GET['trigger_action_on_watchdog'])) {
watchdog_skip_semaphore('action_loop_test', 'Triggering action loop');
}
......
......@@ -11,9 +11,9 @@
use Drupal\Core\Language\Language;
/**
* Implements hook_init().
* Implements hook_page_build().
*/
function language_test_init() {
function language_test_page_build() {
language_test_store_language_negotiation();
if (isset(language(Language::TYPE_INTERFACE)->langcode) && isset(language(Language::TYPE_INTERFACE)->method_id)) {
drupal_set_message(t('Language negotiation method: @name', array('@name' => language(Language::TYPE_INTERFACE)->method_id)));
......
......@@ -2,13 +2,17 @@
/**
* @file
* Contains Drupal\overlay\EventSubscriber\OverlaySubscriber.
* Contains \Drupal\overlay\EventSubscriber\OverlaySubscriber.
*/
namespace Drupal\overlay\EventSubscriber;
use Drupal\Core\ContentNegotiation;
use Drupal\user\UserData;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpKernel\Event\FilterResponseEvent;
use Symfony\Component\HttpKernel\Event\GetResponseEvent;
use Symfony\Component\HttpKernel\KernelEvents;
/**
......@@ -16,6 +20,93 @@
*/
class OverlaySubscriber implements EventSubscriberInterface {
/**
* The content negotiation service.
*
* @var \Drupal\Core\ContentNegotiation
*/
protected $negotiation;
/**
* The user.data service.
*
* @var \Drupal\user\UserData
*/
protected $userData;
/**
* Constructs an OverlaySubscriber object.
*
* @param \Drupal\Core\ContentNegotiation $negotiation
* The content negotiation service.
* @param \Drupal\user\UserData $user_data
* The user.data service.
*/
public function __construct(ContentNegotiation $negotiation, UserData $user_data) {
$this->negotiation = $negotiation;
$this->userData = $user_data;
}
/**
* Performs check on the beginning of a request.
*
* Determine whether the current page request is destined to appear in the
* parent window or in the overlay window, and format the page accordingly.
*
* @see overlay_set_mode()
*/
public function onRequest(GetResponseEvent $event) {
$request = $event->getRequest();
if ($this->negotiation->getContentType($request) != 'html') {
// Only act on html pages.
return;
}
global $user;
$mode = overlay_get_mode();
// Only act if the user has access to the overlay and a mode was not already
// set. Other modules can also enable the overlay directly for other uses.
$user_data = $this->userData->get('overlay', $user->uid, 'enabled');
$use_overlay = !isset($user_data) || $user_data;
if (empty($mode) && user_access('access overlay') && $use_overlay) {
$current_path = $request->attributes->get('system_path');
// After overlay is enabled on the modules page, redirect to
// <front>#overlay=admin/modules to actually enable the overlay.
if (isset($_SESSION['overlay_enable_redirect']) && $_SESSION['overlay_enable_redirect']) {
unset($_SESSION['overlay_enable_redirect']);
$response = new RedirectResponse(url('<front>', array('fragment' => 'overlay=' . $current_path, 'absolute' => TRUE)));
$event->setResponse($response);
}
if ($request->query->get('render') == 'overlay') {
// If a previous page requested that we close the overlay, close it and
// redirect to the final destination.
if (isset($_SESSION['overlay_close_dialog'])) {
call_user_func_array('overlay_close_dialog', $_SESSION['overlay_close_dialog']);
unset($_SESSION['overlay_close_dialog']);
}
// If this page shouldn't be rendered inside the overlay, redirect to
// the parent.
elseif (!path_is_admin($current_path)) {
overlay_close_dialog($current_path, array('query' => drupal_get_query_parameters(NULL, array('render'))));
}
// Indicate that we are viewing an overlay child page.
overlay_set_mode('child');
// Unset the render parameter to avoid it being included in URLs on the
// page.
$request->query->remove('render');
}
// Do not enable the overlay if we already are on an admin page.
elseif (!path_is_admin($current_path)) {
// Otherwise add overlay parent code and our behavior.
overlay_set_mode('parent');
}
}
}
/**
* Performs end of request tasks.
*
......@@ -48,6 +139,7 @@ public function onResponse(FilterResponseEvent $event) {
* {@inheritdoc}
*/
static function getSubscribedEvents() {
$events[KernelEvents::REQUEST][] = array('onRequest');
$events[KernelEvents::RESPONSE][] = array('onResponse');
return $events;
......
......@@ -125,59 +125,6 @@ function overlay_user_update($account) {
}
}
/**
* Implements hook_init().
*
* Determine whether the current page request is destined to appear in the
* parent window or in the overlay window, and format the page accordingly.
*
* @see overlay_set_mode()
*/
function overlay_init() {
global $user;
$mode = overlay_get_mode();
// Only act if the user has access to the overlay and a mode was not already
// set. Other modules can also enable the overlay directly for other uses.
$user_data = drupal_container()->get('user.data')->get('overlay', $user->uid, 'enabled');
$use_overlay = !isset($user_data) || $user_data;
if (empty($mode) && user_access('access overlay') && $use_overlay) {
$current_path = current_path();
// After overlay is enabled on the modules page, redirect to
// <front>#overlay=admin/modules to actually enable the overlay.
if (isset($_SESSION['overlay_enable_redirect']) && $_SESSION['overlay_enable_redirect']) {
unset($_SESSION['overlay_enable_redirect']);
drupal_goto('<front>', array('fragment' => 'overlay=' . $current_path));
}
if (isset($_GET['render']) && $_GET['render'] == 'overlay') {
// If a previous page requested that we close the overlay, close it and
// redirect to the final destination.
if (isset($_SESSION['overlay_close_dialog'])) {
call_user_func_array('overlay_close_dialog', $_SESSION['overlay_close_dialog']);
unset($_SESSION['overlay_close_dialog']);
}
// If this page shouldn't be rendered inside the overlay, redirect to the
// parent.
elseif (!path_is_admin($current_path)) {
overlay_close_dialog($current_path, array('query' => drupal_get_query_parameters(NULL, array('render'))));
}
// Indicate that we are viewing an overlay child page.
overlay_set_mode('child');
// Unset the render parameter to avoid it being included in URLs on the page.
unset($_GET['render']);
}
// Do not enable the overlay if we already are on an admin page.
elseif (!path_is_admin($current_path)) {
// Otherwise add overlay parent code and our behavior.
overlay_set_mode('parent');
}
}
}
/**
* Implements hook_library_info().
*/
......@@ -602,10 +549,10 @@ function overlay_get_mode() {
* - 'none': This is used to avoid adding any overlay-related code to the
* page at all. Modules can set this to explicitly prevent the overlay from
* being used. For example, since the overlay module itself sets the mode
* to 'parent' or 'child' in overlay_init() when certain conditions are
* met, other modules which want to override that behavior can do so by
* setting the mode to 'none' earlier in the page request - e.g., in their
* own hook_init() implementations, if they have a lower weight.
* to 'parent' or 'child' in the overlay event subscriber when certain
* conditions are met, other modules which want to override that behavior
* can do so by setting the mode to 'none' earlier in the page request -
* e.g., in their own event subscribers, if they have a higher priority.
* This parameter is optional, and if omitted, the current mode will be
* returned with no action taken.
*
......@@ -613,7 +560,7 @@ function overlay_get_mode() {
* The current mode, if any has been set, or NULL if no mode has been set.
*
* @ingroup overlay_api
* @see overlay_init()
* @see \Drupal\overlay\EventSubscriber\OverlaySubscriber::onRequest()
*/
function overlay_set_mode($mode = NULL) {
global $base_path;
......
......@@ -3,3 +3,4 @@ services:
class: Drupal\overlay\EventSubscriber\OverlaySubscriber
tags:
- { name: event_subscriber }
arguments: ['@content_negotiation', '@user.data']
<?php
/**
* Definition of Drupal\system\Tests\System\SystemInitTest.
* Contains \Drupal\system\Tests\System\IgnoreSlaveSubscriberTest.
*/
namespace Drupal\system\Tests\System;
use Drupal\Core\Database\Database;
use \Drupal\simpletest\UnitTestBase;
use \Symfony\Component\HttpFoundation\Request;
use Drupal\Core\EventSubscriber\SlaveDatabaseIgnoreSubscriber;
use Drupal\Core\DrupalKernel;
use Drupal\simpletest\UnitTestBase;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpKernel\HttpKernelInterface;
use Symfony\Component\HttpKernel\Event\GetResponseEvent;
/**
* Tests system_init().
* Tests the event subscriber that disables the slave database.
*/
class SystemInitTest extends UnitTestBase {
class IgnoreSlaveSubscriberTest extends UnitTestBase {
public static function getInfo() {
return array(
'name' => 'System Init',
'description' => 'Tests the system_init function in system.module.',
'name' => 'Slave database ignoring event listener',
'description' => 'Tests that SlaveDatabaseIgnoreSubscriber functions correctly.',
'group' => 'System',
);
}
/**
* Tests that system_init properly ignores slaves when requested.
* Tests \Drupal\Core\EventSubscriber\SlaveDatabaseIgnoreSubscriber::checkSlaveServer().
*/
function testSystemInitIgnoresSlaves() {
// Clone the master credentials to a slave connection.
......@@ -34,7 +38,10 @@ function testSystemInitIgnoresSlaves() {
Database::addConnectionInfo('default', 'slave', $connection_info['default']);
db_ignore_slave();
system_init();
$kernel = new DrupalKernel('testing', FALSE, drupal_classloader(), FALSE);
$event = new GetResponseEvent($kernel, Request::create('http://example.com'), HttpKernelInterface::MASTER_REQUEST);
$subscriber = new SlaveDatabaseIgnoreSubscriber();
$subscriber->checkSlaveServer($event);
$db1 = Database::getConnection('default', 'default');
$db2 = Database::getConnection('slave', 'default');
......
......@@ -2,7 +2,7 @@
/**
* @file
* Definition of Drupal\system\Tests\Theme\HookInitTest.
* Definition of Drupal\system\Tests\Theme\ThemeEarlyInitializationTest.
*/
namespace Drupal\system\Tests\Theme;
......@@ -10,9 +10,9 @@
use Drupal\simpletest\WebTestBase;
/**
* Functional test for initialization of the theme system in hook_init().
* Functional test for initialization of the theme system early in the request.
*/
class HookInitTest extends WebTestBase {
class ThemeEarlyInitializationTest extends WebTestBase {
/**
* Modules to enable.
......@@ -23,21 +23,21 @@ class HookInitTest extends WebTestBase {
public static function getInfo() {
return array(
'name' => 'Theme initialization in hook_init()',
'description' => 'Tests that the theme system can be correctly initialized in hook_init().',
'name' => 'Early theme initialization',
'description' => 'Tests that the theme system can be correctly initialized early in the page request.',
'group' => 'Theme',
);
}
/**
* Test that the theme system can generate output when called by hook_init().
* Test that the theme system can generate output in a request listener.
*/
function testThemeInitializationHookInit() {
$this->drupalGet('theme-test/hook-init');
// Verify that themed output generated in hook_init() appears.
$this->assertRaw('Themed output generated in hook_init()');
// Verify that the default theme's CSS still appears when the theme system
// is initialized in hook_init().
function testRequestListener() {
$this->drupalGet('theme-test/request-listener');
// Verify that themed output generated in the request listener appears.
$this->assertRaw('Themed output generated in a KernelEvents::REQUEST listener');
// Verify that the default theme's CSS still appears even though the theme
// system was initialized early.
$this->assertRaw('stark/css/layout.css');
}
}
......@@ -1347,23 +1347,6 @@ function hook_forms($form_id, $args) {
return $forms;
}
/**
* Perform setup tasks for non-cached page requests.
*
* This hook is run at the beginning of the page request. It is typically
* used to set up global parameters that are needed later in the request.
* When this hook is called, the theme and all modules are already loaded in
* memory.
*
* This hook is not run on cached pages.
*
* Do not use this hook to add CSS/JS to pages, use hook_page_build() instead.
*
* @see hook_page_build()
*/
function hook_init() {
}
/**
* Alter an email message created with the drupal_mail() function.
*
......
......@@ -8,7 +8,6 @@
use Drupal\Core\Cache\CacheBackendInterface;
use Drupal\Core\Cache\Cache;
use Drupal\Core\Language\Language;
use Drupal\Core\Database\Database;
use Drupal\Core\Utility\ModuleInfo;
use Drupal\Core\TypedData\Primitive;
use Drupal\system\Plugin\Block\SystemMenuBlock;
......@@ -2503,34 +2502,6 @@ function system_filetransfer_info() {
return $backends;
}
/**
* Implements hook_init().
*/
function system_init() {
// Ignore slave database servers for this request.
//
// In Drupal's distributed database structure, new data is written to the
// master and then propagated to the slave servers. This means there is a
// lag between when data is written to the master and when it is available on
// the slave. At these times, we will want to avoid using a slave server
// temporarily. For example, if a user posts a new node then we want to
// disable the slave server for that user temporarily to allow the slave
// server to catch up. That way, that user will see their changes immediately
// while for other users we still get the benefits of having a slave server,
// just with slightly stale data. Code that wants to disable the slave
// server should use the db_ignore_slave() function to set
// $_SESSION['ignore_slave_server'] to the timestamp after which the slave
// can be re-enabled.
if (isset($_SESSION['ignore_slave_server'])) {
if ($_SESSION['ignore_slave_server'] >= REQUEST_TIME) {
Database::ignoreTarget('default', 'slave');
}
else {
unset($_SESSION['ignore_slave_server']);
}
}
}
/**
* Implements hook_page_build().
*/
......
......@@ -531,18 +531,6 @@ function menu_test_menu_trail_callback() {
return 'This is menu_test_menu_trail_callback().';
}
/**
* Implements hook_init().
*/
function menu_test_init() {
// When requested by one of the MenuTrailTestCase tests, record the initial
// active trail during Drupal's bootstrap (before the user is redirected to a
// custom 403 or 404 page). See menu_test_custom_403_404_callback().
if (state()->get('menu_test.record_active_trail') ?: FALSE) {
state()->set('menu_test.active_trail_initial', menu_get_active_trail());
}
}
/**
* Callback for our custom 403 and 404 pages.
*/
......@@ -614,6 +602,12 @@ function menu_test_theme_callback($argument) {
* The name of the custom theme to use for the current page.
*/
function menu_test_custom_theme() {
// When requested by one of the MenuTrailTestCase tests, record the initial
// active trail during Drupal's bootstrap (before the user is redirected to a
// custom 403 or 404 page). See menu_test_custom_403_404_callback().
if (state()->get('menu_test.record_active_trail') ?: FALSE) {
state()->set('menu_test.active_trail_initial', menu_get_active_trail());
}
// If an appropriate variable has been set in the database, request the theme
// that is stored there. Otherwise, do not attempt to dynamically set the
// theme.
......
......@@ -128,17 +128,6 @@ function system_test_modules_uninstalled($modules) {
}
}
/**
* Implements hook_init().
*/
function system_test_init() {
// Used by FrontPageTestCase to get the results of drupal_is_front_page().
$frontpage = state()->get('system_test.front_page_output') ?: 0;
if ($frontpage && drupal_is_front_page()) {
drupal_set_message(t('On front page.'));
}
}
/**
* Implements hook_system_info_alter().
*/
......@@ -220,6 +209,11 @@ function system_test_page_build(&$page) {
elseif ($menu_item['path'] == 'system-test/main-content-duplication') {
drupal_set_page_content();
}
// Used by FrontPageTestCase to get the results of drupal_is_front_page().
$frontpage = state()->get('system_test.front_page_output') ?: 0;
if ($frontpage && drupal_is_front_page()) {
drupal_set_message(t('On front page.'));
}
}
/**
......
<?php
/**
* @file
* Contains \Drupal\theme_test\EventSubscriber\ThemeTestSubscriber.
*/
namespace Drupal\theme_test\EventSubscriber;
use Symfony\Component\HttpKernel\KernelEvents;
use Symfony\Component\HttpKernel\Event\GetResponseEvent;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
/**
* Theme test subscriber for controller requests.
*/
class ThemeTestSubscriber implements EventSubscriberInterface {
/**
* Generates themed output early in a page request.
*
* @see \Drupal\system\Tests\Theme\ThemeEarlyInitializationTest::testRequestListener()
*/
public function onRequest(GetResponseEvent $event) {
$request = $event->getRequest();
$current_path = $request->attributes->get('system_path');
if ($current_path == 'theme-test/request-listener') {
// First, force the theme registry to be rebuilt on this page request.
// This allows us to test a full initialization of the theme system in
// the code below.
drupal_theme_rebuild();
// Next, initialize the theme system by storing themed text in a global
// variable. We will use this later in
// theme_test_request_listener_page_callback() to test that even when the
// theme system is initialized this early, it is still capable of
// returning output and theming the page as a whole.
$GLOBALS['theme_test_output'] = theme('more_link', array('url' => 'user', 'title' => 'Themed output generated in a KernelEvents::REQUEST listener'));
}
if (strpos($current_path, 'user/autocomplete') === 0) {
// Register a fake registry loading callback. If it gets called by
// theme_get_registry(), the registry has not been initialized yet.
_theme_registry_callback('_theme_test_load_registry', array());
}
}
/**
* {@inheritdoc}
*/
static function getSubscribedEvents() {
$events[KernelEvents::REQUEST][] = array('onRequest');
return $events;
}
}
......@@ -52,8 +52,8 @@ function theme_test_menu() {
'theme callback' => '_theme_custom_theme',
'type' => MENU_CALLBACK,
);
$items['theme-test/hook-init'] = array(
'page callback' => 'theme_test_hook_init_page_callback',
$items['theme-test/request-listener'] = array(
'page callback' => 'theme_test_request_listener_page_callback',
'access callback' => TRUE,