Skip to content
Commits on Source (15)
......@@ -165,21 +165,6 @@ services:
calls:
- [addSubscriber, ['@http_client_simpletest_subscriber']]
- [setUserAgent, ['Drupal (+http://drupal.org/)']]
theme.negotiator:
class: Drupal\Core\Theme\ThemeNegotiator
arguments: ['@access_check.theme']
calls:
- [setRequest, ['@request']]
theme.negotiator.default:
class: Drupal\Core\Theme\DefaultNegotiator
arguments: ['@config.factory']
tags:
- { name: theme_negotiator, priority: -100 }
theme.negotiator.ajax_base_page:
class: Drupal\Core\Theme\AjaxBasePageNegotiator
arguments: ['@csrf_token', '@config.factory']
tags:
- { name: theme_negotiator, priority: 1000 }
container.namespaces:
class: ArrayObject
arguments: [ '%container.namespaces%' ]
......@@ -211,17 +196,12 @@ services:
plugin.manager.menu.local_task:
class: Drupal\Core\Menu\LocalTaskManager
arguments: ['@controller_resolver', '@request', '@router.route_provider', '@module_handler', '@cache.cache', '@language_manager', '@access_manager', '@current_user']
scope: request
plugin.manager.menu.contextual_link:
class: Drupal\Core\Menu\ContextualLinkManager
arguments: ['@controller_resolver', '@module_handler', '@cache.cache', '@language_manager', '@access_manager', '@current_user']
request:
class: Symfony\Component\HttpFoundation\Request
# @TODO the synthetic setting must be uncommented whenever drupal_session_initialize()
# is run after there is a request and the following two lines should be removed.
factory_class: Symfony\Component\HttpFoundation\Request
factory_method: createFromGlobals
#synthetic: true
synthetic: true
event_dispatcher:
class: Symfony\Component\EventDispatcher\ContainerAwareEventDispatcher
arguments: ['@service_container']
......@@ -365,6 +345,10 @@ services:
tags:
- { name: event_subscriber }
arguments: ['@settings']
ajax_response_subscriber:
class: Drupal\Core\EventSubscriber\AjaxResponseSubscriber
tags:
- { name: event_subscriber }
route_enhancer.authentication:
class: Drupal\Core\Routing\Enhancer\AuthenticationEnhancer
calls:
......@@ -436,7 +420,6 @@ services:
- [setCurrentUser, ['@?current_user']]
tags:
- { name: event_subscriber }
scope: request
access_route_subscriber:
class: Drupal\Core\EventSubscriber\AccessRouteSubscriber
tags:
......
......@@ -302,6 +302,42 @@ function ajax_render($commands = array()) {
return drupal_json_encode($commands);
}
/**
* Theme callback: Returns the correct theme for an Ajax request.
*
* Many different pages can invoke an Ajax request to system/ajax or another
* generic Ajax path. It is almost always desired for an Ajax response to be
* rendered using the same theme as the base page, because most themes are built
* with the assumption that they control the entire page, so if the CSS for two
* themes are both loaded for a given page, they may conflict with each other.
* For example, Bartik is Drupal's default theme, and Seven is Drupal's default
* administration theme. Depending on whether the "Use the administration theme
* when editing or creating content" checkbox is checked, the node edit form may
* be displayed in either theme, but the Ajax response to the Field module's
* "Add another item" button should be rendered using the same theme as the rest
* of the page. Therefore, system_menu() sets the 'theme callback' for
* 'system/ajax' to this function, and it is recommended that modules
* implementing other generic Ajax paths do the same.
*
* @see system_menu()
* @see file_menu()
*/
function ajax_base_page_theme() {
if (!empty($_POST['ajax_page_state']['theme']) && !empty($_POST['ajax_page_state']['theme_token'])) {
$theme = $_POST['ajax_page_state']['theme'];
$token = $_POST['ajax_page_state']['theme_token'];
// Prevent a request forgery from giving a person access to a theme they
// shouldn't be otherwise allowed to see. However, since everyone is allowed
// to see the default theme, token validation isn't required for that, and
// bypassing it allows most use-cases to work even when accessed from the
// page cache.
if ($theme === \Drupal::config('system.theme')->get('default') || drupal_valid_token($token, $theme)) {
return $theme;
}
}
}
/**
* Converts the return value of a page callback into an Ajax commands array.
*
......
......@@ -1552,7 +1552,7 @@ function watchdog($type, $message, array $variables = NULL, $severity = WATCHDOG
$log_entry['referer'] = $request->headers->get('Referer', '');
$log_entry['ip'] = $request->getClientIP();
}
catch (\InvalidArgumentException $e) {
catch (DependencyInjectionRuntimeException $e) {
// We are not in a request context.
}
......@@ -1718,9 +1718,18 @@ function drupal_set_title($title = NULL, $output = Title::CHECK_PLAIN) {
* The user session object.
*/
function drupal_anonymous_user() {
try {
$request = \Drupal::request();
$hostname = $request->getClientIP();
}
catch (DependencyInjectionRuntimeException $e) {
// We are not in a request context.
$hostname = '';
}
$values = array(
'uid' => 0,
'hostname' => \Drupal::request()->getClientIP(),
'hostname' => $hostname,
'roles' => array(DRUPAL_ANONYMOUS_RID),
);
return new UserSession($values);
......@@ -1861,10 +1870,13 @@ function drupal_handle_request($test_only = FALSE) {
// @todo Remove this once everything in the bootstrap has been
// converted to services in the DIC.
$kernel->boot();
drupal_bootstrap(DRUPAL_BOOTSTRAP_CODE);
// Create a request object from the HttpFoundation.
$request = Request::createFromGlobals();
\Drupal::getContainer()->set('request', $request);
drupal_bootstrap(DRUPAL_BOOTSTRAP_CODE);
$response = $kernel->handle($request)->prepare($request)->send();
$kernel->terminate($request, $response);
......@@ -1994,6 +2006,8 @@ function _drupal_bootstrap_kernel() {
if (!\Drupal::getContainer()) {
$kernel = new DrupalKernel('prod', drupal_classloader());
$kernel->boot();
$request = Request::createFromGlobals();
\Drupal::getContainer()->set('request', $request);
}
}
......
......@@ -399,14 +399,15 @@ function drupal_add_feed($url = NULL, $title = '') {
if (isset($url)) {
$stored_feed_links[$url] = theme('feed_icon', array('url' => $url, 'title' => $title));
drupal_add_html_head_link(array(
$build['#attached']['drupal_add_html_head_link'][][] = array(
'rel' => 'alternate',
'type' => 'application/rss+xml',
'title' => $title,
// Force the URL to be absolute, for consistency with other <link> tags
// output by Drupal.
'href' => url($url, array('absolute' => TRUE)),
));
);
drupal_render($build);
}
return $stored_feed_links;
}
......@@ -2330,7 +2331,7 @@ function drupal_get_js($scope = 'header', $javascript = NULL, $skip_alter = FALS
global $theme_key;
// Provide the page with information about the theme that's used, so that
// a later AJAX request can be rendered using the same theme.
// @see \Drupal\Core\Theme\AjaxBasePageNegotiator
// @see ajax_base_page_theme()
$setting['ajaxPageState']['theme'] = $theme_key;
// Checks that the DB is available before filling theme_token.
if (!defined('MAINTENANCE_MODE')) {
......@@ -3147,6 +3148,7 @@ 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') {
menu_set_custom_theme();
drupal_theme_initialize();
}
}
......
......@@ -625,10 +625,19 @@ function drupal_install_system() {
// Create tables.
drupal_install_schema('system');
if (!drupal_container()->has('kernel')) {
// Immediately boot a kernel to have real services ready.
if (!\Drupal::getContainer()->has('kernel')) {
// Immediately boot a kernel to have real services ready. If there's already
// an initialized request object in the pre-kernel container, persist it in
// the post-kernel container.
if (\Drupal::getContainer()->initialized('request')) {
$request = \Drupal::request();
}
$kernel = new DrupalKernel('install', drupal_classloader(), FALSE);
$kernel->boot();
if (isset($request)) {
\Drupal::getContainer()->set('request', $request);
}
}
$system_path = drupal_get_path('module', 'system');
......
......@@ -463,8 +463,8 @@ function menu_set_item($path, $router_item) {
* menu_router table. The value corresponding to the key 'map' holds the
* loaded objects. The value corresponding to the key 'access' is TRUE if the
* current user can access this page. The values corresponding to the keys
* 'title', 'page_arguments', and 'access_arguments', will be filled in based
* on the database values and the objects loaded.
* 'title', 'page_arguments', 'access_arguments', and 'theme_arguments' will
* be filled in based on the database values and the objects loaded.
*/
function menu_get_item($path = NULL, $router_item = NULL) {
$router_items = &drupal_static(__FUNCTION__);
......@@ -501,6 +501,7 @@ function menu_get_item($path = NULL, $router_item = NULL) {
if ($router_item['access']) {
$router_item['map'] = $map;
$router_item['page_arguments'] = array_merge(menu_unserialize($router_item['page_arguments'], $map), array_slice($map, $router_item['number_parts']));
$router_item['theme_arguments'] = array_merge(menu_unserialize($router_item['theme_arguments'], $map), array_slice($map, $router_item['number_parts']));
}
}
$router_items[$path] = $router_item;
......@@ -1794,6 +1795,51 @@ function drupal_help_arg($arg = array()) {
return $arg + array('', '', '', '', '', '', '', '', '', '', '', '');
}
/**
* Gets the custom theme for the current page, if there is one.
*
* @param $initialize
* This parameter should only be used internally; it is set to TRUE in order
* to force the custom theme to be initialized for the current page request.
*
* @return
* The machine-readable name of the custom theme, if there is one.
*
* @see menu_set_custom_theme()
*/
function menu_get_custom_theme($initialize = FALSE) {
$custom_theme = &drupal_static(__FUNCTION__);
// Skip this if the site is offline or being installed or updated, since the
// menu system may not be correctly initialized then.
if ($initialize && !_menu_site_is_offline(TRUE) && (!defined('MAINTENANCE_MODE') || (MAINTENANCE_MODE != 'update' && MAINTENANCE_MODE != 'install'))) {
// First allow modules to dynamically set a custom theme for the current
// page. Since we can only have one, the last module to return a valid
// theme takes precedence.
$custom_themes = array_filter(\Drupal::moduleHandler()->invokeAll('custom_theme'), 'drupal_theme_access');
if (!empty($custom_themes)) {
$custom_theme = array_pop($custom_themes);
}
// If there is a theme callback function for the current page, execute it.
// If this returns a valid theme, it will override any theme that was set
// by a hook_custom_theme() implementation above.
$router_item = menu_get_item();
if (!empty($router_item['access']) && !empty($router_item['theme_callback'])) {
$theme_name = call_user_func_array($router_item['theme_callback'], $router_item['theme_arguments']);
if (drupal_theme_access($theme_name)) {
$custom_theme = $theme_name;
}
}
}
return $custom_theme;
}
/**
* Sets a custom theme for the current page, if there is one.
*/
function menu_set_custom_theme() {
menu_get_custom_theme(TRUE);
}
/**
* Returns an array containing the names of system-defined (default) menus.
*/
......@@ -3020,6 +3066,13 @@ function _menu_router_build($callbacks, $save = FALSE) {
}
}
}
// Same for theme callbacks.
if (!isset($item['theme callback']) && isset($parent['theme callback'])) {
$item['theme callback'] = $parent['theme callback'];
if (!isset($item['theme arguments']) && isset($parent['theme arguments'])) {
$item['theme arguments'] = $parent['theme arguments'];
}
}
// Same for load arguments: if a loader doesn't have any explict
// arguments, try to find arguments in the parent.
if (!isset($item['load arguments'])) {
......@@ -3056,6 +3109,8 @@ function _menu_router_build($callbacks, $save = FALSE) {
'page callback' => '',
'title arguments' => array(),
'title callback' => 't',
'theme arguments' => array(),
'theme callback' => '',
'description' => '',
'description arguments' => array(),
'description callback' => 't',
......@@ -3120,6 +3175,8 @@ function _menu_router_save($menu, $masks) {
'title',
'title_callback',
'title_arguments',
'theme_callback',
'theme_arguments',
'type',
'description',
'description_callback',
......@@ -3150,6 +3207,8 @@ function _menu_router_save($menu, $masks) {
'title' => $item['title'],
'title_callback' => $item['title callback'],
'title_arguments' => ($item['title arguments'] ? serialize($item['title arguments']) : ''),
'theme_callback' => $item['theme callback'],
'theme_arguments' => serialize($item['theme arguments']),
'type' => $item['type'],
'description' => $item['description'],
'description_callback' => $item['description callback'],
......
......@@ -92,14 +92,16 @@ function drupal_theme_initialize() {
}
drupal_bootstrap(DRUPAL_BOOTSTRAP_DATABASE);
$themes = list_themes();
// @todo Let the theme.negotiator listen to the kernel request event.
// Determine the active theme for the theme negotiator service. This includes
// the default theme as well as really specific ones like the ajax base theme.
$request = \Drupal::request();
$theme = \Drupal::service('theme.negotiator')->determineActiveTheme($request) ?: 'stark';
// Only select the user selected theme if it is available in the
// list of themes that can be accessed.
$theme = !empty($user->theme) && drupal_theme_access($user->theme) ? $user->theme : \Drupal::config('system.theme')->get('default');
// Allow modules to override the theme. Validation has already been performed
// inside menu_get_custom_theme(), so we do not need to check it again here.
$custom_theme = menu_get_custom_theme();
$theme = !empty($custom_theme) ? $custom_theme : $theme;
// Store the identifier for retrieving theme settings with.
$theme_key = $theme;
......@@ -112,6 +114,9 @@ function drupal_theme_initialize() {
$base_theme[] = $themes[$ancestor];
}
_drupal_theme_initialize($themes[$theme], array_reverse($base_theme));
// Themes can have alter functions, so reset the drupal_alter() cache.
drupal_static_reset('drupal_alter');
}
/**
......@@ -363,17 +368,11 @@ function list_themes($refresh = FALSE) {
$list = array();
// Extract from the database only when it is available.
// Also check that the site is not in the middle of an install or update.
if (!defined('MAINTENANCE_MODE')) {
try {
$themes = system_list('theme');
}
catch (Exception $e) {
// If the database is not available, rebuild the theme data.
$themes = _system_rebuild_theme_data();
}
try {
$themes = system_list('theme');
}
else {
// Scan the installation when the database should not be read.
catch (Exception $e) {
// If the database is not available, rebuild the theme data.
$themes = _system_rebuild_theme_data();
}
......@@ -1274,8 +1273,14 @@ function template_preprocess_status_messages(&$variables) {
* is used as its CSS class. Each link should be itself an array, with the
* following elements:
* - title: The link text.
* - href: The link URL. If omitted, the 'title' is shown as a plain text
* item in the links list.
* - route_name: (optional) The name of the route to link to. If omitted
* (and if 'href' is omitted as well), the 'title' is shown as
* a plain text item in the links list.
* - route_parameters: (optional) An array of route parameters for the link.
* - href: (optional) The link URL. It is preferred to use 'route_name' and
* 'route parameters' for internal links. Use 'href' for links to external
* URLs. If omitted (and if 'route_name' is omitted as well), the 'title'
* is shown as a plain text item in the links list.
* - html: (optional) Whether or not 'title' is HTML. If set, the title
* will not be passed through
* \Drupal\Component\Utility\String::checkPlain().
......@@ -2221,7 +2226,12 @@ function template_preprocess_html(&$variables) {
if (theme_get_setting('features.favicon')) {
$favicon = theme_get_setting('favicon.url');
$type = theme_get_setting('favicon.mimetype');
drupal_add_html_head_link(array('rel' => 'shortcut icon', 'href' => Url::stripDangerousProtocols($favicon), 'type' => $type));
$build['#attached']['drupal_add_html_head_link'][][] = array(
'rel' => 'shortcut icon',
'href' => Url::stripDangerousProtocols($favicon),
'type' => $type,
);
drupal_render($build);
}
$site_config = \Drupal::config('system.site');
......@@ -2504,7 +2514,12 @@ function template_preprocess_maintenance_page(&$variables) {
if (theme_get_setting('features.favicon')) {
$favicon = theme_get_setting('favicon.url');
$type = theme_get_setting('favicon.mimetype');
drupal_add_html_head_link(array('rel' => 'shortcut icon', 'href' => Url::stripDangerousProtocols($favicon), 'type' => $type));
$build['#attached']['drupal_add_html_head_link'][][] = array(
'rel' => 'shortcut icon',
'href' => Url::stripDangerousProtocols($favicon),
'type' => $type,
);
drupal_render($build);
}
// Get all region content set with drupal_add_region_content().
......
......@@ -9,9 +9,6 @@
/**
* Defines an object which stores multiple plugin instances to lazy load them.
*
* The \ArrayAccess implementation is only for backwards compatibility, it is
* deprecated and should not be used by new code.
*/
abstract class PluginBag implements \Iterator, \Countable {
......@@ -30,7 +27,7 @@ abstract class PluginBag implements \Iterator, \Countable {
protected $instanceIDs = array();
/**
* Initializes a plugin and stores the result in $this->pluginInstances.
* Initializes and stores a plugin.
*
* @param string $instance_id
* The ID of the plugin instance to initialize.
......@@ -85,7 +82,7 @@ public function set($instance_id, $value) {
/**
* Removes an initialized plugin.
*
* The plugin can still be used, it will be reinitialized.
* The plugin can still be used; it will be reinitialized.
*
* @param string $instance_id
* The ID of the plugin instance to remove.
......@@ -95,7 +92,7 @@ public function remove($instance_id) {
}
/**
* Adds an instance ID to the array of available instance IDs.
* Adds an instance ID to the available instance IDs.
*
* @param string $id
* The ID of the plugin instance to add.
......@@ -117,7 +114,7 @@ public function getInstanceIds() {
}
/**
* Sets the instance IDs property.
* Sets all instance IDs.
*
* @param array $instance_ids
* An associative array of instance IDs.
......@@ -138,28 +135,28 @@ public function removeInstanceId($instance_id) {
}
/**
* Implements \Iterator::current().
* {@inheritdoc}
*/
public function current() {
return $this->get($this->key());
}
/**
* Implements \Iterator::next().
* {@inheritdoc}
*/
public function next() {
next($this->instanceIDs);
}
/**
* Implements \Iterator::key().
* {@inheritdoc}
*/
public function key() {
return key($this->instanceIDs);
}
/**
* Implements \Iterator::valid().
* {@inheritdoc}
*/
public function valid() {
$key = key($this->instanceIDs);
......@@ -167,14 +164,14 @@ public function valid() {
}
/**
* Implements \Iterator::rewind().
* {@inheritdoc}
*/
public function rewind() {
reset($this->instanceIDs);
}
/**
* Implements \Countable::count().
* {@inheritdoc}
*/
public function count() {
return count($this->instanceIDs);
......
......@@ -9,6 +9,7 @@
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
/**
* JSON response object for AJAX requests.
......@@ -46,17 +47,25 @@ public function addCommand($command, $prepend = FALSE) {
}
/**
* Sets the response's data to be the array of AJAX commands.
*
* @param Request $request
* A request object.
* {@inheritdoc}
*
* @return Response
* The current response.
* Sets the response's data to be the array of AJAX commands.
*/
public function prepare(Request $request) {
$this->setData($this->ajaxRender($request));
return parent::prepare($request);
$this->prepareResponse($request);
return $this;
}
/**
* Sets the rendered AJAX right before the response is prepared.
*
* @param \Symfony\Component\HttpFoundation\Request $request
* The request object.
*/
public function prepareResponse(Request $request) {
if ($this->data == '{}') {
$this->setData($this->ajaxRender($request));
}
}
/**
......
......@@ -204,14 +204,11 @@ public function listAll($prefix = '') {
throw new StorageException($this->directory . '/ not found.');
}
$extension = '.' . static::getFileExtension();
$files = new \GlobIterator($this->directory . '/' . $prefix . '*' . $extension);
$names = array();
foreach ($files as $file) {
$names[] = $file->getBasename($extension);
}
return $names;
$files = glob($this->directory . '/' . $prefix . '*' . $extension);
$clean_name = function ($value) use ($extension) {
return basename($value, $extension);
};
return array_map($clean_name, $files);
}
/**
......
......@@ -134,9 +134,10 @@ public function getComponentNames($type, array $list) {
foreach ($list as $name) {
$directory = $this->getComponentFolder($type, $name);
if (file_exists($directory)) {
$files = new \GlobIterator($directory . '/*' . $extension);
foreach ($files as $file) {
$folders[$file->getBasename($extension)] = $directory;
$files = glob($directory . '/*' . $extension);
foreach ($files as $filename) {
$name = basename($filename, $extension);
$folders[$name] = $directory;
}
}
}
......
......@@ -23,7 +23,6 @@
use Drupal\Core\DependencyInjection\Compiler\RegisterBreadcrumbBuilderPass;
use Drupal\Core\DependencyInjection\Compiler\RegisterAuthenticationPass;
use Drupal\Core\DependencyInjection\Compiler\RegisterTwigExtensionsPass;
use Drupal\Core\Theme\ThemeNegotiatorPass;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\DependencyInjection\Reference;
use Symfony\Component\DependencyInjection\Definition;
......@@ -72,9 +71,6 @@ public function register(ContainerBuilder $container) {
// Add the compiler pass that will process the tagged breadcrumb builder
// services.
$container->addCompilerPass(new RegisterBreadcrumbBuilderPass());
// Add the compiler pass that will process the tagged theme negotiator
// service.
$container->addCompilerPass(new ThemeNegotiatorPass());
// Add the compiler pass that lets service providers modify existing
// service definitions.
$container->addCompilerPass(new ModifyServiceDefinitionsPass());
......
......@@ -369,10 +369,17 @@ protected function getKernelParameters() {
protected function initializeContainer() {
$this->containerNeedsDumping = FALSE;
$persist = $this->getServicesToPersist();
// If we are rebuilding the kernel and we are in a request scope, store
// request info so we can add them back after the rebuild.
if (isset($this->container) && $this->container->hasScope('request')) {
$request = $this->container->get('request');
// The request service requires custom persisting logic, since it is also
// potentially scoped. During Drupal installation, there is a request
// service without a request scope.
$request_scope = FALSE;
if (isset($this->container)) {
if ($this->container->isScopeActive('request')) {
$request_scope = TRUE;
}
if ($this->container->initialized('request')) {
$request = $this->container->get('request');
}
}
$this->container = NULL;
$class = $this->getClassName();
......@@ -445,8 +452,10 @@ protected function initializeContainer() {
// Set the class loader which was registered as a synthetic service.
$this->container->set('class_loader', $this->classLoader);
// If we have a request set it back to the new container.
if (isset($request)) {
if ($request_scope) {
$this->container->enterScope('request');
}
if (isset($request)) {
$this->container->set('request', $request);
}
\Drupal::setContainer($this->container);
......
......@@ -225,16 +225,11 @@ class EntityType extends Plugin {
public $bundle_keys;
/**
* The base router path for the entity type's field administration page.
*
* If the entity type has a bundle, include {bundle} in the path.
*
* For example, the node entity type specifies
* "admin/structure/types/manage/{bundle}" as its base field admin path.
* The name of the entity type which provides bundles.
*
* @var string (optional)
*/
public $route_base_path;
public $bundle_entity_type = 'bundle';
/**
* Link templates using the URI template syntax.
......
......@@ -301,9 +301,9 @@ public function getAdminPath($entity_type, $bundle) {
$admin_path = '';
$entity_info = $this->getDefinition($entity_type);
// Check for an entity type's admin base path.
if (isset($entity_info['route_base_path'])) {
// Replace any dynamic 'bundle' portion of the path with the actual bundle.
$admin_path = str_replace('{bundle}', $bundle, $entity_info['route_base_path']);
if (isset($entity_info['links']['admin-form'])) {
$route_parameters[$entity_info['bundle_entity_type']] = $bundle;
$admin_path = \Drupal::urlGenerator()->getPathFromRoute($entity_info['links']['admin-form'], $route_parameters);
}
return $admin_path;
......@@ -313,10 +313,11 @@ public function getAdminPath($entity_type, $bundle) {
* {@inheritdoc}
*/
public function getAdminRouteInfo($entity_type, $bundle) {
$entity_info = $this->getDefinition($entity_type);
return array(
'route_name' => "field_ui.overview_$entity_type",
'route_parameters' => array(
'bundle' => $bundle,
$entity_info['bundle_entity_type'] => $bundle,
)
);
}
......
......@@ -164,6 +164,11 @@ public function getViewBuilder($entity_type);
*
* @return string
* The administration path for an entity type bundle, if it exists.
*
* @deprecated since version 8.0
* System paths should not be used - use route names and parameters.
*
* @see self::getAdminRouteInfo()
*/
public function getAdminPath($entity_type, $bundle);
......
<?php
/**
* @file
* Contains \Drupal\Core\EventSubscriber\AjaxResponseSubscriber.
*/
namespace Drupal\Core\EventSubscriber;
use Drupal\Core\Ajax\AjaxResponse;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpKernel\Event\FilterResponseEvent;
use Symfony\Component\HttpKernel\HttpKernelInterface;
use Symfony\Component\HttpKernel\KernelEvents;
class AjaxResponseSubscriber implements EventSubscriberInterface {
/**
* Renders the ajax commands right before preparing the result.
*
* @param \Symfony\Component\HttpKernel\Event\FilterResponseEvent $event
* The response event, which contains the possible AjaxResponse object.
*/
public function onResponse(FilterResponseEvent $event) {
$response = $event->getResponse();
if ($response instanceof AjaxResponse) {
$response->prepareResponse($event->getRequest());
}
}
/**
* {@inheritdoc}
*/
public static function getSubscribedEvents() {
$events[KernelEvents::RESPONSE][] = array('onResponse', -100);
return $events;
}
}
......@@ -27,6 +27,9 @@ class LegacyRequestSubscriber implements EventSubscriberInterface {
*/
public function onKernelRequestLegacy(GetResponseEvent $event) {
if ($event->getRequestType() == HttpKernelInterface::MASTER_REQUEST) {
menu_set_custom_theme();
drupal_theme_initialize();
// Tell Drupal it is now fully bootstrapped (for the benefit of code that
// calls drupal_get_bootstrap_phase()), but without having
// _drupal_bootstrap_full() do anything, since we've already done the
......@@ -36,16 +39,6 @@ public function onKernelRequestLegacy(GetResponseEvent $event) {
}
}
/**
* Initializes the theme system after the routing system.
*
* @param \Symfony\Component\HttpKernel\Event\GetResponseEvent $event
* The Event to process.
*/
public function onKernelRequestLegacyAfterRouting(GetResponseEvent $event) {
drupal_theme_initialize();
}
/**
* Registers the methods in this class that should be listeners.
*
......@@ -54,8 +47,6 @@ public function onKernelRequestLegacyAfterRouting(GetResponseEvent $event) {
*/
static function getSubscribedEvents() {
$events[KernelEvents::REQUEST][] = array('onKernelRequestLegacy', 90);
// Initialize the theme system after the routing system.
$events[KernelEvents::REQUEST][] = array('onKernelRequestLegacyAfterRouting', 30);
return $events;
}
......
<?php
/**
* @file
* Contains \Drupal\Core\Theme\AjaxBasePageNegotiator.
*/
namespace Drupal\Core\Theme;
use Drupal\Core\Access\CsrfTokenGenerator;
use Drupal\Core\Config\ConfigFactory;
use Symfony\Cmf\Component\Routing\RouteObjectInterface;
use Symfony\Component\HttpFoundation\Request;
/**
* Defines a theme negotiator that deals with the active theme on ajax requests.
*
* Many different pages can invoke an Ajax request to system/ajax or another
* generic Ajax path. It is almost always desired for an Ajax response to be
* rendered using the same theme as the base page, because most themes are built
* with the assumption that they control the entire page, so if the CSS for two
* themes are both loaded for a given page, they may conflict with each other.
* For example, Bartik is Drupal's default theme, and Seven is Drupal's default
* administration theme. Depending on whether the "Use the administration theme
* when editing or creating content" checkbox is checked, the node edit form may
* be displayed in either theme, but the Ajax response to the Field module's
* "Add another item" button should be rendered using the same theme as the rest
* of the page.
*
* Therefore specify '_theme: ajax_base_page' as part of the router options.
*/
class AjaxBasePageNegotiator implements ThemeNegotiatorInterface {
/**
* The CSRF token generator.
*
* @var \Drupal\Core\Access\CsrfTokenGenerator
*/
protected $csrfGenerator;
/**
* The config factory.
*
* @var \Drupal\Core\Config\ConfigFactory
*/
protected $configFactory;
/**
* Constructs a new AjaxBasePageNegotiator.
*
* @param \Drupal\Core\Access\CsrfTokenGenerator $token_generator
* The CSRF token generator.
* @param \Drupal\Core\Config\ConfigFactory $config_factory
* The config factory.
*/
public function __construct(CsrfTokenGenerator $token_generator, ConfigFactory $config_factory) {
$this->csrfGenerator = $token_generator;
$this->configFactory = $config_factory;
}
/**
* {@inheritdoc}
*/
public function determineActiveTheme(Request $request) {
// Check whether the route was configured to use the base page theme.
if (!(($route = $request->attributes->get(RouteObjectInterface::ROUTE_OBJECT)) && $route->hasOption('_theme') && $route->getOption('_theme') == 'ajax_base_page')) {
return NULL;
}
if (($ajax_page_state = $request->request->get('ajax_page_state')) && !empty($ajax_page_state['theme']) && !empty($ajax_page_state['theme_token'])) {
$theme = $ajax_page_state['theme'];
$token = $ajax_page_state['theme_token'];
// Prevent a request forgery from giving a person access to a theme they
// shouldn't be otherwise allowed to see. However, since everyone is allowed
// to see the default theme, token validation isn't required for that, and
// bypassing it allows most use-cases to work even when accessed from the
// page cache.
if ($theme === $this->configFactory->get('system.theme')->get('default') || $this->csrfGenerator->validate($token, $theme)) {
return $theme;
}
}
}
}
<?php
/**
* @file
* Contains \Drupal\Core\Theme\DefaultNegotiator.
*/
namespace Drupal\Core\Theme;
use Drupal\Core\Config\ConfigFactory;
use Symfony\Component\HttpFoundation\Request;
/**
* Determines the default theme of the site.
*/
class DefaultNegotiator implements ThemeNegotiatorInterface {
/**
* The system theme config object.
*
* @var \Drupal\Core\Config\Config
*/
protected $config;
/**
* Constructs a DefaultNegotiator object.
*
* @param \Drupal\Core\Config\ConfigFactory $config_factory
* The config factory.
*/
public function __construct(ConfigFactory $config_factory) {
$this->config = $config_factory->get('system.theme');
}
/**
* {@inheritdoc}
*/
public function determineActiveTheme(Request $request) {
return $this->config->get('default');
}
}