Skip to content
Commits on Source (38)
...@@ -77,15 +77,23 @@ Drupal 8.0, xxxx-xx-xx (development version) ...@@ -77,15 +77,23 @@ Drupal 8.0, xxxx-xx-xx (development version)
* All Gettext files are now imported in chunks, better for low resource * All Gettext files are now imported in chunks, better for low resource
environments. environments.
* Improved content language support: * Improved content language support:
* Freely orderable language selector in forms. * Made it possible to assign language to taxonomy terms, vocabularies,
* Made it possible to assign language to taxonomy terms, vocabularies menu items, and files.
and files. * Added a field translation based content translation module that applies
* Node type specific default language assignment is much more versatile. to all content entities.
* Removed the old node-copy based content translation module.
* Introduced language defaults configuration for each entity type and
subtype.
* Added entity language variance support to search module. * Added entity language variance support to search module.
* Search indexing and query preprocessors now get language information. * Search indexing and query preprocessors now get language information.
* Unified content translation permission granularity with content editing * Unified content translation permission granularity with content editing
permissions. permissions.
* Better language based configuration * Made the language selector freely orderable in entity forms.
* Better configuration language support
* Added language selectors to most configuration options (views, menus,
etc.)
* Added a configuration translation user interface that works with any
configuration with translatable values (blocks, views, fields, etc).
* Added language options to block visibility. * Added language options to block visibility.
* Much improved language APIs for developers: * Much improved language APIs for developers:
* Added simple APIs and hooks to save/delete/update languages. * Added simple APIs and hooks to save/delete/update languages.
...@@ -97,10 +105,13 @@ Drupal 8.0, xxxx-xx-xx (development version) ...@@ -97,10 +105,13 @@ Drupal 8.0, xxxx-xx-xx (development version)
* Made it possible for users to have a preferred language separate from * Made it possible for users to have a preferred language separate from
their user entity language. their user entity language.
* The text formatter from t() is now available as format_string(). * The text formatter from t() is now available as format_string().
* Added support for interface translation contexts in Drupal.t() and * Added support for interface translation contexts in Drupal.t(),
Drupal.formatPlural() in JavaScript. Drupal.formatPlural() as well as routing, tabs, actions, and contextual
links.
* Removed textgroups support from interface translation in favor of * Removed textgroups support from interface translation in favor of
native configuration language support. native configuration language support.
* Added configuration schema system to support generating translation
forms for any configuration.
* Reworked Gettext PO support to use pluggable read/write handlers. * Reworked Gettext PO support to use pluggable read/write handlers.
* Added language select form element in the Form API. * Added language select form element in the Form API.
- Added E-mail field type to core. - Added E-mail field type to core.
......
...@@ -237,9 +237,17 @@ Comment module ...@@ -237,9 +237,17 @@ Comment module
Configuration module Configuration module
- ? - ?
Configuration Translation module
- Gábor Hojtsy 'Gábor Hojtsy' http://drupal.org/user/4166
- Tobias Stöckler 'tstoeckler' https://drupal.org/user/107158
- Vijayachandran Mani 'vijaycs85' https://drupal.org/user/93488
Contact module Contact module
- ? - ?
Content Translation module
- Francesco Placella 'plach' http://drupal.org/user/183211
Contextual module Contextual module
- Daniel F. Kudwien 'sun' http://drupal.org/user/54136 - Daniel F. Kudwien 'sun' http://drupal.org/user/54136
...@@ -294,12 +302,16 @@ Help module ...@@ -294,12 +302,16 @@ Help module
Image module Image module
- Claudiu Cristea 'claudiu.cristea' https://drupal.org/user/56348 - Claudiu Cristea 'claudiu.cristea' https://drupal.org/user/56348
Link module Interface Translation (locale) module
- ? - Gábor Hojtsy 'Gábor Hojtsy' http://drupal.org/user/4166
Locale module Language module
- Francesco Placella 'plach' http://drupal.org/user/183211
- Gábor Hojtsy 'Gábor Hojtsy' http://drupal.org/user/4166 - Gábor Hojtsy 'Gábor Hojtsy' http://drupal.org/user/4166
Link module
- ?
Menu module Menu module
- ? - ?
...@@ -382,9 +394,6 @@ Tour module ...@@ -382,9 +394,6 @@ Tour module
Tracker module Tracker module
- David Strauss 'David Strauss' http://drupal.org/user/93254 - David Strauss 'David Strauss' http://drupal.org/user/93254
Translation module
- Francesco Placella 'plach' http://drupal.org/user/183211
Update module Update module
- Derek Wright 'dww' http://drupal.org/user/46549 - Derek Wright 'dww' http://drupal.org/user/46549
......
...@@ -196,17 +196,12 @@ services: ...@@ -196,17 +196,12 @@ services:
plugin.manager.menu.local_task: plugin.manager.menu.local_task:
class: Drupal\Core\Menu\LocalTaskManager class: Drupal\Core\Menu\LocalTaskManager
arguments: ['@controller_resolver', '@request', '@router.route_provider', '@module_handler', '@cache.cache', '@language_manager', '@access_manager', '@current_user'] arguments: ['@controller_resolver', '@request', '@router.route_provider', '@module_handler', '@cache.cache', '@language_manager', '@access_manager', '@current_user']
scope: request
plugin.manager.menu.contextual_link: plugin.manager.menu.contextual_link:
class: Drupal\Core\Menu\ContextualLinkManager class: Drupal\Core\Menu\ContextualLinkManager
arguments: ['@controller_resolver', '@module_handler', '@cache.cache', '@language_manager', '@access_manager', '@current_user'] arguments: ['@controller_resolver', '@module_handler', '@cache.cache', '@language_manager', '@access_manager', '@current_user']
request: request:
class: Symfony\Component\HttpFoundation\Request class: Symfony\Component\HttpFoundation\Request
# @TODO the synthetic setting must be uncommented whenever drupal_session_initialize() synthetic: true
# 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
event_dispatcher: event_dispatcher:
class: Symfony\Component\EventDispatcher\ContainerAwareEventDispatcher class: Symfony\Component\EventDispatcher\ContainerAwareEventDispatcher
arguments: ['@service_container'] arguments: ['@service_container']
...@@ -350,6 +345,10 @@ services: ...@@ -350,6 +345,10 @@ services:
tags: tags:
- { name: event_subscriber } - { name: event_subscriber }
arguments: ['@settings'] arguments: ['@settings']
ajax_response_subscriber:
class: Drupal\Core\EventSubscriber\AjaxResponseSubscriber
tags:
- { name: event_subscriber }
route_enhancer.authentication: route_enhancer.authentication:
class: Drupal\Core\Routing\Enhancer\AuthenticationEnhancer class: Drupal\Core\Routing\Enhancer\AuthenticationEnhancer
calls: calls:
...@@ -407,7 +406,7 @@ services: ...@@ -407,7 +406,7 @@ services:
class: Drupal\Core\Access\CsrfTokenGenerator class: Drupal\Core\Access\CsrfTokenGenerator
arguments: ['@private_key'] arguments: ['@private_key']
calls: calls:
- [setRequest, ['@?request']] - [setCurrentUser, ['@?current_user']]
access_manager: access_manager:
class: Drupal\Core\Access\AccessManager class: Drupal\Core\Access\AccessManager
arguments: ['@router.route_provider', '@url_generator', '@paramconverter_manager'] arguments: ['@router.route_provider', '@url_generator', '@paramconverter_manager']
...@@ -421,7 +420,6 @@ services: ...@@ -421,7 +420,6 @@ services:
- [setCurrentUser, ['@?current_user']] - [setCurrentUser, ['@?current_user']]
tags: tags:
- { name: event_subscriber } - { name: event_subscriber }
scope: request
access_route_subscriber: access_route_subscriber:
class: Drupal\Core\EventSubscriber\AccessRouteSubscriber class: Drupal\Core\EventSubscriber\AccessRouteSubscriber
tags: tags:
...@@ -641,6 +639,11 @@ services: ...@@ -641,6 +639,11 @@ services:
class: Zend\Feed\Writer\Extension\Threading\Renderer\Entry class: Zend\Feed\Writer\Extension\Threading\Renderer\Entry
feed.writer.wellformedwebrendererentry: feed.writer.wellformedwebrendererentry:
class: Zend\Feed\Writer\Extension\WellFormedWeb\Renderer\Entry class: Zend\Feed\Writer\Extension\WellFormedWeb\Renderer\Entry
theme.registry:
class: Drupal\Core\Theme\Registry
arguments: ['@cache.cache', '@lock', '@module_handler']
tags:
- { name: needs_destruction }
authentication: authentication:
class: Drupal\Core\Authentication\AuthenticationManager class: Drupal\Core\Authentication\AuthenticationManager
authentication.cookie: authentication.cookie:
......
...@@ -1374,6 +1374,9 @@ function format_string($string, array $args = array()) { ...@@ -1374,6 +1374,9 @@ function format_string($string, array $args = array()) {
* @see \Drupal\Component\Utility\String::checkPlain() * @see \Drupal\Component\Utility\String::checkPlain()
* @see drupal_validate_utf8() * @see drupal_validate_utf8()
* @ingroup sanitization * @ingroup sanitization
*
* @deprecated as of Drupal 8.0. Use
* Drupal\Component\Utility\String::checkPlain() directly instead.
*/ */
function check_plain($text) { function check_plain($text) {
return String::checkPlain($text); return String::checkPlain($text);
...@@ -1549,7 +1552,7 @@ function watchdog($type, $message, array $variables = NULL, $severity = WATCHDOG ...@@ -1549,7 +1552,7 @@ function watchdog($type, $message, array $variables = NULL, $severity = WATCHDOG
$log_entry['referer'] = $request->headers->get('Referer', ''); $log_entry['referer'] = $request->headers->get('Referer', '');
$log_entry['ip'] = $request->getClientIP(); $log_entry['ip'] = $request->getClientIP();
} }
catch (\InvalidArgumentException $e) { catch (DependencyInjectionRuntimeException $e) {
// We are not in a request context. // We are not in a request context.
} }
...@@ -1715,9 +1718,18 @@ function drupal_set_title($title = NULL, $output = Title::CHECK_PLAIN) { ...@@ -1715,9 +1718,18 @@ function drupal_set_title($title = NULL, $output = Title::CHECK_PLAIN) {
* The user session object. * The user session object.
*/ */
function drupal_anonymous_user() { function drupal_anonymous_user() {
try {
$request = \Drupal::request();
$hostname = $request->getClientIP();
}
catch (DependencyInjectionRuntimeException $e) {
// We are not in a request context.
$hostname = '';
}
$values = array( $values = array(
'uid' => 0, 'uid' => 0,
'hostname' => \Drupal::request()->getClientIP(), 'hostname' => $hostname,
'roles' => array(DRUPAL_ANONYMOUS_RID), 'roles' => array(DRUPAL_ANONYMOUS_RID),
); );
return new UserSession($values); return new UserSession($values);
...@@ -1858,10 +1870,13 @@ function drupal_handle_request($test_only = FALSE) { ...@@ -1858,10 +1870,13 @@ function drupal_handle_request($test_only = FALSE) {
// @todo Remove this once everything in the bootstrap has been // @todo Remove this once everything in the bootstrap has been
// converted to services in the DIC. // converted to services in the DIC.
$kernel->boot(); $kernel->boot();
drupal_bootstrap(DRUPAL_BOOTSTRAP_CODE);
// Create a request object from the HttpFoundation. // Create a request object from the HttpFoundation.
$request = Request::createFromGlobals(); $request = Request::createFromGlobals();
\Drupal::getContainer()->set('request', $request);
drupal_bootstrap(DRUPAL_BOOTSTRAP_CODE);
$response = $kernel->handle($request)->prepare($request)->send(); $response = $kernel->handle($request)->prepare($request)->send();
$kernel->terminate($request, $response); $kernel->terminate($request, $response);
...@@ -1991,6 +2006,8 @@ function _drupal_bootstrap_kernel() { ...@@ -1991,6 +2006,8 @@ function _drupal_bootstrap_kernel() {
if (!\Drupal::getContainer()) { if (!\Drupal::getContainer()) {
$kernel = new DrupalKernel('prod', drupal_classloader()); $kernel = new DrupalKernel('prod', drupal_classloader());
$kernel->boot(); $kernel->boot();
$request = Request::createFromGlobals();
\Drupal::getContainer()->set('request', $request);
} }
} }
......
...@@ -399,14 +399,15 @@ function drupal_add_feed($url = NULL, $title = '') { ...@@ -399,14 +399,15 @@ function drupal_add_feed($url = NULL, $title = '') {
if (isset($url)) { if (isset($url)) {
$stored_feed_links[$url] = theme('feed_icon', array('url' => $url, 'title' => $title)); $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', 'rel' => 'alternate',
'type' => 'application/rss+xml', 'type' => 'application/rss+xml',
'title' => $title, 'title' => $title,
// Force the URL to be absolute, for consistency with other <link> tags // Force the URL to be absolute, for consistency with other <link> tags
// output by Drupal. // output by Drupal.
'href' => url($url, array('absolute' => TRUE)), 'href' => url($url, array('absolute' => TRUE)),
)); );
drupal_render($build);
} }
return $stored_feed_links; return $stored_feed_links;
} }
...@@ -3797,7 +3798,19 @@ function drupal_render_page($page) { ...@@ -3797,7 +3798,19 @@ function drupal_render_page($page) {
* - If this element has #prefix and/or #suffix defined, they are concatenated * - If this element has #prefix and/or #suffix defined, they are concatenated
* to #children. * to #children.
* - If this element has #cache defined, the rendered output of this element * - If this element has #cache defined, the rendered output of this element
* is saved to drupal_render()'s internal cache. * is saved to drupal_render()'s internal cache. This includes the changes
* made by #post_render.
* - If this element (or any of its children) has an array of
* #post_render_cache functions defined, they are called sequentially to
* replace placeholders in the final #markup and extend #attached.
* Placeholders must contain a unique token, to guarantee that e.g. samples
* of placeholders are not replaced also. For this, a special element named
* 'render_cache_placeholder' is provided.
* Note that these callbacks run always: when hitting the render cache, when
* missing, or when render caching is not used at all. This is done to allow
* any Drupal module to customize other render arrays without breaking the
* render cache if it is enabled, and to not require it to use other logic
* when render caching is disabled.
* - #printed is set to TRUE for this element to ensure that it is only * - #printed is set to TRUE for this element to ensure that it is only
* rendered once. * rendered once.
* - The final value of #children for this element is returned as the rendered * - The final value of #children for this element is returned as the rendered
...@@ -3805,6 +3818,8 @@ function drupal_render_page($page) { ...@@ -3805,6 +3818,8 @@ function drupal_render_page($page) {
* *
* @param array $elements * @param array $elements
* The structured array describing the data to be rendered. * The structured array describing the data to be rendered.
* @param bool $is_recursive_call
* Whether this is a recursive call or not, for internal use.
* *
* @return string * @return string
* The rendered HTML. * The rendered HTML.
...@@ -3814,7 +3829,7 @@ function drupal_render_page($page) { ...@@ -3814,7 +3829,7 @@ function drupal_render_page($page) {
* @see drupal_process_states() * @see drupal_process_states()
* @see drupal_process_attached() * @see drupal_process_attached()
*/ */
function drupal_render(&$elements) { function drupal_render(&$elements, $is_recursive_call = FALSE) {
// Early-return nothing if user does not have access. // Early-return nothing if user does not have access.
if (empty($elements) || (isset($elements['#access']) && !$elements['#access'])) { if (empty($elements) || (isset($elements['#access']) && !$elements['#access'])) {
return ''; return '';
...@@ -3825,11 +3840,19 @@ function drupal_render(&$elements) { ...@@ -3825,11 +3840,19 @@ function drupal_render(&$elements) {
return ''; return '';
} }
// Try to fetch the element's markup from cache and return. // Try to fetch the prerendered element from cache, run any #post_render_cache
// callbacks and return the final markup.
if (isset($elements['#cache'])) { if (isset($elements['#cache'])) {
$cached_output = drupal_render_cache_get($elements); $cached_element = drupal_render_cache_get($elements);
if ($cached_output !== FALSE) { if ($cached_element !== FALSE) {
return $cached_output; $elements = $cached_element;
// Only when we're not in a recursive drupal_render() call,
// #post_render_cache callbacks must be executed, to prevent breaking the
// render cache in case of nested elements with #cache set.
if (!$is_recursive_call) {
_drupal_render_process_post_render_cache($elements);
}
return $elements['#markup'];
} }
} }
...@@ -3888,7 +3911,7 @@ function drupal_render(&$elements) { ...@@ -3888,7 +3911,7 @@ function drupal_render(&$elements) {
// process as drupal_render_children() but is inlined for speed. // process as drupal_render_children() but is inlined for speed.
if ((!$theme_is_implemented || isset($elements['#render_children'])) && empty($elements['#children'])) { if ((!$theme_is_implemented || isset($elements['#render_children'])) && empty($elements['#children'])) {
foreach ($children as $key) { foreach ($children as $key) {
$elements['#children'] .= drupal_render($elements[$key]); $elements['#children'] .= drupal_render($elements[$key], TRUE);
} }
} }
...@@ -3948,17 +3971,40 @@ function drupal_render(&$elements) { ...@@ -3948,17 +3971,40 @@ function drupal_render(&$elements) {
} }
} }
// We store the resulting output in $elements['#markup'], to be consistent
// with how render cached output gets stored. This ensures that
// #post_render_cache callbacks get the same data to work with, no matter if
// #cache is disabled, #cache is enabled, there is a cache hit or miss.
$prefix = isset($elements['#prefix']) ? $elements['#prefix'] : ''; $prefix = isset($elements['#prefix']) ? $elements['#prefix'] : '';
$suffix = isset($elements['#suffix']) ? $elements['#suffix'] : ''; $suffix = isset($elements['#suffix']) ? $elements['#suffix'] : '';
$output = $prefix . $elements['#children'] . $suffix; $elements['#markup'] = $prefix . $elements['#children'] . $suffix;
// Cache the processed element if #cache is set. // Cache the processed element if #cache is set.
if (isset($elements['#cache'])) { if (isset($elements['#cache'])) {
drupal_render_cache_set($output, $elements); // Collect all #post_render_cache callbacks associated with this element.
$post_render_cache = drupal_render_collect_post_render_cache($elements);
if ($post_render_cache) {
$elements['#post_render_cache'] = $post_render_cache;
}
drupal_render_cache_set($elements['#markup'], $elements);
}
// Only when we're not in a recursive drupal_render() call,
// #post_render_cache callbacks must be executed, to prevent breaking the
// render cache in case of nested elements with #cache set.
//
// By running them here, we ensure that:
// - they run when #cache is disabled,
// - they run when #cache is enabled and there is a cache miss.
// Only the case of a cache hit when #cache is enabled, is not handled here,
// that is handled earlier in drupal_render().
if (!$is_recursive_call) {
_drupal_render_process_post_render_cache($elements);
} }
$elements['#printed'] = TRUE; $elements['#printed'] = TRUE;
return $output; return $elements['#markup'];
} }
/** /**
...@@ -4074,32 +4120,33 @@ function show(&$element) { ...@@ -4074,32 +4120,33 @@ function show(&$element) {
} }
/** /**
* Gets the rendered output of a renderable element from the cache. * Gets the cached, prerendered element of a renderable element from the cache.
* *
* @param $elements * @param array $elements
* A renderable array. * A renderable array.
* *
* @return * @return array
* A markup string containing the rendered content of the element, or FALSE * A renderable array, with the original element and all its children pre-
* if no cached copy of the element is available. * rendered, or FALSE if no cached copy of the element is available.
* *
* @see drupal_render() * @see drupal_render()
* @see drupal_render_cache_set() * @see drupal_render_cache_set()
*/ */
function drupal_render_cache_get($elements) { function drupal_render_cache_get(array $elements) {
if (!\Drupal::request()->isMethodSafe() || !$cid = drupal_render_cid_create($elements)) { if (!\Drupal::request()->isMethodSafe() || !$cid = drupal_render_cid_create($elements)) {
return FALSE; return FALSE;
} }
$bin = isset($elements['#cache']['bin']) ? $elements['#cache']['bin'] : 'cache'; $bin = isset($elements['#cache']['bin']) ? $elements['#cache']['bin'] : 'cache';
if (!empty($cid) && $cache = cache($bin)->get($cid)) { if (!empty($cid) && $cache = cache($bin)->get($cid)) {
$cached_element = $cache->data;
// Add additional libraries, JavaScript, CSS and other data attached // Add additional libraries, JavaScript, CSS and other data attached
// to this element. // to this element.
if (isset($cache->data['#attached'])) { if (isset($cached_element['#attached'])) {
drupal_process_attached($cache->data); drupal_process_attached($cached_element);
} }
// Return the rendered output. // Return the cached element.
return $cache->data['#markup']; return $cached_element;
} }
return FALSE; return FALSE;
} }
...@@ -4112,12 +4159,12 @@ function drupal_render_cache_get($elements) { ...@@ -4112,12 +4159,12 @@ function drupal_render_cache_get($elements) {
* *
* @param $markup * @param $markup
* The rendered output string of $elements. * The rendered output string of $elements.
* @param $elements * @param array $elements
* A renderable array. * A renderable array.
* *
* @see drupal_render_cache_get() * @see drupal_render_cache_get()
*/ */
function drupal_render_cache_set(&$markup, $elements) { function drupal_render_cache_set(&$markup, array $elements) {
// Create the cache ID for the element. // Create the cache ID for the element.
if (!\Drupal::request()->isMethodSafe() || !$cid = drupal_render_cid_create($elements)) { if (!\Drupal::request()->isMethodSafe() || !$cid = drupal_render_cid_create($elements)) {
return FALSE; return FALSE;
...@@ -4129,18 +4176,194 @@ function drupal_render_cache_set(&$markup, $elements) { ...@@ -4129,18 +4176,194 @@ function drupal_render_cache_set(&$markup, $elements) {
// $data['#real-value']) and return an include command instead. When the // $data['#real-value']) and return an include command instead. When the
// ESI command is executed by the content accelerator, the real value can // ESI command is executed by the content accelerator, the real value can
// be retrieved and used. // be retrieved and used.
$data['#markup'] = &$markup; $data['#markup'] = $markup;
// Persist attached data associated with this element. // Persist attached data associated with this element.
$attached = drupal_render_collect_attached($elements, TRUE); $attached = drupal_render_collect_attached($elements, TRUE);
if ($attached) { if ($attached) {
$data['#attached'] = $attached; $data['#attached'] = $attached;
} }
// Persist #post_render_cache callbacks associated with this element.
if (isset($elements['#post_render_cache'])) {
$data['#post_render_cache'] = $elements['#post_render_cache'];
}
$bin = isset($elements['#cache']['bin']) ? $elements['#cache']['bin'] : 'cache'; $bin = isset($elements['#cache']['bin']) ? $elements['#cache']['bin'] : 'cache';
$expire = isset($elements['#cache']['expire']) ? $elements['#cache']['expire'] : CacheBackendInterface::CACHE_PERMANENT; $expire = isset($elements['#cache']['expire']) ? $elements['#cache']['expire'] : CacheBackendInterface::CACHE_PERMANENT;
$tags = drupal_render_collect_cache_tags($elements); $tags = drupal_render_collect_cache_tags($elements);
cache($bin)->set($cid, $data, $expire, $tags); cache($bin)->set($cid, $data, $expire, $tags);
} }
/**
* Generates a render cache placeholder.
*
* This is used by drupal_pre_render_render_cache_placeholder() to generate
* placeholders, but should also be called by #post_render_cache callbacks that
* want to replace the placeholder with the final markup.
*
* @param callable $callback
* The #post_render_cache callback that will replace the placeholder with its
* eventual markup.
* @param array $context
* An array providing context for the #post_render_cache callback.
* @param string $token
* A unique token to uniquely identify the placeholder.
*
* @see drupal_render_cache_get()
*/
function drupal_render_cache_generate_placeholder($callback, array $context, $token) {
// Serialize the context into a HTML attribute; unserializing is unnecessary.
$context_attribute = '';
foreach ($context as $key => $value) {
$context_attribute .= $key . ':' . $value . ';';
}
return '<drupal:render-cache-placeholder callback="' . $callback . '" context="' . $context_attribute . '" token="'. $token . '" />';;
}
/**
* Pre-render callback: Renders a render cache placeholder into #markup.
*
* @param $elements
* A structured array whose keys form the arguments to l():
* - #callback: The #post_render_cache callback that will replace the
* placeholder with its eventual markup.
* - #context: An array providing context for the #post_render_cache callback.
*
* @return
* The passed-in element containing a render cache placeholder in '#markup'
* and a callback with context, keyed by a generated unique token in
* '#post_render_cache'.
*
* @see drupal_render_cache_generate_placeholder()
*/
function drupal_pre_render_render_cache_placeholder($element) {
$callback = $element['#callback'];
if (!is_callable($callback)) {
throw new Exception(t('#callback must be a callable function.'));
}
$context = $element['#context'];
if (!is_array($context)) {
throw new Exception(t('#context must be an array.'));
}
$token = \Drupal\Component\Utility\Crypt::randomStringHashed(55);
// Generate placeholder markup and store #post_render_cache callback.
$element['#markup'] = drupal_render_cache_generate_placeholder($callback, $context, $token);
$element['#post_render_cache'][$callback][$token] = $context;
return $element;
}
/**
* Processes #post_render_cache callbacks.
*
* #post_render_cache callbacks may modify:
* - #markup: to replace placeholders
* - #attached: to add libraries or JavaScript settings
*
* Note that in either of these cases, #post_render_cache callbacks are
* implicitly idempotent: a placeholder that has been replaced can't be replaced
* again, and duplicate attachments are ignored.
*
* @param array &$elements
* The structured array describing the data being rendered.
*
* @see drupal_render()
* @see drupal_render_collect_post_render_cache
*/
function _drupal_render_process_post_render_cache(array &$elements) {
if (isset($elements['#post_render_cache'])) {
// Call all #post_render_cache callbacks, while passing the provided context
// and if keyed by a number, no token is passed, otherwise, the token string
// is passed to the callback as well. This token is used to uniquely
// identify the placeholder in the markup.
$modified_elements = $elements;
foreach ($elements['#post_render_cache'] as $callback => $options) {
foreach ($elements['#post_render_cache'][$callback] as $token => $context) {
// The advanced option, when setting #post_render_cache directly.
if (is_numeric($token)) {
$modified_elements = call_user_func_array($callback, array($modified_elements, $context));
}
// The simple option, when using the standard placeholders, and hence
// also when using #type => render_cache_placeholder.
else {
// Call #post_render_cache callback to generate the element that will
// fill in the placeholder.
$generated_element = call_user_func_array($callback, array($context));
// Update #attached based on the generated element.
if (isset($generated_element['#attached'])) {
if (!isset($modified_elements['#attached'])) {
$modified_elements['#attached'] = array();
}
$modified_elements['#attached'] = drupal_merge_attached($modified_elements['#attached'], drupal_render_collect_attached($generated_element, TRUE));
}
// Replace the placeholder with the rendered markup of the generated
// element.
$placeholder = drupal_render_cache_generate_placeholder($callback, $context, $token);
$modified_elements['#markup'] = str_replace($placeholder, drupal_render($generated_element), $modified_elements['#markup']);
}
}
}
// Only retain changes to the #markup and #attached properties, as would be
// the case when the render cache was actually being used.
$elements['#markup'] = $modified_elements['#markup'];
if (isset($modified_elements['#attached'])) {
$elements['#attached'] = $modified_elements['#attached'];
}
// Make sure that any attachments added in #post_render_cache callbacks are
// also executed.
if (isset($elements['#attached'])) {
drupal_process_attached($elements);
}
}
}
/**
* Collects #post_render_cache for an element and its children into a single
* array.
*
* When caching elements, it is necessary to collect all #post_render_cache
* callbacks into a single array, from both the element itself and all child
* elements. This allows drupal_render() to execute all of them when the element
* is retrieved from the render cache.
*
* @param array $elements
* The element to collect #post_render_cache from.
* @param array $callbacks
* Internal use only. The #post_render_callbacks array so far.
* @param bool $is_root_element
* Internal use only. Whether the element being processed is the root or not.
*
* @return
* The #post_render_cache array for this element and its descendants.
*
* @see drupal_render()
* @see _drupal_render_process_post_render_cache()
*/
function drupal_render_collect_post_render_cache(array $elements, array $callbacks = array(), $is_root_element = TRUE) {
// Collect all #post_render_cache for this element.
if (isset($elements['#post_render_cache'])) {
$callbacks = NestedArray::mergeDeep($callbacks, $elements['#post_render_cache']);
}
// Child elements that have #cache set will already have collected all their
// children's #post_render_cache callbacks, so no need to traverse further.
if (!$is_root_element && isset($elements['#cache'])) {
return $callbacks;
}
else if ($children = element_children($elements)) {
foreach ($children as $child) {
$callbacks = drupal_render_collect_post_render_cache($elements[$child], $callbacks, FALSE);
}
}
return $callbacks;
}
/** /**
* Collects #attached for an element and its children into a single array. * Collects #attached for an element and its children into a single array.
* *
......
...@@ -410,6 +410,13 @@ function install_begin_request(&$install_state) { ...@@ -410,6 +410,13 @@ function install_begin_request(&$install_state) {
// implementation here. // implementation here.
$container->register('lock', 'Drupal\Core\Lock\NullLockBackend'); $container->register('lock', 'Drupal\Core\Lock\NullLockBackend');
$container
->register('theme.registry', 'Drupal\Core\Theme\Registry')
->addArgument(new Reference('cache.cache'))
->addArgument(new Reference('lock'))
->addArgument(new Reference('module_handler'))
->addTag('needs_destruction');
// Register a module handler for managing enabled modules. // Register a module handler for managing enabled modules.
$container $container
->register('module_handler', 'Drupal\Core\Extension\ModuleHandler'); ->register('module_handler', 'Drupal\Core\Extension\ModuleHandler');
......
...@@ -625,10 +625,19 @@ function drupal_install_system() { ...@@ -625,10 +625,19 @@ function drupal_install_system() {
// Create tables. // Create tables.
drupal_install_schema('system'); drupal_install_schema('system');
if (!drupal_container()->has('kernel')) { if (!\Drupal::getContainer()->has('kernel')) {
// Immediately boot a kernel to have real services ready. // 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 = new DrupalKernel('install', drupal_classloader(), FALSE);
$kernel->boot(); $kernel->boot();
if (isset($request)) {
\Drupal::getContainer()->set('request', $request);
}
} }
$system_path = drupal_get_path('module', 'system'); $system_path = drupal_get_path('module', 'system');
......
This diff is collapsed.
...@@ -91,6 +91,10 @@ function _drupal_maintenance_theme() { ...@@ -91,6 +91,10 @@ function _drupal_maintenance_theme() {
$ancestor = $themes[$ancestor]->base_theme; $ancestor = $themes[$ancestor]->base_theme;
} }
_drupal_theme_initialize($themes[$theme], array_reverse($base_theme), '_theme_load_offline_registry'); _drupal_theme_initialize($themes[$theme], array_reverse($base_theme), '_theme_load_offline_registry');
_drupal_theme_initialize($themes[$theme], array_reverse($base_theme));
// Prime the theme registry.
// @todo Remove global theme variables.
Drupal::service('theme.registry');
// These CSS files are normally added by system_page_build(), except // These CSS files are normally added by system_page_build(), except
// system.maintenance.css. When the database is inactive, it's not called so // system.maintenance.css. When the database is inactive, it's not called so
...@@ -98,13 +102,6 @@ function _drupal_maintenance_theme() { ...@@ -98,13 +102,6 @@ function _drupal_maintenance_theme() {
drupal_add_library('system', 'normalize'); drupal_add_library('system', 'normalize');
} }
/**
* Builds the registry when the site needs to bypass any database calls.
*/
function _theme_load_offline_registry($theme, $base_theme = NULL, $theme_engine = NULL) {
return _theme_build_registry($theme, $base_theme, $theme_engine);
}
/** /**
* Returns HTML for a list of maintenance tasks to perform. * Returns HTML for a list of maintenance tasks to perform.
* *
......
...@@ -458,6 +458,10 @@ function update_prepare_d8_bootstrap() { ...@@ -458,6 +458,10 @@ function update_prepare_d8_bootstrap() {
new Settings($settings); new Settings($settings);
$kernel = new DrupalKernel('update', drupal_classloader(), FALSE); $kernel = new DrupalKernel('update', drupal_classloader(), FALSE);
$kernel->boot(); $kernel->boot();
// Clear the D7 caches, to ensure that for example the theme_registry does not
// take part in the upgrade process.
Drupal::cache('cache')->deleteAll();
} }
/** /**
......
...@@ -9,9 +9,6 @@ ...@@ -9,9 +9,6 @@
/** /**
* Defines an object which stores multiple plugin instances to lazy load them. * 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 { abstract class PluginBag implements \Iterator, \Countable {
...@@ -30,7 +27,7 @@ abstract class PluginBag implements \Iterator, \Countable { ...@@ -30,7 +27,7 @@ abstract class PluginBag implements \Iterator, \Countable {
protected $instanceIDs = array(); protected $instanceIDs = array();
/** /**
* Initializes a plugin and stores the result in $this->pluginInstances. * Initializes and stores a plugin.
* *
* @param string $instance_id * @param string $instance_id
* The ID of the plugin instance to initialize. * The ID of the plugin instance to initialize.
...@@ -85,7 +82,7 @@ public function set($instance_id, $value) { ...@@ -85,7 +82,7 @@ public function set($instance_id, $value) {
/** /**
* Removes an initialized plugin. * 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 * @param string $instance_id
* The ID of the plugin instance to remove. * The ID of the plugin instance to remove.
...@@ -95,7 +92,7 @@ public function remove($instance_id) { ...@@ -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 * @param string $id
* The ID of the plugin instance to add. * The ID of the plugin instance to add.
...@@ -117,7 +114,7 @@ public function getInstanceIds() { ...@@ -117,7 +114,7 @@ public function getInstanceIds() {
} }
/** /**
* Sets the instance IDs property. * Sets all instance IDs.
* *
* @param array $instance_ids * @param array $instance_ids
* An associative array of instance IDs. * An associative array of instance IDs.
...@@ -138,28 +135,28 @@ public function removeInstanceId($instance_id) { ...@@ -138,28 +135,28 @@ public function removeInstanceId($instance_id) {
} }
/** /**
* Implements \Iterator::current(). * {@inheritdoc}
*/ */
public function current() { public function current() {
return $this->get($this->key()); return $this->get($this->key());
} }
/** /**
* Implements \Iterator::next(). * {@inheritdoc}
*/ */
public function next() { public function next() {
next($this->instanceIDs); next($this->instanceIDs);
} }
/** /**
* Implements \Iterator::key(). * {@inheritdoc}
*/ */
public function key() { public function key() {
return key($this->instanceIDs); return key($this->instanceIDs);
} }
/** /**
* Implements \Iterator::valid(). * {@inheritdoc}
*/ */
public function valid() { public function valid() {
$key = key($this->instanceIDs); $key = key($this->instanceIDs);
...@@ -167,14 +164,14 @@ public function valid() { ...@@ -167,14 +164,14 @@ public function valid() {
} }
/** /**
* Implements \Iterator::rewind(). * {@inheritdoc}
*/ */
public function rewind() { public function rewind() {
reset($this->instanceIDs); reset($this->instanceIDs);
} }
/** /**
* Implements \Countable::count(). * {@inheritdoc}
*/ */
public function count() { public function count() {
return count($this->instanceIDs); return count($this->instanceIDs);
......
...@@ -9,7 +9,7 @@ ...@@ -9,7 +9,7 @@
use Drupal\Component\Utility\Crypt; use Drupal\Component\Utility\Crypt;
use Drupal\Core\PrivateKey; use Drupal\Core\PrivateKey;
use Symfony\Component\HttpFoundation\Request; use Drupal\Core\Session\AccountInterface;
/** /**
* Generates and validates CSRF tokens. * Generates and validates CSRF tokens.
...@@ -26,11 +26,11 @@ class CsrfTokenGenerator { ...@@ -26,11 +26,11 @@ class CsrfTokenGenerator {
protected $privateKey; protected $privateKey;
/** /**
* The current request object. * The current user.
* *
* @var \Symfony\Component\HttpFoundation\Request * @var \Drupal\Core\Session\AccountInterface
*/ */
protected $request; protected $currentUser;
/** /**
* Constructs the token generator. * Constructs the token generator.
...@@ -43,13 +43,13 @@ public function __construct(PrivateKey $private_key) { ...@@ -43,13 +43,13 @@ public function __construct(PrivateKey $private_key) {
} }
/** /**
* Sets the $request property. * Sets the current user.
* *
* @param \Symfony\Component\HttpFoundation\Request $request * @param \Drupal\Core\Session\AccountInterface|null $current_user
* The HttpRequest object representing the current request. * The current user service.
*/ */
public function setRequest(Request $request) { public function setCurrentUser(AccountInterface $current_user = NULL) {
$this->request = $request; $this->currentUser = $current_user;
} }
/** /**
...@@ -84,9 +84,7 @@ public function get($value = '') { ...@@ -84,9 +84,7 @@ public function get($value = '') {
* is TRUE, the return value will always be TRUE for anonymous users. * is TRUE, the return value will always be TRUE for anonymous users.
*/ */
public function validate($token, $value = '', $skip_anonymous = FALSE) { public function validate($token, $value = '', $skip_anonymous = FALSE) {
$user = $this->request->attributes->get('_account'); return ($skip_anonymous && $this->currentUser->isAnonymous()) || ($token == $this->get($value));
return ($skip_anonymous && $user->isAnonymous()) || ($token == $this->get($value));
} }
} }
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
use Symfony\Component\HttpFoundation\JsonResponse; use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
/** /**
* JSON response object for AJAX requests. * JSON response object for AJAX requests.
...@@ -46,17 +47,25 @@ public function addCommand($command, $prepend = FALSE) { ...@@ -46,17 +47,25 @@ public function addCommand($command, $prepend = FALSE) {
} }
/** /**
* Sets the response's data to be the array of AJAX commands. * {@inheritdoc}
*
* @param Request $request
* A request object.
* *
* @return Response * Sets the response's data to be the array of AJAX commands.
* The current response.
*/ */
public function prepare(Request $request) { public function prepare(Request $request) {
$this->setData($this->ajaxRender($request)); $this->prepareResponse($request);
return parent::prepare($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));
}
} }
/** /**
......
...@@ -110,7 +110,6 @@ public function authenticate(Request $request) { ...@@ -110,7 +110,6 @@ public function authenticate(Request $request) {
// Save the authenticated account and the provider that supplied it // Save the authenticated account and the provider that supplied it
// for later access. // for later access.
$request->attributes->set('_account', $account);
$request->attributes->set('_authentication_provider', $this->triggeredProviderId); $request->attributes->set('_authentication_provider', $this->triggeredProviderId);
// The global $user object is included for backward compatibility only and // The global $user object is included for backward compatibility only and
......
...@@ -369,10 +369,17 @@ protected function getKernelParameters() { ...@@ -369,10 +369,17 @@ protected function getKernelParameters() {
protected function initializeContainer() { protected function initializeContainer() {
$this->containerNeedsDumping = FALSE; $this->containerNeedsDumping = FALSE;
$persist = $this->getServicesToPersist(); $persist = $this->getServicesToPersist();
// If we are rebuilding the kernel and we are in a request scope, store // The request service requires custom persisting logic, since it is also
// request info so we can add them back after the rebuild. // potentially scoped. During Drupal installation, there is a request
if (isset($this->container) && $this->container->hasScope('request')) { // service without a request scope.
$request = $this->container->get('request'); $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; $this->container = NULL;
$class = $this->getClassName(); $class = $this->getClassName();
...@@ -445,8 +452,10 @@ protected function initializeContainer() { ...@@ -445,8 +452,10 @@ protected function initializeContainer() {
// Set the class loader which was registered as a synthetic service. // Set the class loader which was registered as a synthetic service.
$this->container->set('class_loader', $this->classLoader); $this->container->set('class_loader', $this->classLoader);
// If we have a request set it back to the new container. // If we have a request set it back to the new container.
if (isset($request)) { if ($request_scope) {
$this->container->enterScope('request'); $this->container->enterScope('request');
}
if (isset($request)) {
$this->container->set('request', $request); $this->container->set('request', $request);
} }
\Drupal::setContainer($this->container); \Drupal::setContainer($this->container);
......
...@@ -225,16 +225,11 @@ class EntityType extends Plugin { ...@@ -225,16 +225,11 @@ class EntityType extends Plugin {
public $bundle_keys; public $bundle_keys;
/** /**
* The base router path for the entity type's field administration page. * The name of the entity type which provides bundles.
*
* 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.
* *
* @var string (optional) * @var string (optional)
*/ */
public $route_base_path; public $bundle_entity_type = 'bundle';
/** /**
* Link templates using the URI template syntax. * Link templates using the URI template syntax.
......
...@@ -904,9 +904,18 @@ public function __clone() { ...@@ -904,9 +904,18 @@ public function __clone() {
// Avoid deep-cloning when we are initializing a translation object, since // Avoid deep-cloning when we are initializing a translation object, since
// it will represent the same entity, only with a different active language. // it will represent the same entity, only with a different active language.
if (!$this->translationInitialize) { if (!$this->translationInitialize) {
foreach ($this->fields as $name => $properties) { $definitions = $this->getPropertyDefinitions();
foreach ($properties as $langcode => $property) { foreach ($this->fields as $name => $values) {
$this->fields[$name][$langcode] = clone $property; $this->fields[$name] = array();
// Untranslatable fields may have multiple references for the same field
// object keyed by language. To avoid creating different field objects
// we retain just the original value, as references will be recreated
// later as needed.
if (empty($definitions[$name]['translatable']) && count($values) > 1) {
$values = array_intersect_key($values, array(Language::LANGCODE_DEFAULT => TRUE));
}
foreach ($values as $langcode => $items) {
$this->fields[$name][$langcode] = clone $items;
$this->fields[$name][$langcode]->setContext($name, $this); $this->fields[$name][$langcode]->setContext($name, $this);
} }
} }
......
...@@ -176,6 +176,10 @@ public function form(array $form, array &$form_state) { ...@@ -176,6 +176,10 @@ public function form(array $form, array &$form_state) {
* @see \Drupal\Core\Entity\EntityFormController::form() * @see \Drupal\Core\Entity\EntityFormController::form()
*/ */
public function processForm($element, $form_state, $form) { public function processForm($element, $form_state, $form) {
// If the form is cached, process callbacks may not have a valid reference
// to the entity object, hence we must restore it.
$this->entity = $form_state['controller']->getEntity();
// Assign the weights configured in the form display. // Assign the weights configured in the form display.
foreach ($this->getFormDisplay($form_state)->getComponents() as $name => $options) { foreach ($this->getFormDisplay($form_state)->getComponents() as $name => $options) {
if (isset($element[$name])) { if (isset($element[$name])) {
......
...@@ -301,9 +301,9 @@ public function getAdminPath($entity_type, $bundle) { ...@@ -301,9 +301,9 @@ public function getAdminPath($entity_type, $bundle) {
$admin_path = ''; $admin_path = '';
$entity_info = $this->getDefinition($entity_type); $entity_info = $this->getDefinition($entity_type);
// Check for an entity type's admin base path. // Check for an entity type's admin base path.
if (isset($entity_info['route_base_path'])) { if (isset($entity_info['links']['admin-form'])) {
// Replace any dynamic 'bundle' portion of the path with the actual bundle. $route_parameters[$entity_info['bundle_entity_type']] = $bundle;
$admin_path = str_replace('{bundle}', $bundle, $entity_info['route_base_path']); $admin_path = \Drupal::urlGenerator()->getPathFromRoute($entity_info['links']['admin-form'], $route_parameters);
} }
return $admin_path; return $admin_path;
...@@ -313,10 +313,11 @@ public function getAdminPath($entity_type, $bundle) { ...@@ -313,10 +313,11 @@ public function getAdminPath($entity_type, $bundle) {
* {@inheritdoc} * {@inheritdoc}
*/ */
public function getAdminRouteInfo($entity_type, $bundle) { public function getAdminRouteInfo($entity_type, $bundle) {
$entity_info = $this->getDefinition($entity_type);
return array( return array(
'route_name' => "field_ui.overview_$entity_type", 'route_name' => "field_ui.overview_$entity_type",
'route_parameters' => array( 'route_parameters' => array(
'bundle' => $bundle, $entity_info['bundle_entity_type'] => $bundle,
) )
); );
} }
......
...@@ -164,6 +164,11 @@ public function getViewBuilder($entity_type); ...@@ -164,6 +164,11 @@ public function getViewBuilder($entity_type);
* *
* @return string * @return string
* The administration path for an entity type bundle, if it exists. * 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); public function getAdminPath($entity_type, $bundle);
......