Update to Drupal 8.0.3. For more information, see https://www.drupal.org/drupal-8.0.3-release-notes
This commit is contained in:
parent
10f9f7fbde
commit
9db4fae9a7
202 changed files with 3806 additions and 760 deletions
|
@ -135,7 +135,7 @@ class CssCollectionRenderer implements AssetCollectionRendererInterface {
|
|||
// assets: output a LINK tag for a file CSS asset.
|
||||
if (count($css_assets) <= 31) {
|
||||
$element = $link_element_defaults;
|
||||
$element['#attributes']['href'] = file_create_url($css_asset['data']) . $query_string_separator . $query_string;
|
||||
$element['#attributes']['href'] = file_url_transform_relative(file_create_url($css_asset['data'])) . $query_string_separator . $query_string;
|
||||
$element['#attributes']['media'] = $css_asset['media'];
|
||||
$element['#browsers'] = $css_asset['browsers'];
|
||||
$elements[] = $element;
|
||||
|
@ -148,7 +148,7 @@ class CssCollectionRenderer implements AssetCollectionRendererInterface {
|
|||
// LINK tag.
|
||||
if (!$css_asset['preprocess']) {
|
||||
$element = $link_element_defaults;
|
||||
$element['#attributes']['href'] = file_create_url($css_asset['data']) . $query_string_separator . $query_string;
|
||||
$element['#attributes']['href'] = file_url_transform_relative(file_create_url($css_asset['data'])) . $query_string_separator . $query_string;
|
||||
$element['#attributes']['media'] = $css_asset['media'];
|
||||
$element['#browsers'] = $css_asset['browsers'];
|
||||
$elements[] = $element;
|
||||
|
@ -168,7 +168,7 @@ class CssCollectionRenderer implements AssetCollectionRendererInterface {
|
|||
// control browser-caching. IE7 does not support a media type on
|
||||
// the @import statement, so we instead specify the media for
|
||||
// the group on the STYLE tag.
|
||||
$import[] = '@import url("' . Html::escape(file_create_url($next_css_asset['data']) . '?' . $query_string) . '");';
|
||||
$import[] = '@import url("' . Html::escape(file_url_transform_relative(file_create_url($next_css_asset['data'])) . '?' . $query_string) . '");';
|
||||
// Move the outer for loop skip the next item, since we
|
||||
// processed it here.
|
||||
$i = $j;
|
||||
|
|
|
@ -265,7 +265,7 @@ class CssOptimizer implements AssetOptimizerInterface {
|
|||
$last = $path;
|
||||
$path = preg_replace('`(^|/)(?!\.\./)([^/]+)/\.\./`', '$1', $path);
|
||||
}
|
||||
return 'url(' . file_create_url($path) . ')';
|
||||
return 'url(' . file_url_transform_relative(file_create_url($path)) . ')';
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -79,7 +79,7 @@ class JsCollectionRenderer implements AssetCollectionRendererInterface {
|
|||
case 'file':
|
||||
$query_string = $js_asset['version'] == -1 ? $default_query_string : 'v=' . $js_asset['version'];
|
||||
$query_string_separator = (strpos($js_asset['data'], '?') !== FALSE) ? '&' : '?';
|
||||
$element['#attributes']['src'] = file_create_url($js_asset['data']);
|
||||
$element['#attributes']['src'] = file_url_transform_relative(file_create_url($js_asset['data']));
|
||||
// Only add the cache-busting query string if this isn't an aggregate
|
||||
// file.
|
||||
if (!isset($js_asset['preprocessed'])) {
|
||||
|
|
|
@ -18,7 +18,7 @@ abstract class ConfigFactoryOverrideBase implements EventSubscriberInterface {
|
|||
* Reacts to the ConfigEvents::COLLECTION_INFO event.
|
||||
*
|
||||
* @param \Drupal\Core\Config\ConfigCollectionInfo $collection_info
|
||||
* The configuration collection names event.
|
||||
* The configuration collection info event.
|
||||
*/
|
||||
abstract public function addCollections(ConfigCollectionInfo $collection_info);
|
||||
|
||||
|
|
|
@ -39,16 +39,6 @@ abstract class ConfigEntityBase extends Entity implements ConfigEntityInterface
|
|||
*/
|
||||
protected $originalId;
|
||||
|
||||
/**
|
||||
* The name of the property that is used to store plugin configuration.
|
||||
*
|
||||
* This is needed when the entity uses a LazyPluginCollection, to dictate
|
||||
* where the plugin configuration should be stored.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $pluginConfigKey;
|
||||
|
||||
/**
|
||||
* The enabled/disabled status of the configuration entity.
|
||||
*
|
||||
|
|
|
@ -169,9 +169,6 @@ interface ConfigEntityInterface extends EntityInterface, ThirdPartySettingsInter
|
|||
* Dependency types are, for example, entity, module and theme.
|
||||
*
|
||||
* @return bool
|
||||
* TRUE if the entity has changed, FALSE if not.
|
||||
*
|
||||
* @return bool
|
||||
* TRUE if the entity has been changed as a result, FALSE if not.
|
||||
*
|
||||
* @see \Drupal\Core\Config\Entity\ConfigDependencyManager
|
||||
|
|
|
@ -95,12 +95,13 @@ class FileStorage implements StorageInterface {
|
|||
if (!$this->exists($name)) {
|
||||
return FALSE;
|
||||
}
|
||||
$data = file_get_contents($this->getFilePath($name));
|
||||
$filepath = $this->getFilePath($name);
|
||||
$data = file_get_contents($filepath);
|
||||
try {
|
||||
$data = $this->decode($data);
|
||||
}
|
||||
catch (InvalidDataTypeException $e) {
|
||||
throw new UnsupportedDataTypeConfigException("Invalid data type in config $name: {$e->getMessage()}");
|
||||
throw new UnsupportedDataTypeConfigException('Invalid data type in config ' . $name . ', found in file' . $filepath . ' : ' . $e->getMessage());
|
||||
}
|
||||
return $data;
|
||||
}
|
||||
|
|
|
@ -86,6 +86,7 @@ class TypedConfigManager extends TypedDataManager implements TypedConfigManagerI
|
|||
// Add default values for data type and replace variables.
|
||||
$definition += array('type' => 'undefined');
|
||||
|
||||
$replace = [];
|
||||
$type = $definition['type'];
|
||||
if (strpos($type, ']')) {
|
||||
// Replace variable names in definition.
|
||||
|
@ -102,7 +103,7 @@ class TypedConfigManager extends TypedDataManager implements TypedConfigManagerI
|
|||
unset($definition['type']);
|
||||
}
|
||||
// Add default values from type definition.
|
||||
$definition += $this->getDefinition($type);
|
||||
$definition += $this->_getDefinitionWithReplacements($type, $replace);
|
||||
|
||||
$data_definition = $this->createDataDefinition($definition['type']);
|
||||
|
||||
|
@ -116,10 +117,17 @@ class TypedConfigManager extends TypedDataManager implements TypedConfigManagerI
|
|||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* Determines the typed config type for a plugin ID.
|
||||
*
|
||||
* @param string $base_plugin_id
|
||||
* The plugin ID.
|
||||
* @param array $definitions
|
||||
* An array of typed config definitions.
|
||||
*
|
||||
* @return string
|
||||
* The typed config type for the given plugin ID.
|
||||
*/
|
||||
public function getDefinition($base_plugin_id, $exception_on_invalid = TRUE) {
|
||||
$definitions = $this->getDefinitions();
|
||||
protected function _determineType($base_plugin_id, array $definitions) {
|
||||
if (isset($definitions[$base_plugin_id])) {
|
||||
$type = $base_plugin_id;
|
||||
}
|
||||
|
@ -131,6 +139,27 @@ class TypedConfigManager extends TypedDataManager implements TypedConfigManagerI
|
|||
// If we don't have definition, return the 'undefined' element.
|
||||
$type = 'undefined';
|
||||
}
|
||||
return $type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a schema definition with replacements for dynamic names.
|
||||
*
|
||||
* @param string $base_plugin_id
|
||||
* A plugin ID.
|
||||
* @param array $replacements
|
||||
* An array of replacements for dynamic type names.
|
||||
* @param bool $exception_on_invalid
|
||||
* (optional) This parameter is passed along to self::getDefinition().
|
||||
* However, self::getDefinition() does not respect this parameter, so it is
|
||||
* effectively useless in this context.
|
||||
*
|
||||
* @return array
|
||||
* A schema definition array.
|
||||
*/
|
||||
protected function _getDefinitionWithReplacements($base_plugin_id, array $replacements, $exception_on_invalid = TRUE) {
|
||||
$definitions = $this->getDefinitions();
|
||||
$type = $this->_determineType($base_plugin_id, $definitions);
|
||||
$definition = $definitions[$type];
|
||||
// Check whether this type is an extension of another one and compile it.
|
||||
if (isset($definition['type'])) {
|
||||
|
@ -138,6 +167,15 @@ class TypedConfigManager extends TypedDataManager implements TypedConfigManagerI
|
|||
// Preserve integer keys on merge, so sequence item types can override
|
||||
// parent settings as opposed to adding unused second, third, etc. items.
|
||||
$definition = NestedArray::mergeDeepArray(array($merge, $definition), TRUE);
|
||||
|
||||
// Replace dynamic portions of the definition type.
|
||||
if (!empty($replacements) && strpos($definition['type'], ']')) {
|
||||
$sub_type = $this->_determineType($this->replaceName($definition['type'], $replacements), $definitions);
|
||||
// Merge the newly determined subtype definition with the original
|
||||
// definition.
|
||||
$definition = NestedArray::mergeDeepArray([$definitions[$sub_type], $definition], TRUE);
|
||||
}
|
||||
|
||||
// Unset type so we try the merge only once per type.
|
||||
unset($definition['type']);
|
||||
$this->definitions[$type] = $definition;
|
||||
|
@ -150,6 +188,13 @@ class TypedConfigManager extends TypedDataManager implements TypedConfigManagerI
|
|||
return $definition;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getDefinition($base_plugin_id, $exception_on_invalid = TRUE) {
|
||||
return $this->_getDefinitionWithReplacements($base_plugin_id, [], $exception_on_invalid);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
|
|
|
@ -64,10 +64,9 @@ class PagerSelectExtender extends SelectExtender {
|
|||
* to it.
|
||||
*/
|
||||
public function execute() {
|
||||
|
||||
// Add convenience tag to mark that this is an extended query. We have to
|
||||
// do this in the constructor to ensure that it is set before preExecute()
|
||||
// gets called.
|
||||
// By calling preExecute() here, we force it to preprocess the extender
|
||||
// object rather than just the base query object. That means
|
||||
// hook_query_alter() gets access to the extended object.
|
||||
if (!$this->preExecute($this)) {
|
||||
return NULL;
|
||||
}
|
||||
|
|
|
@ -968,11 +968,13 @@ class DrupalKernel implements DrupalKernelInterface, TerminableInterface {
|
|||
}
|
||||
}
|
||||
|
||||
// If the class loader is still the same, possibly upgrade to the APCu class
|
||||
// If the class loader is still the same, possibly upgrade to the APC class
|
||||
// loader.
|
||||
// ApcClassLoader does not support APCu without backwards compatibility
|
||||
// enabled.
|
||||
if ($class_loader_class == get_class($this->classLoader)
|
||||
&& Settings::get('class_loader_auto_detect', TRUE)
|
||||
&& function_exists('apcu_fetch')) {
|
||||
&& extension_loaded('apc')) {
|
||||
$prefix = Settings::getApcuPrefix('class_loader', $this->root);
|
||||
$apc_loader = new \Symfony\Component\ClassLoader\ApcClassLoader($prefix, $this->classLoader);
|
||||
$this->classLoader->unregister();
|
||||
|
|
|
@ -440,7 +440,8 @@ abstract class ContentEntityStorageBase extends EntityStorageBase implements Con
|
|||
protected function invokeFieldMethod($method, ContentEntityInterface $entity) {
|
||||
$result = [];
|
||||
$args = array_slice(func_get_args(), 2);
|
||||
foreach (array_keys($entity->getTranslationLanguages()) as $langcode) {
|
||||
$langcodes = array_keys($entity->getTranslationLanguages());
|
||||
foreach ($langcodes as $langcode) {
|
||||
$translation = $entity->getTranslation($langcode);
|
||||
// For non translatable fields, there is only one field object instance
|
||||
// across all translations and it has as parent entity the entity in the
|
||||
|
@ -453,6 +454,20 @@ abstract class ContentEntityStorageBase extends EntityStorageBase implements Con
|
|||
$result[$langcode][$name] = $args ? call_user_func_array([$items, $method], $args) : $items->{$method}();
|
||||
}
|
||||
}
|
||||
|
||||
// We need to call the delete method for field items of removed
|
||||
// translations.
|
||||
if ($method == 'postSave' && !empty($entity->original)) {
|
||||
$original_langcodes = array_keys($entity->original->getTranslationLanguages());
|
||||
foreach (array_diff($original_langcodes, $langcodes) as $removed_langcode) {
|
||||
$translation = $entity->original->getTranslation($removed_langcode);
|
||||
$fields = $translation->getTranslatableFields();
|
||||
foreach ($fields as $name => $items) {
|
||||
$items->delete();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
|
|
|
@ -330,11 +330,11 @@ class EntityAutocomplete extends Textfield {
|
|||
|
||||
// Take "label (entity id)', match the ID from parenthesis when it's a
|
||||
// number.
|
||||
if (preg_match("/.+\((\d+)\)/", $input, $matches)) {
|
||||
if (preg_match("/.+\s\((\d+)\)/", $input, $matches)) {
|
||||
$match = $matches[1];
|
||||
}
|
||||
// Match the ID when it's a string (e.g. for config entity types).
|
||||
elseif (preg_match("/.+\(([\w.]+)\)/", $input, $matches)) {
|
||||
elseif (preg_match("/.+\s\(([\w.]+)\)/", $input, $matches)) {
|
||||
$match = $matches[1];
|
||||
}
|
||||
|
||||
|
|
|
@ -83,8 +83,11 @@ class AuthenticationSubscriber implements EventSubscriberInterface {
|
|||
$account = $this->authenticationProvider->authenticate($request);
|
||||
if ($account) {
|
||||
$this->accountProxy->setAccount($account);
|
||||
return;
|
||||
}
|
||||
}
|
||||
// No account has been set explicitly, initialize the timezone here.
|
||||
date_default_timezone_set(drupal_get_user_timezone());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -237,7 +237,9 @@ interface ModuleHandlerInterface {
|
|||
*
|
||||
* @return array
|
||||
* An array of return values of the hook implementations. If modules return
|
||||
* arrays from their implementations, those are merged into one array.
|
||||
* arrays from their implementations, those are merged into one array
|
||||
* recursively. Note: integer keys in arrays will be lost, as the merge is
|
||||
* done using array_merge_recursive().
|
||||
*/
|
||||
public function invokeAll($hook, array $args = array());
|
||||
|
||||
|
|
|
@ -70,7 +70,7 @@ abstract class FieldItemBase extends Map implements FieldItemInterface {
|
|||
* {@inheritdoc}
|
||||
*/
|
||||
public function getLangcode() {
|
||||
return $this->parent->getLangcode();
|
||||
return $this->getParent()->getLangcode();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -102,28 +102,28 @@ interface FieldItemListInterface extends ListInterface, AccessibleInterface {
|
|||
/**
|
||||
* Magic method: Gets a property value of to the first field item.
|
||||
*
|
||||
* @see \Drupal\Core\Field\FieldItemInterface::__get()
|
||||
* @see \Drupal\Core\Field\FieldItemInterface::__set()
|
||||
*/
|
||||
public function __get($property_name);
|
||||
|
||||
/**
|
||||
* Magic method: Sets a property value of the first field item.
|
||||
*
|
||||
* @see \Drupal\Core\Field\FieldItemInterface::__set()
|
||||
* @see \Drupal\Core\Field\FieldItemInterface::__get()
|
||||
*/
|
||||
public function __set($property_name, $value);
|
||||
|
||||
/**
|
||||
* Magic method: Determines whether a property of the first field item is set.
|
||||
*
|
||||
* @see \Drupal\Core\Field\FieldItemInterface::__isset()
|
||||
* @see \Drupal\Core\Field\FieldItemInterface::__unset()
|
||||
*/
|
||||
public function __isset($property_name);
|
||||
|
||||
/**
|
||||
* Magic method: Unsets a property of the first field item.
|
||||
*
|
||||
* @see \Drupal\Core\Field\FieldItemInterface::__unset()
|
||||
* @see \Drupal\Core\Field\FieldItemInterface::__isset()
|
||||
*/
|
||||
public function __unset($property_name);
|
||||
|
||||
|
|
|
@ -83,6 +83,7 @@ class BooleanFormatter extends FormatterBase {
|
|||
}
|
||||
}
|
||||
|
||||
$field_name = $this->fieldDefinition->getName();
|
||||
$form['format'] = [
|
||||
'#type' => 'select',
|
||||
'#title' => $this->t('Output format'),
|
||||
|
@ -95,7 +96,7 @@ class BooleanFormatter extends FormatterBase {
|
|||
'#default_value' => $this->getSetting('format_custom_true'),
|
||||
'#states' => [
|
||||
'visible' => [
|
||||
'select[name="fields[field_boolean][settings_edit_form][settings][format]"]' => ['value' => 'custom'],
|
||||
'select[name="fields[' . $field_name . '][settings_edit_form][settings][format]"]' => ['value' => 'custom'],
|
||||
],
|
||||
],
|
||||
];
|
||||
|
@ -105,7 +106,7 @@ class BooleanFormatter extends FormatterBase {
|
|||
'#default_value' => $this->getSetting('format_custom_false'),
|
||||
'#states' => [
|
||||
'visible' => [
|
||||
'select[name="fields[field_boolean][settings_edit_form][settings][format]"]' => ['value' => 'custom'],
|
||||
'select[name="fields[' . $field_name . '][settings_edit_form][settings][format]"]' => ['value' => 'custom'],
|
||||
],
|
||||
],
|
||||
];
|
||||
|
|
|
@ -55,7 +55,7 @@ class DecimalFormatter extends NumericFormatterBase {
|
|||
$range = range(0, 10);
|
||||
$elements['scale'] = array(
|
||||
'#type' => 'select',
|
||||
'#title' => t('Scale', array(), array('decimal places')),
|
||||
'#title' => t('Scale', array(), array('context' => 'decimal places')),
|
||||
'#options' => array_combine($range, $range),
|
||||
'#default_value' => $this->getSetting('scale'),
|
||||
'#description' => t('The number of digits to the right of the decimal.'),
|
||||
|
|
|
@ -131,7 +131,7 @@ class TimestampFormatter extends FormatterBase implements ContainerFactoryPlugin
|
|||
);
|
||||
|
||||
$elements['custom_date_format']['#states']['visible'][] = array(
|
||||
':input[name="options[settings][date_format]"]' => array('value' => 'custom'),
|
||||
':input[name="name="fields[' . $this->fieldDefinition->getName() . '][settings_edit_form][settings][date_format]"]' => array('value' => 'custom'),
|
||||
);
|
||||
|
||||
$elements['timezone'] = array(
|
||||
|
|
|
@ -81,7 +81,7 @@ class DecimalItem extends NumericItemBase {
|
|||
$range = range(0, 10);
|
||||
$element['scale'] = array(
|
||||
'#type' => 'select',
|
||||
'#title' => t('Scale', array(), array('decimal places')),
|
||||
'#title' => t('Scale', array(), array('context' => 'decimal places')),
|
||||
'#options' => array_combine($range, $range),
|
||||
'#default_value' => $settings['scale'],
|
||||
'#description' => t('The number of digits to the right of the decimal.'),
|
||||
|
|
|
@ -62,6 +62,9 @@ class PasswordItem extends StringItem {
|
|||
$this->value = $entity->original->{$this->getFieldDefinition()->getName()}->value;
|
||||
}
|
||||
}
|
||||
// Ensure that the existing password is unset to minimise risks of it
|
||||
// getting serialized and stored somewhere.
|
||||
$this->existing = NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -75,7 +75,7 @@ interface WidgetBaseInterface extends PluginSettingsInterface {
|
|||
/**
|
||||
* Retrieves processing information about the widget from $form_state.
|
||||
*
|
||||
* This method is static so that is can be used in static Form API callbacks.
|
||||
* This method is static so that it can be used in static Form API callbacks.
|
||||
*
|
||||
* @param array $parents
|
||||
* The array of #parents where the field lives in the form.
|
||||
|
@ -95,7 +95,7 @@ interface WidgetBaseInterface extends PluginSettingsInterface {
|
|||
/**
|
||||
* Stores processing information about the widget in $form_state.
|
||||
*
|
||||
* This method is static so that is can be used in static Form API #callbacks.
|
||||
* This method is static so that it can be used in static Form API #callbacks.
|
||||
*
|
||||
* @param array $parents
|
||||
* The array of #parents where the widget lives in the form.
|
||||
|
|
|
@ -146,8 +146,6 @@ function callback_batch_finished($success, $results, $operations) {
|
|||
*
|
||||
* @param \Drupal\Core\Ajax\CommandInterface[] $data
|
||||
* An array of all the rendered commands that will be sent to the client.
|
||||
*
|
||||
* @see \Drupal\Core\Ajax\AjaxResponse::ajaxRender()
|
||||
*/
|
||||
function hook_ajax_render_alter(array &$data) {
|
||||
// Inject any new status messages into the content area.
|
||||
|
|
|
@ -253,6 +253,7 @@ class LanguageManager implements LanguageManagerInterface {
|
|||
'dz' => array('Dzongkha', 'རྫོང་ཁ'),
|
||||
'el' => array('Greek', 'Ελληνικά'),
|
||||
'en' => array('English', 'English'),
|
||||
'en-x-simple' => array('Simple English', 'Simple English'),
|
||||
'eo' => array('Esperanto', 'Esperanto'),
|
||||
'es' => array('Spanish', 'Español'),
|
||||
'et' => array('Estonian', 'Eesti'),
|
||||
|
|
|
@ -93,9 +93,17 @@ class LoggerChannel implements LoggerChannelInterface {
|
|||
$context['request_uri'] = $request->getUri();
|
||||
$context['referer'] = $request->headers->get('Referer', '');
|
||||
$context['ip'] = $request->getClientIP();
|
||||
if ($this->currentUser) {
|
||||
$context['user'] = $this->currentUser;
|
||||
$context['uid'] = $this->currentUser->id();
|
||||
try {
|
||||
if ($this->currentUser) {
|
||||
$context['user'] = $this->currentUser;
|
||||
$context['uid'] = $this->currentUser->id();
|
||||
}
|
||||
}
|
||||
catch (\Exception $e) {
|
||||
// An exception might be thrown if the database connection is not
|
||||
// available or due to another unexpected reason. It is more important
|
||||
// to log the error that we already have so any additional exceptions
|
||||
// are ignored.
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -23,10 +23,7 @@ interface LoggerChannelFactoryInterface {
|
|||
public function get($channel);
|
||||
|
||||
/**
|
||||
* Adds a logger.
|
||||
*
|
||||
* Here is were all services tagged as 'logger' are being retrieved and then
|
||||
* passed to the channels after instantiation.
|
||||
* Adds a logger to all the channels.
|
||||
*
|
||||
* @param \Psr\Log\LoggerInterface $logger
|
||||
* The PSR-3 logger to add.
|
||||
|
|
|
@ -8,6 +8,9 @@
|
|||
namespace Drupal\Core\Menu;
|
||||
|
||||
use Drupal\Core\Access\AccessManagerInterface;
|
||||
use Drupal\Core\Cache\Cache;
|
||||
use Drupal\Core\Cache\CacheableDependencyInterface;
|
||||
use Drupal\Core\Cache\CacheableMetadata;
|
||||
use Drupal\Core\Cache\CacheBackendInterface;
|
||||
use Drupal\Core\Extension\ModuleHandlerInterface;
|
||||
use Drupal\Core\Language\LanguageManagerInterface;
|
||||
|
@ -182,8 +185,10 @@ class LocalActionManager extends DefaultPluginManager implements LocalActionMana
|
|||
$links = array();
|
||||
/** @var $plugin \Drupal\Core\Menu\LocalActionInterface */
|
||||
foreach ($this->instances[$route_appears] as $plugin_id => $plugin) {
|
||||
$cacheability = new CacheableMetadata();
|
||||
$route_name = $plugin->getRouteName();
|
||||
$route_parameters = $plugin->getRouteParameters($this->routeMatch);
|
||||
$access = $this->accessManager->checkNamedRoute($route_name, $route_parameters, $this->account, TRUE);
|
||||
$links[$plugin_id] = array(
|
||||
'#theme' => 'menu_local_action',
|
||||
'#link' => array(
|
||||
|
@ -191,10 +196,22 @@ class LocalActionManager extends DefaultPluginManager implements LocalActionMana
|
|||
'url' => Url::fromRoute($route_name, $route_parameters),
|
||||
'localized_options' => $plugin->getOptions($this->routeMatch),
|
||||
),
|
||||
'#access' => $this->accessManager->checkNamedRoute($route_name, $route_parameters, $this->account, TRUE),
|
||||
'#access' => $access,
|
||||
'#weight' => $plugin->getWeight(),
|
||||
);
|
||||
$cacheability->addCacheableDependency($access);
|
||||
// For backward compatibility in 8.0.x, plugins that do not implement
|
||||
// the \Drupal\Core\Cache\CacheableDependencyInterface are assumed
|
||||
// to be cacheable forever.
|
||||
if ($plugin instanceof CacheableDependencyInterface) {
|
||||
$cacheability->addCacheableDependency($plugin);
|
||||
}
|
||||
else {
|
||||
$cacheability->setCacheMaxAge(Cache::PERMANENT);
|
||||
}
|
||||
$cacheability->applyTo($links[$plugin_id]);
|
||||
}
|
||||
$links['#cache']['contexts'][] = 'route';
|
||||
|
||||
return $links;
|
||||
}
|
||||
|
|
|
@ -8,7 +8,6 @@
|
|||
namespace Drupal\Core\Menu\Plugin\Block;
|
||||
|
||||
use Drupal\Core\Block\BlockBase;
|
||||
use Drupal\Core\Cache\Cache;
|
||||
use Drupal\Core\Menu\LocalActionManagerInterface;
|
||||
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
|
@ -84,18 +83,8 @@ class LocalActionsBlock extends BlockBase implements ContainerFactoryPluginInter
|
|||
public function build() {
|
||||
$route_name = $this->routeMatch->getRouteName();
|
||||
$local_actions = $this->localActionManager->getActionsForRoute($route_name);
|
||||
if (empty($local_actions)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return $local_actions;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getCacheContexts() {
|
||||
return Cache::mergeContexts(parent::getCacheContexts(), ['route']);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -75,7 +75,7 @@ class ImageButton extends Submit {
|
|||
$element['#attributes']['type'] = 'image';
|
||||
Element::setAttributes($element, array('id', 'name', 'value'));
|
||||
|
||||
$element['#attributes']['src'] = file_create_url($element['#src']);
|
||||
$element['#attributes']['src'] = file_url_transform_relative(file_create_url($element['#src']));
|
||||
if (!empty($element['#title'])) {
|
||||
$element['#attributes']['alt'] = $element['#title'];
|
||||
$element['#attributes']['title'] = $element['#title'];
|
||||
|
|
|
@ -22,8 +22,8 @@ use Drupal\Component\Utility\Html as HtmlUtility;
|
|||
* $form['settings']['active'] = array(
|
||||
* '#type' => 'radios',
|
||||
* '#title' => t('Poll status'),
|
||||
* '#default_value' => 1
|
||||
* '#options' => array(0 => t('Closed'), 1 => t('Active'),
|
||||
* '#default_value' => 1,
|
||||
* '#options' => array(0 => t('Closed'), 1 => t('Active')),
|
||||
* );
|
||||
* @endcode
|
||||
*
|
||||
|
|
|
@ -34,7 +34,7 @@ use Drupal\Component\Utility\Html as HtmlUtility;
|
|||
* @code
|
||||
* $form['contacts'] = array(
|
||||
* '#type' => 'table',
|
||||
* '#title' => 'Sample Table',
|
||||
* '#caption' => 'Sample Table',
|
||||
* '#header' => array('Name', 'Phone'),
|
||||
* );
|
||||
*
|
||||
|
|
|
@ -16,7 +16,7 @@ use Drupal\Core\StringTranslation\TranslatableMarkup;
|
|||
* Provides a form element for a table with radios or checkboxes in left column.
|
||||
*
|
||||
* Properties:
|
||||
* - #headers: Table headers used in the table.
|
||||
* - #header: Table headers used in the table.
|
||||
* - #options: An associative array where each key is the value returned when
|
||||
* a user selects the radio button or checkbox, and each value is the row of
|
||||
* table data.
|
||||
|
|
|
@ -56,7 +56,7 @@ class AccountProxy implements AccountProxyInterface {
|
|||
// After the container is rebuilt, DrupalKernel sets the initial
|
||||
// account to the id of the logged in user. This is necessary in order
|
||||
// to refresh the user account reference here.
|
||||
$this->account = $this->loadUserEntity($this->initialAccountId);
|
||||
$this->setAccount($this->loadUserEntity($this->initialAccountId));
|
||||
}
|
||||
else {
|
||||
$this->account = new AnonymousUserSession();
|
||||
|
|
|
@ -135,7 +135,9 @@ class TwigExtension extends \Twig_Extension {
|
|||
new \Twig_SimpleFunction('url', array($this, 'getUrl'), array('is_safe_callback' => array($this, 'isUrlGenerationSafe'))),
|
||||
new \Twig_SimpleFunction('path', array($this, 'getPath'), array('is_safe_callback' => array($this, 'isUrlGenerationSafe'))),
|
||||
new \Twig_SimpleFunction('link', array($this, 'getLink')),
|
||||
new \Twig_SimpleFunction('file_url', 'file_create_url'),
|
||||
new \Twig_SimpleFunction('file_url', function ($uri) {
|
||||
return file_url_transform_relative(file_create_url($uri));
|
||||
}),
|
||||
new \Twig_SimpleFunction('attach_library', [$this, 'attachLibrary']),
|
||||
new \Twig_SimpleFunction('active_theme_path', [$this, 'getActiveThemePath']),
|
||||
new \Twig_SimpleFunction('active_theme', [$this, 'getActiveTheme']),
|
||||
|
|
|
@ -318,7 +318,6 @@ class ThemeInitialization implements ThemeInitializationInterface {
|
|||
$stylesheets_remove = array();
|
||||
// Grab stylesheets from base theme.
|
||||
foreach ($base_themes as $base) {
|
||||
$base_theme_path = $base->getPath();
|
||||
if (!empty($base->info['stylesheets-remove'])) {
|
||||
foreach ($base->info['stylesheets-remove'] as $css_file) {
|
||||
$css_file = $this->resolveStyleSheetPlaceholders($css_file);
|
||||
|
|
|
@ -293,6 +293,11 @@ class Url {
|
|||
* @see \Drupal\Core\Url::fromUserInput()
|
||||
*/
|
||||
public static function fromUri($uri, $options = []) {
|
||||
// parse_url() incorrectly parses base:number/... as hostname:port/...
|
||||
// and not the scheme. Prevent that by prefixing the path with a slash.
|
||||
if (preg_match('/^base:\d/', $uri)) {
|
||||
$uri = str_replace('base:', 'base:/', $uri);
|
||||
}
|
||||
$uri_parts = parse_url($uri);
|
||||
if ($uri_parts === FALSE) {
|
||||
throw new \InvalidArgumentException("The URI '$uri' is malformed.");
|
||||
|
|
Reference in a new issue