Skip to content
Commits on Source (34)
......@@ -77,15 +77,23 @@ Drupal 8.0, xxxx-xx-xx (development version)
* All Gettext files are now imported in chunks, better for low resource
environments.
* Improved content language support:
* Freely orderable language selector in forms.
* Made it possible to assign language to taxonomy terms, vocabularies
and files.
* Node type specific default language assignment is much more versatile.
* Made it possible to assign language to taxonomy terms, vocabularies,
menu items, and files.
* Added a field translation based content translation module that applies
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.
* Search indexing and query preprocessors now get language information.
* Unified content translation permission granularity with content editing
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.
* Much improved language APIs for developers:
* Added simple APIs and hooks to save/delete/update languages.
......@@ -97,10 +105,13 @@ Drupal 8.0, xxxx-xx-xx (development version)
* Made it possible for users to have a preferred language separate from
their user entity language.
* The text formatter from t() is now available as format_string().
* Added support for interface translation contexts in Drupal.t() and
Drupal.formatPlural() in JavaScript.
* Added support for interface translation contexts in Drupal.t(),
Drupal.formatPlural() as well as routing, tabs, actions, and contextual
links.
* Removed textgroups support from interface translation in favor of
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.
* Added language select form element in the Form API.
- Added E-mail field type to core.
......
......@@ -237,9 +237,17 @@ Comment 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
- ?
Content Translation module
- Francesco Placella 'plach' http://drupal.org/user/183211
Contextual module
- Daniel F. Kudwien 'sun' http://drupal.org/user/54136
......@@ -294,12 +302,16 @@ Help module
Image module
- 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
Link module
- ?
Menu module
- ?
......@@ -382,9 +394,6 @@ Tour module
Tracker module
- David Strauss 'David Strauss' http://drupal.org/user/93254
Translation module
- Francesco Placella 'plach' http://drupal.org/user/183211
Update module
- Derek Wright 'dww' http://drupal.org/user/46549
......
......@@ -196,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']
......@@ -350,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:
......@@ -421,7 +420,6 @@ services:
- [setCurrentUser, ['@?current_user']]
tags:
- { name: event_subscriber }
scope: request
access_route_subscriber:
class: Drupal\Core\EventSubscriber\AccessRouteSubscriber
tags:
......
......@@ -1374,6 +1374,9 @@ function format_string($string, array $args = array()) {
* @see \Drupal\Component\Utility\String::checkPlain()
* @see drupal_validate_utf8()
* @ingroup sanitization
*
* @deprecated as of Drupal 8.0. Use
* Drupal\Component\Utility\String::checkPlain() directly instead.
*/
function check_plain($text) {
return String::checkPlain($text);
......@@ -1549,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.
}
......@@ -1715,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);
......@@ -1858,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);
......@@ -1991,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;
}
......@@ -3797,7 +3798,19 @@ function drupal_render_page($page) {
* - If this element has #prefix and/or #suffix defined, they are concatenated
* to #children.
* - 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
* rendered once.
* - The final value of #children for this element is returned as the rendered
......@@ -3805,6 +3818,8 @@ function drupal_render_page($page) {
*
* @param array $elements
* 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
* The rendered HTML.
......@@ -3814,7 +3829,7 @@ function drupal_render_page($page) {
* @see drupal_process_states()
* @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.
if (empty($elements) || (isset($elements['#access']) && !$elements['#access'])) {
return '';
......@@ -3825,11 +3840,19 @@ function drupal_render(&$elements) {
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'])) {
$cached_output = drupal_render_cache_get($elements);
if ($cached_output !== FALSE) {
return $cached_output;
$cached_element = drupal_render_cache_get($elements);
if ($cached_element !== FALSE) {
$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) {
// process as drupal_render_children() but is inlined for speed.
if ((!$theme_is_implemented || isset($elements['#render_children'])) && empty($elements['#children'])) {
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) {
}
}
// 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'] : '';
$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.
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;
return $output;
return $elements['#markup'];
}
/**
......@@ -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.
*
* @return
* A markup string containing the rendered content of the element, or FALSE
* if no cached copy of the element is available.
* @return array
* A renderable array, with the original element and all its children pre-
* rendered, or FALSE if no cached copy of the element is available.
*
* @see drupal_render()
* @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)) {
return FALSE;
}
$bin = isset($elements['#cache']['bin']) ? $elements['#cache']['bin'] : 'cache';
if (!empty($cid) && $cache = cache($bin)->get($cid)) {
$cached_element = $cache->data;
// Add additional libraries, JavaScript, CSS and other data attached
// to this element.
if (isset($cache->data['#attached'])) {
drupal_process_attached($cache->data);
if (isset($cached_element['#attached'])) {
drupal_process_attached($cached_element);
}
// Return the rendered output.
return $cache->data['#markup'];
// Return the cached element.
return $cached_element;
}
return FALSE;
}
......@@ -4112,12 +4159,12 @@ function drupal_render_cache_get($elements) {
*
* @param $markup
* The rendered output string of $elements.
* @param $elements
* @param array $elements
* A renderable array.
*
* @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.
if (!\Drupal::request()->isMethodSafe() || !$cid = drupal_render_cid_create($elements)) {
return FALSE;
......@@ -4129,18 +4176,194 @@ function drupal_render_cache_set(&$markup, $elements) {
// $data['#real-value']) and return an include command instead. When the
// ESI command is executed by the content accelerator, the real value can
// be retrieved and used.
$data['#markup'] = &$markup;
$data['#markup'] = $markup;
// Persist attached data associated with this element.
$attached = drupal_render_collect_attached($elements, TRUE);
if ($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';
$expire = isset($elements['#cache']['expire']) ? $elements['#cache']['expire'] : CacheBackendInterface::CACHE_PERMANENT;
$tags = drupal_render_collect_cache_tags($elements);
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.
*
......
......@@ -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');
......
......@@ -368,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();
}
......@@ -1279,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().
......@@ -2226,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');
......@@ -2509,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));
}
}
/**
......
......@@ -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.
......
......@@ -904,9 +904,18 @@ public function __clone() {
// Avoid deep-cloning when we are initializing a translation object, since
// it will represent the same entity, only with a different active language.
if (!$this->translationInitialize) {
foreach ($this->fields as $name => $properties) {
foreach ($properties as $langcode => $property) {
$this->fields[$name][$langcode] = clone $property;
$definitions = $this->getPropertyDefinitions();
foreach ($this->fields as $name => $values) {
$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);
}
}
......
......@@ -176,6 +176,10 @@ public function form(array $form, array &$form_state) {
* @see \Drupal\Core\Entity\EntityFormController::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.
foreach ($this->getFormDisplay($form_state)->getComponents() as $name => $options) {
if (isset($element[$name])) {
......
......@@ -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;
}
}
......@@ -478,21 +478,6 @@ public function retrieveForm($form_id, &$form_state) {
// Record the $form_id.
$form_state['build_info']['form_id'] = $form_id;
// Record the filepath of the include file containing the original form, so
// the form builder callbacks can be loaded when the form is being rebuilt
// from cache on a different path (such as 'system/ajax'). See
// self::getCache(). Don't do this in maintenance mode as Drupal may not be
// fully bootstrapped (i.e. during installation) in which case
// menu_get_item() is not available.
if (!isset($form_state['build_info']['files']['menu']) && !defined('MAINTENANCE_MODE')) {
$item = $this->menuGetItem();
if (!empty($item['include_file'])) {
// Do not use form_load_include() here, as the file is already loaded.
// Anyway, self::getCache() is able to handle filepaths too.
$form_state['build_info']['files']['menu'] = $item['include_file'];
}
}
// We save two copies of the incoming arguments: one for modules to use
// when mapping form ids to constructor functions, and another to pass to
// the constructor function itself.
......@@ -1701,15 +1686,6 @@ protected function drupalInstallationAttempted() {
return drupal_installation_attempted();
}
/**
* Wraps menu_get_item().
*
* @return array|bool
*/
protected function menuGetItem() {
return menu_get_item();
}
/**
* Wraps watchdog().
*/
......
......@@ -2,9 +2,7 @@
/**
* @file
* Provides views data and handlers for action.module.
*
* @ingroup views_module_handlers
* Provides views data for action.module.
*/
/**
......
......@@ -3,8 +3,6 @@
/**
* @file
* Provides views data for aggregator.module.
*
* @ingroup views_module_handlers
*/
/**
......
......@@ -36,10 +36,10 @@
* admin_permission = "administer blocks",
* base_table = "custom_block",
* revision_table = "custom_block_revision",
* route_base_path = "admin/structure/block/custom-blocks/manage/{bundle}",
* links = {
* "canonical" = "custom_block.edit",
* "edit-form" = "custom_block.edit"
* "edit-form" = "custom_block.edit",
* "admin-form" = "custom_block.type_edit"
* },
* fieldable = TRUE,
* translatable = TRUE,
......@@ -52,7 +52,8 @@
* },
* bundle_keys = {
* "bundle" = "type"
* }
* },
* bundle_entity_type = "custom_block_type"
* )
*/
class CustomBlock extends ContentEntityBase implements CustomBlockInterface {
......