Update to Drupal 8.0.5. For more information, see https://www.drupal.org/node/2679347
This commit is contained in:
parent
2a9f1f148d
commit
fd3b12cf27
251 changed files with 5439 additions and 957 deletions
|
@ -43,7 +43,7 @@ class InsertCommand implements CommandInterface, CommandWithAttachedAssetsInterf
|
|||
protected $content;
|
||||
|
||||
/**
|
||||
* A settings array to be passed to any any attached JavaScript behavior.
|
||||
* A settings array to be passed to any attached JavaScript behavior.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
|
|
|
@ -11,8 +11,8 @@ namespace Drupal\Core\Ajax;
|
|||
* AJAX command for calling the jQuery replace() method.
|
||||
*
|
||||
* The 'insert/replaceWith' command instructs the client to use jQuery's
|
||||
* replaceWith() method to replace each element matched matched by the given
|
||||
* selector with the given HTML.
|
||||
* replaceWith() method to replace each element matched by the given selector
|
||||
* with the given HTML.
|
||||
*
|
||||
* This command is implemented by Drupal.AjaxCommands.prototype.insert()
|
||||
* defined in misc/ajax.js.
|
||||
|
|
|
@ -14,7 +14,7 @@ use Symfony\Component\HttpFoundation\Request;
|
|||
*
|
||||
* Some authentication methods should not be available throughout a whole site.
|
||||
* For instance, there are good reasons to restrict insecure methods like HTTP
|
||||
* basic authentication or an URL token authentication method to API-only
|
||||
* basic authentication or a URL token authentication method to API-only
|
||||
* routes.
|
||||
*/
|
||||
interface AuthenticationProviderFilterInterface {
|
||||
|
|
|
@ -375,8 +375,12 @@ class DbDumpCommand extends DbCommandBase {
|
|||
* The template for the generated PHP script.
|
||||
*/
|
||||
protected function getTemplate() {
|
||||
// The template contains an instruction for the file to be ignored by PHPCS.
|
||||
// This is because the files can be huge and coding standards are
|
||||
// irrelevant.
|
||||
$script = <<<'ENDOFSCRIPT'
|
||||
<?php
|
||||
// @codingStandardsIgnoreFile
|
||||
/**
|
||||
* @file
|
||||
* A database agnostic dump for testing purposes.
|
||||
|
|
|
@ -302,7 +302,7 @@ class ConfigManager implements ConfigManagerInterface {
|
|||
$dependency_manager = $this->getConfigDependencyManager();
|
||||
$dependents = $this->findConfigEntityDependentsAsEntities($type, $names, $dependency_manager);
|
||||
$original_dependencies = $dependents;
|
||||
$update_uuids = [];
|
||||
$delete_uuids = $update_uuids = [];
|
||||
|
||||
$return = [
|
||||
'update' => [],
|
||||
|
@ -311,26 +311,35 @@ class ConfigManager implements ConfigManagerInterface {
|
|||
];
|
||||
|
||||
// Try to fix any dependencies and find out what will happen to the
|
||||
// dependency graph.
|
||||
foreach ($dependents as $dependent) {
|
||||
// dependency graph. Entities are processed in the order of most dependent
|
||||
// first. For example, this ensures that fields are removed before
|
||||
// field storages.
|
||||
while ($dependent = array_pop($dependents)) {
|
||||
/** @var \Drupal\Core\Config\Entity\ConfigEntityInterface $dependent */
|
||||
if ($dry_run) {
|
||||
// Clone the entity so any changes do not change any static caches.
|
||||
$dependent = clone $dependent;
|
||||
}
|
||||
$fixed = FALSE;
|
||||
if ($this->callOnDependencyRemoval($dependent, $original_dependencies, $type, $names)) {
|
||||
// Recalculate dependencies and update the dependency graph data.
|
||||
$dependent->calculateDependencies();
|
||||
$dependency_manager->updateData($dependent->getConfigDependencyName(), $dependent->getDependencies());
|
||||
// Based on the updated data rebuild the list of dependents.
|
||||
// Based on the updated data rebuild the list of dependents. This will
|
||||
// remove entities that are no longer dependent after the recalculation.
|
||||
$dependents = $this->findConfigEntityDependentsAsEntities($type, $names, $dependency_manager);
|
||||
// Remove any entities that we've already marked for deletion.
|
||||
$dependents = array_filter($dependents, function ($dependent) use ($delete_uuids) {
|
||||
return !in_array($dependent->uuid(), $delete_uuids);
|
||||
});
|
||||
// Ensure that the dependency has actually been fixed. It is possible
|
||||
// that the dependent has multiple dependencies that cause it to be in
|
||||
// the dependency chain.
|
||||
$fixed = TRUE;
|
||||
foreach ($dependents as $entity) {
|
||||
foreach ($dependents as $key => $entity) {
|
||||
if ($entity->uuid() == $dependent->uuid()) {
|
||||
$fixed = FALSE;
|
||||
unset($dependents[$key]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -339,15 +348,12 @@ class ConfigManager implements ConfigManagerInterface {
|
|||
$update_uuids[] = $dependent->uuid();
|
||||
}
|
||||
}
|
||||
// If the entity cannot be fixed then it has to be deleted.
|
||||
if (!$fixed) {
|
||||
$delete_uuids[] = $dependent->uuid();
|
||||
$return['delete'][] = $dependent;
|
||||
}
|
||||
}
|
||||
// Now that we've fixed all the possible dependencies the remaining need to
|
||||
// be deleted. Reverse the deletes so that entities are removed in the
|
||||
// correct order of dependence. For example, this ensures that fields are
|
||||
// removed before field storages.
|
||||
$return['delete'] = array_reverse($dependents);
|
||||
$delete_uuids = array_map(function($dependent) {
|
||||
return $dependent->uuid();
|
||||
}, $return['delete']);
|
||||
// Use the lists of UUIDs to filter the original list to work out which
|
||||
// configuration entities are unchanged.
|
||||
$return['unchanged'] = array_filter($original_dependencies, function ($dependent) use ($delete_uuids, $update_uuids) {
|
||||
|
|
|
@ -352,6 +352,32 @@ abstract class ConfigEntityBase extends Entity implements ConfigEntityInterface
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function __sleep() {
|
||||
$keys_to_unset = [];
|
||||
if ($this instanceof EntityWithPluginCollectionInterface) {
|
||||
$vars = get_object_vars($this);
|
||||
foreach ($this->getPluginCollections() as $plugin_config_key => $plugin_collection) {
|
||||
// Save any changes to the plugin configuration to the entity.
|
||||
$this->set($plugin_config_key, $plugin_collection->getConfiguration());
|
||||
// If the plugin collections are stored as properties on the entity,
|
||||
// mark them to be unset.
|
||||
$keys_to_unset += array_filter($vars, function ($value) use ($plugin_collection) {
|
||||
return $plugin_collection === $value;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
$vars = parent::__sleep();
|
||||
|
||||
if (!empty($keys_to_unset)) {
|
||||
$vars = array_diff($vars, array_keys($keys_to_unset));
|
||||
}
|
||||
return $vars;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
|
|
|
@ -207,8 +207,9 @@ class FileStorage implements StorageInterface {
|
|||
$files = scandir($dir);
|
||||
|
||||
$names = array();
|
||||
$pattern = '/^' . preg_quote($prefix, '/') . '.*' . preg_quote($extension, '/') . '$/';
|
||||
foreach ($files as $file) {
|
||||
if ($file[0] !== '.' && fnmatch($prefix . '*' . $extension, $file)) {
|
||||
if ($file[0] !== '.' && preg_match($pattern, $file)) {
|
||||
$names[] = basename($file, $extension);
|
||||
}
|
||||
}
|
||||
|
@ -290,6 +291,7 @@ class FileStorage implements StorageInterface {
|
|||
*/
|
||||
protected function getAllCollectionNamesHelper($directory) {
|
||||
$collections = array();
|
||||
$pattern = '/\.' . preg_quote($this->getFileExtension(), '/') . '$/';
|
||||
foreach (new \DirectoryIterator($directory) as $fileinfo) {
|
||||
if ($fileinfo->isDir() && !$fileinfo->isDot()) {
|
||||
$collection = $fileinfo->getFilename();
|
||||
|
@ -309,7 +311,7 @@ class FileStorage implements StorageInterface {
|
|||
// collection.
|
||||
// @see \Drupal\Core\Config\FileStorage::listAll()
|
||||
foreach (scandir($directory . '/' . $collection) as $file) {
|
||||
if ($file[0] !== '.' && fnmatch('*.' . $this->getFileExtension(), $file)) {
|
||||
if ($file[0] !== '.' && preg_match($pattern, $file)) {
|
||||
$collections[] = $collection;
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -190,6 +190,7 @@ class InstallStorage extends FileStorage {
|
|||
*/
|
||||
public function getComponentNames(array $list) {
|
||||
$extension = '.' . $this->getFileExtension();
|
||||
$pattern = '/' . preg_quote($extension, '/') . '$/';
|
||||
$folders = array();
|
||||
foreach ($list as $extension_object) {
|
||||
// We don't have to use ExtensionDiscovery here because our list of
|
||||
|
@ -203,7 +204,7 @@ class InstallStorage extends FileStorage {
|
|||
$files = scandir($directory);
|
||||
|
||||
foreach ($files as $file) {
|
||||
if ($file[0] !== '.' && fnmatch('*' . $extension, $file)) {
|
||||
if ($file[0] !== '.' && preg_match($pattern, $file)) {
|
||||
$folders[basename($file, $extension)] = $directory;
|
||||
}
|
||||
}
|
||||
|
@ -220,6 +221,7 @@ class InstallStorage extends FileStorage {
|
|||
*/
|
||||
public function getCoreNames() {
|
||||
$extension = '.' . $this->getFileExtension();
|
||||
$pattern = '/' . preg_quote($extension, '/') . '$/';
|
||||
$folders = array();
|
||||
$directory = $this->getCoreFolder();
|
||||
if (is_dir($directory)) {
|
||||
|
@ -230,7 +232,7 @@ class InstallStorage extends FileStorage {
|
|||
$files = scandir($directory);
|
||||
|
||||
foreach ($files as $file) {
|
||||
if ($file[0] !== '.' && fnmatch('*' . $extension, $file)) {
|
||||
if ($file[0] !== '.' && preg_match($pattern, $file)) {
|
||||
$folders[basename($file, $extension)] = $directory;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -138,7 +138,38 @@ class Connection extends DatabaseConnection {
|
|||
}
|
||||
}
|
||||
|
||||
return parent::query($query, $args, $options);
|
||||
// We need to wrap queries with a savepoint if:
|
||||
// - Currently in a transaction.
|
||||
// - A 'mimic_implicit_commit' does not exist already.
|
||||
// - The query is not a savepoint query.
|
||||
$wrap_with_savepoint = $this->inTransaction() &&
|
||||
!isset($this->transactionLayers['mimic_implicit_commit']) &&
|
||||
!(is_string($query) && (
|
||||
stripos($query, 'ROLLBACK TO SAVEPOINT ') === 0 ||
|
||||
stripos($query, 'RELEASE SAVEPOINT ') === 0 ||
|
||||
stripos($query, 'SAVEPOINT ') === 0
|
||||
)
|
||||
);
|
||||
if ($wrap_with_savepoint) {
|
||||
// Create a savepoint so we can rollback a failed query. This is so we can
|
||||
// mimic MySQL and SQLite transactions which don't fail if a single query
|
||||
// fails. This is important for tables that are created on demand. For
|
||||
// example, \Drupal\Core\Cache\DatabaseBackend.
|
||||
$this->addSavepoint();
|
||||
try {
|
||||
$return = parent::query($query, $args, $options);
|
||||
$this->releaseSavepoint();
|
||||
}
|
||||
catch (\Exception $e) {
|
||||
$this->rollbackSavepoint();
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
else {
|
||||
$return = parent::query($query, $args, $options);
|
||||
}
|
||||
|
||||
return $return;
|
||||
}
|
||||
|
||||
public function prepareQuery($query) {
|
||||
|
|
|
@ -99,12 +99,25 @@ class Insert extends QueryInsert {
|
|||
elseif ($options['return'] == Database::RETURN_INSERT_ID) {
|
||||
$options['return'] = Database::RETURN_NULL;
|
||||
}
|
||||
// Only use the returned last_insert_id if it is not already set.
|
||||
if (!empty($last_insert_id)) {
|
||||
$this->connection->query($stmt, array(), $options);
|
||||
|
||||
// Create a savepoint so we can rollback a failed query. This is so we can
|
||||
// mimic MySQL and SQLite transactions which don't fail if a single query
|
||||
// fails. This is important for tables that are created on demand. For
|
||||
// example, \Drupal\Core\Cache\DatabaseBackend.
|
||||
$this->connection->addSavepoint();
|
||||
try {
|
||||
// Only use the returned last_insert_id if it is not already set.
|
||||
if (!empty($last_insert_id)) {
|
||||
$this->connection->query($stmt, array(), $options);
|
||||
}
|
||||
else {
|
||||
$last_insert_id = $this->connection->query($stmt, array(), $options);
|
||||
}
|
||||
$this->connection->releaseSavepoint();
|
||||
}
|
||||
else {
|
||||
$last_insert_id = $this->connection->query($stmt, array(), $options);
|
||||
catch (\Exception $e) {
|
||||
$this->connection->rollbackSavepoint();
|
||||
throw $e;
|
||||
}
|
||||
|
||||
// Re-initialize the values array so that we can re-use this query.
|
||||
|
|
|
@ -76,11 +76,23 @@ class NativeUpsert extends QueryUpsert {
|
|||
$options['sequence_name'] = $table_information->sequences[0];
|
||||
}
|
||||
|
||||
$this->connection->query($stmt, [], $options);
|
||||
|
||||
// Re-initialize the values array so that we can re-use this query.
|
||||
$this->insertValues = [];
|
||||
|
||||
// Create a savepoint so we can rollback a failed query. This is so we can
|
||||
// mimic MySQL and SQLite transactions which don't fail if a single query
|
||||
// fails. This is important for tables that are created on demand. For
|
||||
// example, \Drupal\Core\Cache\DatabaseBackend.
|
||||
$this->connection->addSavepoint();
|
||||
try {
|
||||
$this->connection->query($stmt, [], $options);
|
||||
$this->connection->releaseSavepoint();
|
||||
}
|
||||
catch (\Exception $e) {
|
||||
$this->connection->rollbackSavepoint();
|
||||
throw $e;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
|
|
@ -765,7 +765,7 @@ class DrupalKernel implements DrupalKernelInterface, TerminableInterface {
|
|||
* The cache key used for the service container.
|
||||
*/
|
||||
protected function getContainerCacheKey() {
|
||||
$parts = array('service_container', $this->environment, \Drupal::VERSION, Settings::get('deployment_identifier'));
|
||||
$parts = array('service_container', $this->environment, \Drupal::VERSION, Settings::get('deployment_identifier'), serialize(Settings::get('container_yamls')));
|
||||
return implode(':', $parts);
|
||||
}
|
||||
|
||||
|
@ -866,7 +866,7 @@ class DrupalKernel implements DrupalKernelInterface, TerminableInterface {
|
|||
|
||||
// If needs dumping flag was set, dump the container.
|
||||
if ($this->containerNeedsDumping && !$this->cacheDrupalContainer($container_definition)) {
|
||||
$this->container->get('logger.factory')->get('DrupalKernel')->notice('Container cannot be saved to cache.');
|
||||
$this->container->get('logger.factory')->get('DrupalKernel')->error('Container cannot be saved to cache.');
|
||||
}
|
||||
|
||||
return $this->container;
|
||||
|
|
|
@ -139,7 +139,7 @@ abstract class ContentEntityStorageBase extends EntityStorageBase implements Con
|
|||
$values[$this->langcodeKey] = $langcode;
|
||||
$values[$this->getEntityType()->getKey('default_langcode')] = FALSE;
|
||||
$this->initFieldValues($translation, $values, $field_names);
|
||||
$this->invokeHook('translation_create', $entity);
|
||||
$this->invokeHook('translation_create', $translation);
|
||||
return $translation;
|
||||
}
|
||||
|
||||
|
|
|
@ -309,6 +309,9 @@ interface EntityInterface extends AccessibleInterface, CacheableDependencyInterf
|
|||
* The entity storage object.
|
||||
*
|
||||
* @see \Drupal\Core\Field\FieldItemListInterface::preSave()
|
||||
*
|
||||
* @throws \Exception
|
||||
* When there is a problem that should prevent saving the entity.
|
||||
*/
|
||||
public function preSave(EntityStorageInterface $storage);
|
||||
|
||||
|
|
|
@ -177,25 +177,20 @@ class EntityTypeManager extends DefaultPluginManager implements EntityTypeManage
|
|||
* {@inheritdoc}
|
||||
*/
|
||||
public function getFormObject($entity_type, $operation) {
|
||||
if (!isset($this->handlers['form'][$operation][$entity_type])) {
|
||||
if (!$class = $this->getDefinition($entity_type, TRUE)->getFormClass($operation)) {
|
||||
throw new InvalidPluginDefinitionException($entity_type, sprintf('The "%s" entity type did not specify a "%s" form class.', $entity_type, $operation));
|
||||
}
|
||||
|
||||
$form_object = $this->classResolver->getInstanceFromDefinition($class);
|
||||
|
||||
$form_object
|
||||
->setStringTranslation($this->stringTranslation)
|
||||
->setModuleHandler($this->moduleHandler)
|
||||
->setEntityTypeManager($this)
|
||||
->setOperation($operation)
|
||||
// The entity manager cannot be injected due to a circular dependency.
|
||||
// @todo Remove this set call in https://www.drupal.org/node/2603542.
|
||||
->setEntityManager(\Drupal::entityManager());
|
||||
$this->handlers['form'][$operation][$entity_type] = $form_object;
|
||||
if (!$class = $this->getDefinition($entity_type, TRUE)->getFormClass($operation)) {
|
||||
throw new InvalidPluginDefinitionException($entity_type, sprintf('The "%s" entity type did not specify a "%s" form class.', $entity_type, $operation));
|
||||
}
|
||||
|
||||
return $this->handlers['form'][$operation][$entity_type];
|
||||
$form_object = $this->classResolver->getInstanceFromDefinition($class);
|
||||
|
||||
return $form_object
|
||||
->setStringTranslation($this->stringTranslation)
|
||||
->setModuleHandler($this->moduleHandler)
|
||||
->setEntityTypeManager($this)
|
||||
->setOperation($operation)
|
||||
// The entity manager cannot be injected due to a circular dependency.
|
||||
// @todo Remove this set call in https://www.drupal.org/node/2603542.
|
||||
->setEntityManager(\Drupal::entityManager());
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -699,7 +699,6 @@ function hook_entity_type_alter(array &$entity_types) {
|
|||
*
|
||||
* @see \Drupal\Core\Entity\EntityManagerInterface::getAllViewModes()
|
||||
* @see \Drupal\Core\Entity\EntityManagerInterface::getViewModes()
|
||||
* @see hook_entity_view_mode_info()
|
||||
*/
|
||||
function hook_entity_view_mode_info_alter(&$view_modes) {
|
||||
$view_modes['user']['full']['status'] = TRUE;
|
||||
|
|
|
@ -131,7 +131,7 @@ class TimestampFormatter extends FormatterBase implements ContainerFactoryPlugin
|
|||
);
|
||||
|
||||
$elements['custom_date_format']['#states']['visible'][] = array(
|
||||
':input[name="name="fields[' . $this->fieldDefinition->getName() . '][settings_edit_form][settings][date_format]"]' => array('value' => 'custom'),
|
||||
':input[name="fields[' . $this->fieldDefinition->getName() . '][settings_edit_form][settings][date_format]"]' => array('value' => 'custom'),
|
||||
);
|
||||
|
||||
$elements['timezone'] = array(
|
||||
|
|
|
@ -10,6 +10,7 @@ namespace Drupal\Core\Field\Plugin\Field\FieldWidget;
|
|||
use Drupal\Core\Field\FieldItemListInterface;
|
||||
use Drupal\Core\Field\WidgetBase;
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
use Drupal\Core\Render\Element\Email;
|
||||
|
||||
/**
|
||||
* Plugin implementation of the 'email_default' widget.
|
||||
|
@ -29,6 +30,7 @@ class EmailDefaultWidget extends WidgetBase {
|
|||
*/
|
||||
public static function defaultSettings() {
|
||||
return array(
|
||||
'size' => 60,
|
||||
'placeholder' => '',
|
||||
) + parent::defaultSettings();
|
||||
}
|
||||
|
@ -37,6 +39,13 @@ class EmailDefaultWidget extends WidgetBase {
|
|||
* {@inheritdoc}
|
||||
*/
|
||||
public function settingsForm(array $form, FormStateInterface $form_state) {
|
||||
$element['size'] = array(
|
||||
'#type' => 'number',
|
||||
'#title' => $this->t('Textfield size'),
|
||||
'#default_value' => $this->getSetting('size'),
|
||||
'#required' => TRUE,
|
||||
'#min' => 1,
|
||||
);
|
||||
$element['placeholder'] = array(
|
||||
'#type' => 'textfield',
|
||||
'#title' => t('Placeholder'),
|
||||
|
@ -59,6 +68,7 @@ class EmailDefaultWidget extends WidgetBase {
|
|||
else {
|
||||
$summary[] = t('No placeholder');
|
||||
}
|
||||
$summary[] = t('Textfield size: @size', array('@size' => $this->getSetting('size')));
|
||||
|
||||
return $summary;
|
||||
}
|
||||
|
@ -71,6 +81,8 @@ class EmailDefaultWidget extends WidgetBase {
|
|||
'#type' => 'email',
|
||||
'#default_value' => isset($items[$delta]->value) ? $items[$delta]->value : NULL,
|
||||
'#placeholder' => $this->getSetting('placeholder'),
|
||||
'#size' => $this->getSetting('size'),
|
||||
'#maxlength' => Email::EMAIL_MAX_LENGTH,
|
||||
);
|
||||
return $element;
|
||||
}
|
||||
|
|
|
@ -81,6 +81,15 @@ class FormAjaxResponseBuilder implements FormAjaxResponseBuilderInterface {
|
|||
$response = $result;
|
||||
}
|
||||
else {
|
||||
// At this point we know callback returned a render element. If the
|
||||
// element is part of the group (#group is set on it) it won't be rendered
|
||||
// unless we remove #group from it. This is caused by
|
||||
// \Drupal\Core\Render\Element\RenderElement::preRenderGroup(), which
|
||||
// prevents all members of groups from being rendered directly.
|
||||
if (!empty($result['#group'])) {
|
||||
unset($result['#group']);
|
||||
}
|
||||
|
||||
/** @var \Drupal\Core\Ajax\AjaxResponse $response */
|
||||
$response = $this->ajaxRenderer->renderResponse($result, $request, $this->routeMatch);
|
||||
}
|
||||
|
|
|
@ -29,7 +29,8 @@ use Drupal\Core\Language\LanguageInterface;
|
|||
* - Any time UI text is displayed using PHP code, it should be passed through
|
||||
* either the global t() function or a t() method on the class. If it
|
||||
* involves plurals, it should be passed through either the global
|
||||
* formatPlural() function or a formatPlural() method on the class. Use
|
||||
* \Drupal\Core\StringTranslation\PluralTranslatableMarkup::createFromTranslatedString()
|
||||
* or a formatPlural() method on the class. Use
|
||||
* \Drupal\Core\StringTranslation\StringTranslationTrait to get these methods
|
||||
* into a class.
|
||||
* - Dates displayed in the UI should be passed through the 'date' service
|
||||
|
|
|
@ -14,11 +14,11 @@ namespace Drupal\Core\Lock;
|
|||
*
|
||||
* In most environments, multiple Drupal page requests (a.k.a. threads or
|
||||
* processes) will execute in parallel. This leads to potential conflicts or
|
||||
* race conditions when two requests execute the same code at the same time. A
|
||||
* common example of this is a rebuild like menu_router_rebuild() where we
|
||||
* invoke many hook implementations to get and process data from all active
|
||||
* modules, and then delete the current data in the database to insert the new
|
||||
* afterwards.
|
||||
* race conditions when two requests execute the same code at the same time. For
|
||||
* instance, some implementations of hook_cron() implicitly assume they are
|
||||
* running only once, rather than having multiple calls in parallel. To prevent
|
||||
* problems with such code, the cron system uses a locking process to ensure
|
||||
* that cron is not started again if it is already running.
|
||||
*
|
||||
* This is a cooperative, advisory lock system. Any long-running operation
|
||||
* that could potentially be attempted in parallel by multiple requests should
|
||||
|
|
|
@ -9,6 +9,14 @@ namespace Drupal\Core\Menu;
|
|||
|
||||
/**
|
||||
* Defines a contextual link plugin.
|
||||
*
|
||||
* Contextual links by default are in the module_name.links.contextual.yml
|
||||
* file. These YAML files contain a list of contextual link plugin definitions,
|
||||
* keyed by the plugin ID. Each definition must define a route_name and a group
|
||||
* and might define title, options, and weight. See the getter methods on this
|
||||
* interface for an explanation of each.
|
||||
*
|
||||
* @ingroup menu
|
||||
*/
|
||||
interface ContextualLinkInterface {
|
||||
|
||||
|
|
|
@ -110,6 +110,10 @@ class MenuLinkDefaultForm implements MenuLinkFormInterface, ContainerInjectionIn
|
|||
'#type' => 'item',
|
||||
'#title' => $this->t('This link is provided by the @name module. The title and path cannot be edited.', array('@name' => $this->moduleHandler->getName($provider))),
|
||||
);
|
||||
$form['id'] = array(
|
||||
'#type' => 'value',
|
||||
'#value' => $this->menuLink->getPluginId(),
|
||||
);
|
||||
$link = array(
|
||||
'#type' => 'link',
|
||||
'#title' => $this->menuLink->getTitle(),
|
||||
|
@ -158,7 +162,11 @@ class MenuLinkDefaultForm implements MenuLinkFormInterface, ContainerInjectionIn
|
|||
* {@inheritdoc}
|
||||
*/
|
||||
public function extractFormValues(array &$form, FormStateInterface $form_state) {
|
||||
$new_definition = array();
|
||||
// Start from the complete, original, definition.
|
||||
$new_definition = $this->menuLink->getPluginDefinition();
|
||||
// Since the ID may not be present in the definition used to construct the
|
||||
// plugin, add it here so it's available to any consumers of this method.
|
||||
$new_definition['id'] = $form_state->getValue('id');
|
||||
$new_definition['enabled'] = $form_state->getValue('enabled') ? 1 : 0;
|
||||
$new_definition['weight'] = (int) $form_state->getValue('weight');
|
||||
$new_definition['expanded'] = $form_state->getValue('expanded') ? 1 : 0;
|
||||
|
|
|
@ -38,7 +38,8 @@ interface MenuLinkFormInterface extends PluginFormInterface {
|
|||
* The current state of the form.
|
||||
*
|
||||
* @return array
|
||||
* The new plugin definition values taken from the form values.
|
||||
* The new plugin definition values taken from the form values. The plugin
|
||||
* ID must be returned as part of the definition.
|
||||
*/
|
||||
public function extractFormValues(array &$form, FormStateInterface $form_state);
|
||||
|
||||
|
|
|
@ -13,7 +13,7 @@ namespace Drupal\Core\Path;
|
|||
interface PathValidatorInterface {
|
||||
|
||||
/**
|
||||
* Returns an URL object, if the path is valid and accessible.
|
||||
* Returns a URL object, if the path is valid and accessible.
|
||||
*
|
||||
* @param string $path
|
||||
* The path to check.
|
||||
|
@ -24,7 +24,7 @@ interface PathValidatorInterface {
|
|||
public function getUrlIfValid($path);
|
||||
|
||||
/**
|
||||
* Returns an URL object, if the path is valid.
|
||||
* Returns a URL object, if the path is valid.
|
||||
*
|
||||
* Unlike getUrlIfValid(), access check is not performed. Do not use this
|
||||
* method if the $path is about to be presented to a user.
|
||||
|
|
|
@ -27,7 +27,7 @@ use Drupal\Core\Render\Element;
|
|||
* @code
|
||||
* $form['actions']['preview'] = array(
|
||||
* '#type' => 'button',
|
||||
* '#value => $this->t('Preview'),
|
||||
* '#value' => $this->t('Preview'),
|
||||
* );
|
||||
* @endcode
|
||||
*
|
||||
|
|
|
@ -16,13 +16,40 @@ use Drupal\Core\StringTranslation\TranslatableMarkup;
|
|||
* Provides a form element for a table with radios or checkboxes in left column.
|
||||
*
|
||||
* Properties:
|
||||
* - #header: Table headers used in the table.
|
||||
* - #header: An array of table header labels.
|
||||
* - #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.
|
||||
* - #empty: The message to display if table does not have any options.
|
||||
* - #multiple: Set to FALSE to render the table with radios instead checkboxes.
|
||||
* - #js_select: Set to FALSE if you don't want the select all checkbox added to
|
||||
* the header.
|
||||
*
|
||||
* Other properties of the \Drupal\Core\Render\Element\Table element are also
|
||||
* available.
|
||||
*
|
||||
* Usage example:
|
||||
* See https://www.drupal.org/node/945102 for an example and full explanation.
|
||||
* @code
|
||||
* $header = [
|
||||
* 'first_name' => t('First Name'),
|
||||
* 'last_name' => t('Last Name'),
|
||||
* ];
|
||||
*
|
||||
* $options = [
|
||||
* 1 => ['first_name' => 'Indy', 'last_name' => 'Jones'],
|
||||
* 2 => ['first_name' => 'Darth', 'last_name' => 'Vader'],
|
||||
* 3 => ['first_name' => 'Super', 'last_name' => 'Man'],
|
||||
* ];
|
||||
*
|
||||
* $form['table'] = array(
|
||||
* '#type' => 'tableselect',
|
||||
* '#header' => $header,
|
||||
* '#options' => $options,
|
||||
* '#empty' => t('No users found'),
|
||||
* );
|
||||
* @endcode
|
||||
*
|
||||
* See https://www.drupal.org/node/945102 for a full explanation.
|
||||
*
|
||||
* @see \Drupal\Core\Render\Element\Table
|
||||
*
|
||||
|
|
|
@ -47,7 +47,7 @@ class ContentTypeHeaderMatcher implements RouteFilterInterface {
|
|||
// We do not throw a
|
||||
// \Symfony\Component\Routing\Exception\ResourceNotFoundException here
|
||||
// because we don't want to return a 404 status code, but rather a 415.
|
||||
throw new UnsupportedMediaTypeHttpException('No route found that matches the Content-Type header.');
|
||||
throw new UnsupportedMediaTypeHttpException('No route found that matches "Content-Type: ' . $request->headers->get('Content-Type') . '"');
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -34,7 +34,13 @@ interface RedirectDestinationInterface {
|
|||
public function getAsArray();
|
||||
|
||||
/**
|
||||
* Gets the destination as URL.
|
||||
* Gets the destination as a path.
|
||||
*
|
||||
* To convert to a URL suitable for
|
||||
* \Symfony\Component\HttpFoundation\RedirectResponse::__construct() use
|
||||
* @code
|
||||
* \Drupal\Core\Url::fromUserInput(\Drupal::destination()->get())->setAbsolute()->toString()
|
||||
* @endcode
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
|
|
|
@ -305,14 +305,18 @@ class UrlGenerator implements UrlGeneratorInterface {
|
|||
return $collect_bubbleable_metadata ? $generated_url->setGeneratedUrl($url) : $url;
|
||||
}
|
||||
|
||||
$options += array('prefix' => '');
|
||||
$options += $route->getOption('default_url_options') ?: [];
|
||||
$options += array('prefix' => '', 'path_processing' => TRUE);
|
||||
|
||||
$name = $this->getRouteDebugMessage($name);
|
||||
$this->processRoute($name, $route, $parameters, $generated_url);
|
||||
$path = $this->getInternalPathFromRoute($name, $route, $parameters, $query_params);
|
||||
// Outbound path processors might need the route object for the path, e.g.
|
||||
// to get the path pattern.
|
||||
$options['route'] = $route;
|
||||
$path = $this->processPath($path, $options, $generated_url);
|
||||
if ($options['path_processing']) {
|
||||
$path = $this->processPath($path, $options, $generated_url);
|
||||
}
|
||||
|
||||
if (!empty($options['prefix'])) {
|
||||
$path = ltrim($path, '/');
|
||||
|
|
|
@ -55,10 +55,15 @@ class StaticTranslation implements TranslatorInterface {
|
|||
}
|
||||
|
||||
/**
|
||||
* Add translations for new language.
|
||||
* Retrieves translations for a given language.
|
||||
*
|
||||
* @param string $langcode
|
||||
* The langcode of the language.
|
||||
*
|
||||
* @return array
|
||||
* A multidimensional array of translations, indexed by the context the
|
||||
* source string belongs to. The second level is using original strings as
|
||||
* keys. An empty array will be returned when no translations are available.
|
||||
*/
|
||||
protected function getLanguage($langcode) {
|
||||
// This class is usually a base class but we do not declare as abstract
|
||||
|
|
|
@ -254,7 +254,7 @@ class TwigExtension extends \Twig_Extension {
|
|||
}
|
||||
|
||||
/**
|
||||
* Gets a rendered link from an url object.
|
||||
* Gets a rendered link from a url object.
|
||||
*
|
||||
* @param string $text
|
||||
* The link text for the anchor tag as a translated string.
|
||||
|
@ -313,7 +313,7 @@ class TwigExtension extends \Twig_Extension {
|
|||
* Saves the unneeded automatic escaping for performance reasons.
|
||||
*
|
||||
* The URL generation process percent encodes non-alphanumeric characters.
|
||||
* Thus, the only character within an URL that must be escaped in HTML is the
|
||||
* Thus, the only character within a URL that must be escaped in HTML is the
|
||||
* ampersand ("&") which separates query params. Thus we cannot mark
|
||||
* the generated URL as always safe, but only when we are sure there won't be
|
||||
* multiple query params. This is the case when there are none or only one
|
||||
|
@ -402,6 +402,10 @@ class TwigExtension extends \Twig_Extension {
|
|||
* @return string|null
|
||||
* The escaped, rendered output, or NULL if there is no valid output.
|
||||
*
|
||||
* @throws \Exception
|
||||
* When $arg is passed as an object which does not implement __toString(),
|
||||
* RenderableInterface or toString().
|
||||
*
|
||||
* @todo Refactor this to keep it in sync with theme_render_and_autoescape()
|
||||
* in https://www.drupal.org/node/2575065
|
||||
*/
|
||||
|
@ -433,7 +437,7 @@ class TwigExtension extends \Twig_Extension {
|
|||
elseif (method_exists($arg, '__toString')) {
|
||||
$return = (string) $arg;
|
||||
}
|
||||
// You can't throw exceptions in the magic PHP __toString methods, see
|
||||
// You can't throw exceptions in the magic PHP __toString() methods, see
|
||||
// http://php.net/manual/en/language.oop5.magic.php#object.tostring so
|
||||
// we also support a toString method.
|
||||
elseif (method_exists($arg, 'toString')) {
|
||||
|
@ -471,10 +475,11 @@ class TwigExtension extends \Twig_Extension {
|
|||
/**
|
||||
* Wrapper around render() for twig printed output.
|
||||
*
|
||||
* If an object is passed that has no __toString method an exception is thrown;
|
||||
* other objects are casted to string. However in the case that the object is an
|
||||
* instance of a Twig_Markup object it is returned directly to support auto
|
||||
* escaping.
|
||||
* If an object is passed which does not implement __toString(),
|
||||
* RenderableInterface or toString() then an exception is thrown;
|
||||
* Other objects are casted to string. However in the case that the
|
||||
* object is an instance of a Twig_Markup object it is returned directly
|
||||
* to support auto escaping.
|
||||
*
|
||||
* If an array is passed it is rendered via render() and scalar values are
|
||||
* returned directly.
|
||||
|
@ -485,6 +490,10 @@ class TwigExtension extends \Twig_Extension {
|
|||
* @return mixed
|
||||
* The rendered output or an Twig_Markup object.
|
||||
*
|
||||
* @throws \Exception
|
||||
* When $arg is passed as an object which does not implement __toString(),
|
||||
* RenderableInterface or toString().
|
||||
*
|
||||
* @see render
|
||||
* @see TwigNodeVisitor
|
||||
*/
|
||||
|
@ -511,7 +520,7 @@ class TwigExtension extends \Twig_Extension {
|
|||
elseif (method_exists($arg, '__toString')) {
|
||||
return (string) $arg;
|
||||
}
|
||||
// You can't throw exceptions in the magic PHP __toString methods, see
|
||||
// You can't throw exceptions in the magic PHP __toString() methods, see
|
||||
// http://php.net/manual/en/language.oop5.magic.php#object.tostring so
|
||||
// we also support a toString method.
|
||||
elseif (method_exists($arg, 'toString')) {
|
||||
|
|
|
@ -40,7 +40,8 @@ class Registry implements DestructableInterface {
|
|||
* The complete theme registry.
|
||||
*
|
||||
* @var array
|
||||
* An associative array keyed by theme hook names, whose values are
|
||||
* An array of theme registries, keyed by the theme name. Each registry is
|
||||
* an associative array keyed by theme hook names, whose values are
|
||||
* associative arrays containing the aggregated hook definition:
|
||||
* - type: The type of the extension the original theme hook originates
|
||||
* from; e.g., 'module' for theme hook 'node' of Node module.
|
||||
|
@ -79,7 +80,7 @@ class Registry implements DestructableInterface {
|
|||
* - process: An array of theme variable process callbacks to invoke
|
||||
* before invoking the actual theme function or template.
|
||||
*/
|
||||
protected $registry;
|
||||
protected $registry = [];
|
||||
|
||||
/**
|
||||
* The cache backend to use for the complete theme registry data.
|
||||
|
@ -96,11 +97,11 @@ class Registry implements DestructableInterface {
|
|||
protected $moduleHandler;
|
||||
|
||||
/**
|
||||
* The incomplete, runtime theme registry.
|
||||
* An array of incomplete, runtime theme registries, keyed by theme name.
|
||||
*
|
||||
* @var \Drupal\Core\Utility\ThemeRegistry
|
||||
* @var \Drupal\Core\Utility\ThemeRegistry[]
|
||||
*/
|
||||
protected $runtimeRegistry;
|
||||
protected $runtimeRegistry = [];
|
||||
|
||||
/**
|
||||
* Stores whether the registry was already initialized.
|
||||
|
@ -209,20 +210,20 @@ class Registry implements DestructableInterface {
|
|||
*/
|
||||
public function get() {
|
||||
$this->init($this->themeName);
|
||||
if (isset($this->registry)) {
|
||||
return $this->registry;
|
||||
if (isset($this->registry[$this->theme->getName()])) {
|
||||
return $this->registry[$this->theme->getName()];
|
||||
}
|
||||
if ($cache = $this->cache->get('theme_registry:' . $this->theme->getName())) {
|
||||
$this->registry = $cache->data;
|
||||
$this->registry[$this->theme->getName()] = $cache->data;
|
||||
}
|
||||
else {
|
||||
$this->registry = $this->build();
|
||||
$this->build();
|
||||
// Only persist it if all modules are loaded to ensure it is complete.
|
||||
if ($this->moduleHandler->isLoaded()) {
|
||||
$this->setCache();
|
||||
}
|
||||
}
|
||||
return $this->registry;
|
||||
return $this->registry[$this->theme->getName()];
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -235,17 +236,17 @@ class Registry implements DestructableInterface {
|
|||
*/
|
||||
public function getRuntime() {
|
||||
$this->init($this->themeName);
|
||||
if (!isset($this->runtimeRegistry)) {
|
||||
$this->runtimeRegistry = new ThemeRegistry('theme_registry:runtime:' . $this->theme->getName(), $this->cache, $this->lock, array('theme_registry'), $this->moduleHandler->isLoaded());
|
||||
if (!isset($this->runtimeRegistry[$this->theme->getName()])) {
|
||||
$this->runtimeRegistry[$this->theme->getName()] = new ThemeRegistry('theme_registry:runtime:' . $this->theme->getName(), $this->cache, $this->lock, array('theme_registry'), $this->moduleHandler->isLoaded());
|
||||
}
|
||||
return $this->runtimeRegistry;
|
||||
return $this->runtimeRegistry[$this->theme->getName()];
|
||||
}
|
||||
|
||||
/**
|
||||
* Persists the theme registry in the cache backend.
|
||||
*/
|
||||
protected function setCache() {
|
||||
$this->cache->set('theme_registry:' . $this->theme->getName(), $this->registry, Cache::PERMANENT, array('theme_registry'));
|
||||
$this->cache->set('theme_registry:' . $this->theme->getName(), $this->registry[$this->theme->getName()], Cache::PERMANENT, array('theme_registry'));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -359,9 +360,9 @@ class Registry implements DestructableInterface {
|
|||
unset($cache[$hook]['preprocess functions']);
|
||||
}
|
||||
}
|
||||
$this->registry = $cache;
|
||||
$this->registry[$this->theme->getName()] = $cache;
|
||||
|
||||
return $this->registry;
|
||||
return $this->registry[$this->theme->getName()];
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -719,12 +720,12 @@ class Registry implements DestructableInterface {
|
|||
*/
|
||||
public function reset() {
|
||||
// Reset the runtime registry.
|
||||
if (isset($this->runtimeRegistry) && $this->runtimeRegistry instanceof ThemeRegistry) {
|
||||
$this->runtimeRegistry->clear();
|
||||
foreach ($this->runtimeRegistry as $runtime_registry) {
|
||||
$runtime_registry->clear();
|
||||
}
|
||||
$this->runtimeRegistry = NULL;
|
||||
$this->runtimeRegistry = [];
|
||||
|
||||
$this->registry = NULL;
|
||||
$this->registry = [];
|
||||
Cache::invalidateTags(array('theme_registry'));
|
||||
return $this;
|
||||
}
|
||||
|
@ -733,8 +734,8 @@ class Registry implements DestructableInterface {
|
|||
* {@inheritdoc}
|
||||
*/
|
||||
public function destruct() {
|
||||
if (isset($this->runtimeRegistry)) {
|
||||
$this->runtimeRegistry->destruct();
|
||||
foreach ($this->runtimeRegistry as $runtime_registry) {
|
||||
$runtime_registry->destruct();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -28,11 +28,9 @@ abstract class ComplexDataDefinitionBase extends DataDefinition implements Compl
|
|||
* {@inheritdoc}
|
||||
*/
|
||||
public function getPropertyDefinition($name) {
|
||||
if (!isset($this->propertyDefinitions)) {
|
||||
$this->getPropertyDefinitions();
|
||||
}
|
||||
if (isset($this->propertyDefinitions[$name])) {
|
||||
return $this->propertyDefinitions[$name];
|
||||
$definitions = $this->getPropertyDefinitions();
|
||||
if (isset($definitions[$name])) {
|
||||
return $definitions[$name];
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -199,4 +199,23 @@ abstract class TypedData implements TypedDataInterface, PluginInspectionInterfac
|
|||
public function getParent() {
|
||||
return $this->parent;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function __sleep() {
|
||||
$vars = get_object_vars($this);
|
||||
// Prevent services from being serialized. static::getStringTranslation()
|
||||
// and static::getTypedDataManager() lazy-load them after $this has been
|
||||
// unserialized.
|
||||
// @todo Replace this with
|
||||
// \Drupal\Core\DependencyInjection\DependencySerializationTrait before
|
||||
// Drupal 9.0.0. We cannot use that now, because child classes already use
|
||||
// it and PHP 5 would consider that conflicts.
|
||||
unset($vars['stringTranslation']);
|
||||
unset($vars['typedDataManager']);
|
||||
|
||||
return array_keys($vars);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -76,6 +76,7 @@ class Error {
|
|||
'%line' => $caller['line'],
|
||||
'severity_level' => static::ERROR,
|
||||
'backtrace' => $backtrace,
|
||||
'backtrace_string' => $exception->getTraceAsString(),
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -179,7 +180,12 @@ class Error {
|
|||
}
|
||||
}
|
||||
|
||||
$return .= $call['function'] . '(' . implode(', ', $call['args']) . ")\n";
|
||||
$line = '';
|
||||
if (isset($trace['line'])) {
|
||||
$line = " (Line: {$trace['line']})";
|
||||
}
|
||||
|
||||
$return .= $call['function'] . '(' . implode(', ', $call['args']) . ")$line\n";
|
||||
}
|
||||
|
||||
return $return;
|
||||
|
|
Reference in a new issue