only in patch2: unchanged: --- a/.editorconfig +++ b/.editorconfig @@ -13,5 +13,5 @@ charset = utf-8 trim_trailing_whitespace = true insert_final_newline = true -[composer.{json,lock}] +[composer.json] indent_size = 4 only in patch2: unchanged: --- a/composer.json +++ b/composer.json @@ -8,7 +8,7 @@ "wikimedia/composer-merge-plugin": "~1.3" }, "replace": { - "drupal/core": "~8.4" + "drupal/core": "~8.3" }, "minimum-stability": "dev", "prefer-stable": true, only in patch2: unchanged: --- a/composer.lock +++ b/composer.lock @@ -4,40 +4,31 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", "This file is @generated automatically" ], - "content-hash": "47cf4b2b460c00b55b2533e8caa6df19", + "content-hash": "fb766841005ecf4b3ec4ecd8b4c98df4", "packages": [ { "name": "asm89/stack-cors", - "version": "1.1.0", + "version": "1.0.0", "source": { "type": "git", "url": "https://github.com/asm89/stack-cors.git", - "reference": "65ccbd455370f043c2e3b93482a3813603d68731" + "reference": "3ae8ef219bb4c9a6caf857421719aa07fa7776cc" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/asm89/stack-cors/zipball/65ccbd455370f043c2e3b93482a3813603d68731", - "reference": "65ccbd455370f043c2e3b93482a3813603d68731", + "url": "https://api.github.com/repos/asm89/stack-cors/zipball/3ae8ef219bb4c9a6caf857421719aa07fa7776cc", + "reference": "3ae8ef219bb4c9a6caf857421719aa07fa7776cc", "shasum": "" }, "require": { - "php": ">=5.5.9", - "symfony/http-foundation": "~2.7|~3.0", - "symfony/http-kernel": "~2.7|~3.0" - }, - "require-dev": { - "phpunit/phpunit": "^5.0 || ^4.8.10", - "squizlabs/php_codesniffer": "^2.3" + "php": ">=5.3.2", + "symfony/http-foundation": "~2.1|~3.0", + "symfony/http-kernel": "~2.1|~3.0" }, "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.1-dev" - } - }, "autoload": { - "psr-4": { - "Asm89\\Stack\\": "src/Asm89/Stack/" + "psr-0": { + "Asm89\\Stack": "src/" } }, "notification-url": "https://packagist.org/downloads/", @@ -56,7 +47,7 @@ "cors", "stack" ], - "time": "2017-04-11T20:03:41+00:00" + "time": "2016-08-01T12:05:04+00:00" }, { "name": "composer/installers", @@ -2429,30 +2420,29 @@ }, { "name": "twig/twig", - "version": "v1.32.0", + "version": "v1.25.0", "source": { "type": "git", "url": "https://github.com/twigphp/Twig.git", - "reference": "9935b662e24d6e634da88901ab534cc12e8c728f" + "reference": "f16a634ab08d87e520da5671ec52153d627f10f6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/twigphp/Twig/zipball/9935b662e24d6e634da88901ab534cc12e8c728f", - "reference": "9935b662e24d6e634da88901ab534cc12e8c728f", + "url": "https://api.github.com/repos/twigphp/Twig/zipball/f16a634ab08d87e520da5671ec52153d627f10f6", + "reference": "f16a634ab08d87e520da5671ec52153d627f10f6", "shasum": "" }, "require": { "php": ">=5.2.7" }, "require-dev": { - "psr/container": "^1.0", "symfony/debug": "~2.7", - "symfony/phpunit-bridge": "~3.2" + "symfony/phpunit-bridge": "~2.7" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.32-dev" + "dev-master": "1.25-dev" } }, "autoload": { @@ -2487,7 +2477,7 @@ "keywords": [ "templating" ], - "time": "2017-02-27T00:07:03+00:00" + "time": "2016-09-21T23:05:12+00:00" }, { "name": "wikimedia/composer-merge-plugin", only in patch2: unchanged: --- a/core/.gitignore +++ /dev/null @@ -1,7 +0,0 @@ -# Ignore node_modules folder created when installing core's JavaScript -# dependencies. -node_modules - -# Ignore overrides of core's phpcs.xml.dist and phpunit.xml.dist. -phpcs.xml -phpunit.xml only in patch2: unchanged: --- a/core/CHANGELOG.txt +++ b/core/CHANGELOG.txt @@ -1,3 +1,7 @@ +Drupal 8.3.1, 2017-04-19 +------------------------ +- Fixed security issues. See SA-CORE-2017-002. + Drupal 8.3.0, 2017-04-05 ------------------------ - Added modules: only in patch2: unchanged: --- a/core/composer.json +++ b/core/composer.json @@ -32,7 +32,7 @@ "zendframework/zend-diactoros": "~1.1", "composer/semver": "~1.0", "paragonie/random_compat": "^1.0|^2.0", - "asm89/stack-cors": "~1.1" + "asm89/stack-cors": "~1.0" }, "conflict": { "drush/drush": "<8.1.10" @@ -44,7 +44,7 @@ "jcalderonzumba/gastonjs": "~1.0.2", "jcalderonzumba/mink-phantomjs-driver": "~0.3.1", "mikey179/vfsStream": "~1.2", - "phpunit/phpunit": ">=4.8.35 <5", + "phpunit/phpunit": ">=4.8.28 <5", "symfony/browser-kit": ">=2.8.13 <3.0", "symfony/css-selector": "~2.8" }, only in patch2: unchanged: --- a/core/config/schema/core.data_types.schema.yml +++ b/core/config/schema/core.data_types.schema.yml @@ -46,7 +46,7 @@ mapping: sequence: label: Sequence class: '\Drupal\Core\Config\Schema\Sequence' - definition_class: '\Drupal\Core\Config\Schema\SequenceDataDefinition' + definition_class: '\Drupal\Core\TypedData\ListDataDefinition' # Simple extended data types: only in patch2: unchanged: --- a/core/core.link_relation_types.yml +++ b/core/core.link_relation_types.yml @@ -79,9 +79,6 @@ create-form: current: description: "Refers to a resource containing the most recent item(s) in a collection of resources." reference: '[RFC5005]' -customize-form: - description: "The target URI points to a resource where a submission form for customizing associated resource can be obtained." - reference: '[RFC6861]' derivedfrom: description: 'The target IRI points to a resource from which this material was derived.' reference: '[draft-hoffman-xml2rfc]' only in patch2: unchanged: --- a/core/core.services.yml +++ b/core/core.services.yml @@ -331,11 +331,9 @@ services: arguments: ['@config.storage', 'config/schema', '', true, '%install_profile%'] config.typed: class: Drupal\Core\Config\TypedConfigManager - arguments: ['@config.storage', '@config.storage.schema', '@cache.discovery', '@module_handler', '@class_resolver'] + arguments: ['@config.storage', '@config.storage.schema', '@cache.discovery', '@module_handler'] tags: - { name: plugin_manager_cache_clear } - calls: - - [setValidationConstraintManager, ['@validation.constraint']] context.handler: class: Drupal\Core\Plugin\Context\ContextHandler arguments: ['@typed_data_manager'] @@ -1232,8 +1230,8 @@ services: tags: - { name: event_subscriber } arguments: ['@http_kernel', '@logger.channel.php', '@redirect.destination', '@router.no_access_checks'] - exception.final: - class: Drupal\Core\EventSubscriber\FinalExceptionSubscriber + exception.default: + class: Drupal\Core\EventSubscriber\DefaultExceptionSubscriber tags: - { name: event_subscriber } arguments: ['@config.factory'] only in patch2: unchanged: --- a/core/includes/schema.inc +++ b/core/includes/schema.inc @@ -119,7 +119,7 @@ function drupal_install_schema($module) { _drupal_schema_initialize($schema, $module, FALSE); foreach ($schema as $name => $table) { - \Drupal::database()->schema()->createTable($name, $table); + db_create_table($name, $table); } } only in patch2: unchanged: --- a/core/includes/theme.inc +++ b/core/includes/theme.inc @@ -240,7 +240,8 @@ function drupal_find_theme_templates($cache, $extension, $path) { // Match templates based on the 'template' filename. foreach ($cache as $hook => $info) { if (isset($info['template'])) { - if ($template === $info['template']) { + $template_candidates = [$info['template'], str_replace($info['theme path'] . '/templates/', '', $info['template'])]; + if (in_array($template, $template_candidates)) { $implementations[$hook] = [ 'template' => $template, 'path' => dirname($file->uri), only in patch2: unchanged: --- a/core/lib/Drupal.php +++ b/core/lib/Drupal.php @@ -81,7 +81,7 @@ class Drupal { /** * The current system version. */ - const VERSION = '8.4.0-dev'; + const VERSION = '8.3.2-dev'; /** * Core API compatibility. only in patch2: unchanged: --- a/core/lib/Drupal/Core/Action/ConfigurableActionBase.php +++ b/core/lib/Drupal/Core/Action/ConfigurableActionBase.php @@ -17,7 +17,7 @@ public function __construct(array $configuration, $plugin_id, $plugin_definition) { parent::__construct($configuration, $plugin_id, $plugin_definition); - $this->setConfiguration($configuration); + $this->configuration += $this->defaultConfiguration(); } /** @@ -38,7 +38,7 @@ public function getConfiguration() { * {@inheritdoc} */ public function setConfiguration(array $configuration) { - $this->configuration = $configuration + $this->defaultConfiguration(); + $this->configuration = $configuration; } /** only in patch2: unchanged: --- a/core/lib/Drupal/Core/Config/Schema/ArrayElement.php +++ b/core/lib/Drupal/Core/Config/Schema/ArrayElement.php @@ -2,12 +2,10 @@ namespace Drupal\Core\Config\Schema; -use Drupal\Core\TypedData\ComplexDataInterface; - /** * Defines a generic configuration element that contains multiple properties. */ -abstract class ArrayElement extends Element implements \IteratorAggregate, TypedConfigInterface, ComplexDataInterface { +abstract class ArrayElement extends Element implements \IteratorAggregate, TypedConfigInterface { /** * Parsed elements. @@ -163,25 +161,4 @@ public function isNullable() { return isset($this->definition['nullable']) && $this->definition['nullable'] == TRUE; } - /** - * {@inheritdoc} - */ - public function set($property_name, $value, $notify = TRUE) { - $this->value[$property_name] = $value; - // Config schema elements do not make use of notifications. Thus, we skip - // notifying parents. - return $this; - } - - /** - * {@inheritdoc} - */ - public function getProperties($include_computed = FALSE) { - $properties = []; - foreach (array_keys($this->value) as $name) { - $properties[$name] = $this->get($name); - } - return $properties; - } - } only in patch2: unchanged: --- a/core/lib/Drupal/Core/Config/Schema/Sequence.php +++ b/core/lib/Drupal/Core/Config/Schema/Sequence.php @@ -10,12 +10,6 @@ * * Read https://www.drupal.org/node/1905070 for more details about configuration * schema, types and type resolution. - * - * Note that sequences implement the typed data ComplexDataInterface (via the - * parent ArrayElement) rather than the ListInterface. This is because sequences - * may have named keys, which is not supported by ListInterface. From the typed - * data API perspective sequences are handled as ordered mappings without - * metadata about existing properties. */ class Sequence extends ArrayElement { only in patch2: unchanged: --- a/core/lib/Drupal/Core/Config/Schema/SequenceDataDefinition.php +++ /dev/null @@ -1,28 +0,0 @@ -definition['orderby']) ? $this->definition['orderby'] : NULL; - } - -} only in patch2: unchanged: --- a/core/lib/Drupal/Core/Config/StorableConfigBase.php +++ b/core/lib/Drupal/Core/Config/StorableConfigBase.php @@ -3,8 +3,6 @@ namespace Drupal\Core\Config; use Drupal\Core\Config\Schema\Ignore; -use Drupal\Core\Config\Schema\Sequence; -use Drupal\Core\Config\Schema\SequenceDataDefinition; use Drupal\Core\TypedData\PrimitiveInterface; use Drupal\Core\TypedData\Type\FloatInterface; use Drupal\Core\TypedData\Type\IntegerInterface; @@ -212,29 +210,6 @@ protected function castValue($key, $value) { foreach ($value as $nested_value_key => $nested_value) { $value[$nested_value_key] = $this->castValue($key . '.' . $nested_value_key, $nested_value); } - - if ($element instanceof Sequence) { - $data_definition = $element->getDataDefinition(); - if ($data_definition instanceof SequenceDataDefinition) { - // Apply any sorting defined on the schema. - switch ($data_definition->getOrderBy()) { - case 'key': - ksort($value); - break; - - case 'value': - // The PHP documentation notes that "Be careful when sorting - // arrays with mixed types values because sort() can produce - // unpredictable results". There is no risk here because - // \Drupal\Core\Config\StorableConfigBase::castValue() has - // already cast all values to the same type using the - // configuration schema. - sort($value); - break; - - } - } - } } return $value; } only in patch2: unchanged: --- a/core/lib/Drupal/Core/Config/TypedConfigManager.php +++ b/core/lib/Drupal/Core/Config/TypedConfigManager.php @@ -6,7 +6,6 @@ use Drupal\Core\Cache\CacheBackendInterface; use Drupal\Core\Config\Schema\ConfigSchemaAlterException; use Drupal\Core\Config\Schema\ConfigSchemaDiscovery; -use Drupal\Core\DependencyInjection\ClassResolverInterface; use Drupal\Core\Config\Schema\Undefined; use Drupal\Core\Extension\ModuleHandlerInterface; use Drupal\Core\TypedData\TypedDataManager; @@ -46,18 +45,13 @@ class TypedConfigManager extends TypedDataManager implements TypedConfigManagerI * The storage object to use for reading schema data * @param \Drupal\Core\Cache\CacheBackendInterface $cache * The cache backend to use for caching the definitions. - * @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler - * The module handler. - * @param \Drupal\Core\DependencyInjection\ClassResolverInterface $class_resolver - * (optional) The class resolver. */ - public function __construct(StorageInterface $configStorage, StorageInterface $schemaStorage, CacheBackendInterface $cache, ModuleHandlerInterface $module_handler, ClassResolverInterface $class_resolver = NULL) { + public function __construct(StorageInterface $configStorage, StorageInterface $schemaStorage, CacheBackendInterface $cache, ModuleHandlerInterface $module_handler) { $this->configStorage = $configStorage; $this->schemaStorage = $schemaStorage; $this->setCacheBackend($cache, 'typed_config_definitions'); $this->alterInfo('config_schema_info'); $this->moduleHandler = $module_handler; - $this->classResolver = $class_resolver ?: \Drupal::service('class_resolver'); } /** @@ -190,7 +184,6 @@ protected function getDefinitionWithReplacements($base_plugin_id, array $replace $definition += [ 'definition_class' => '\Drupal\Core\TypedData\DataDefinition', 'type' => $type, - 'unwrap_for_canonical_representation' => TRUE, ]; return $definition; } only in patch2: unchanged: --- a/core/lib/Drupal/Core/Database/database.api.php +++ b/core/lib/Drupal/Core/Database/database.api.php @@ -5,8 +5,6 @@ * Hooks related to the Database system and the Schema API. */ -use Drupal\Core\Database\Query\Condition; - /** * @defgroup database Database abstraction layer * @{ @@ -434,11 +432,11 @@ function hook_query_TAG_alter(Drupal\Core\Database\Query\AlterableInterface $que if (!\Drupal::currentUser()->hasPermission('bypass node access')) { // The node_access table has the access grants for any given node. $access_alias = $query->join('node_access', 'na', '%alias.nid = n.nid'); - $or = new Condition('OR'); + $or = db_or(); // If any grant exists for the specified user, then user has access to the node for the specified operation. foreach (node_access_grants($op, $query->getMetaData('account')) as $realm => $gids) { foreach ($gids as $gid) { - $or->condition((new Condition('AND')) + $or->condition(db_and() ->condition($access_alias . '.gid', $gid) ->condition($access_alias . '.realm', $realm) ); only in patch2: unchanged: --- a/core/lib/Drupal/Core/DrupalKernel.php +++ b/core/lib/Drupal/Core/DrupalKernel.php @@ -410,7 +410,7 @@ public static function findSitePath(Request $request, $require_settings = TRUE, * {@inheritdoc} */ public function setSitePath($path) { - if ($this->booted && $path !== $this->sitePath) { + if ($this->booted) { throw new \LogicException('Site path cannot be changed after calling boot()'); } $this->sitePath = $path; only in patch2: unchanged: --- a/core/lib/Drupal/Core/Entity/ContentEntityBase.php +++ b/core/lib/Drupal/Core/Entity/ContentEntityBase.php @@ -1285,15 +1285,20 @@ public static function bundleFieldDefinitions(EntityTypeInterface $entity_type, * An array of field names. */ protected function getFieldsToSkipFromTranslationChangesCheck() { - /** @var \Drupal\Core\Entity\ContentEntityTypeInterface $entity_type */ - $entity_type = $this->getEntityType(); // A list of known revision metadata fields which should be skipped from // the comparision. + // @todo Replace the hard coded list of revision metadata fields with the + // solution from https://www.drupal.org/node/2615016. $fields = [ - $entity_type->getKey('revision'), + $this->getEntityType()->getKey('revision'), 'revision_translation_affected', + 'revision_uid', + 'revision_user', + 'revision_timestamp', + 'revision_created', + 'revision_log', + 'revision_log_message', ]; - $fields = array_merge($fields, array_values($entity_type->getRevisionMetadataKeys())); return $fields; } only in patch2: unchanged: --- a/core/lib/Drupal/Core/Entity/ContentEntityType.php +++ b/core/lib/Drupal/Core/Entity/ContentEntityType.php @@ -8,13 +8,6 @@ class ContentEntityType extends EntityType implements ContentEntityTypeInterface { /** - * An array of entity revision metadata keys. - * - * @var array - */ - protected $revision_metadata_keys = []; - - /** * {@inheritdoc} */ public function __construct($definition) { @@ -48,44 +41,4 @@ protected function checkStorageClass($class) { } } - /** - * {@inheritdoc} - */ - public function getRevisionMetadataKeys($include_backwards_compatibility_field_names = TRUE) { - // Provide backwards compatibility in case the revision metadata keys are - // not defined in the entity annotation. - if (!$this->revision_metadata_keys && $include_backwards_compatibility_field_names) { - $base_fields = \Drupal::service('entity_field.manager')->getBaseFieldDefinitions($this->id()); - if ((isset($base_fields['revision_uid']) && $revision_user = 'revision_uid') || (isset($base_fields['revision_user']) && $revision_user = 'revision_user')) { - @trigger_error('The revision_user revision metadata key is not set.', E_USER_DEPRECATED); - $this->revision_metadata_keys['revision_user'] = $revision_user; - } - if ((isset($base_fields['revision_timestamp']) && $revision_timestamp = 'revision_timestamp') || (isset($base_fields['revision_created'])) && $revision_timestamp = 'revision_created') { - @trigger_error('The revision_created revision metadata key is not set.', E_USER_DEPRECATED); - $this->revision_metadata_keys['revision_created'] = $revision_timestamp; - } - if ((isset($base_fields['revision_log']) && $revision_log = 'revision_log') || (isset($base_fields['revision_log_message']) && $revision_log = 'revision_log_message')) { - @trigger_error('The revision_log_message revision metadata key is not set.', E_USER_DEPRECATED); - $this->revision_metadata_keys['revision_log_message'] = $revision_log; - } - } - return $this->revision_metadata_keys; - } - - /** - * {@inheritdoc} - */ - public function getRevisionMetadataKey($key) { - $keys = $this->getRevisionMetadataKeys(); - return isset($keys[$key]) ? $keys[$key] : FALSE; - } - - /** - * {@inheritdoc} - */ - public function hasRevisionMetadataKey($key) { - $keys = $this->getRevisionMetadataKeys(); - return isset($keys[$key]); - } - } only in patch2: unchanged: --- a/core/lib/Drupal/Core/Entity/ContentEntityTypeInterface.php +++ b/core/lib/Drupal/Core/Entity/ContentEntityTypeInterface.php @@ -6,50 +6,4 @@ * Provides an interface for a content entity type and its metadata. */ interface ContentEntityTypeInterface extends EntityTypeInterface { - - /** - * Gets an array of entity revision metadata keys. - * - * @param bool $include_backwards_compatibility_field_names - * (optional and deprecated) Whether to provide the revision keys on a - * best-effort basis by looking at the base fields defined by the entity - * type. Note that this parameter will be removed in Drupal 9.0.0. Defaults - * to TRUE. - * - * @return array - * An array describing how the Field API can extract revision metadata - * information of this entity type: - * - revision_log_message: The name of the property that contains description - * of the changes that were made in the current revision. - * - revision_user: The name of the property that contains the user ID of - * the author of the current revision. - * - revision_created: The name of the property that contains the timestamp - * of the current revision. - */ - public function getRevisionMetadataKeys($include_backwards_compatibility_field_names = TRUE); - - /** - * Gets a specific entity revision metadata key. - * - * @param string $key - * The name of the entity revision metadata key to return. - * - * @return string|bool - * The entity revision metadata key, or FALSE if it does not exist. - * - * @see self::getRevisionMetadataKeys() - */ - public function getRevisionMetadataKey($key); - - /** - * Indicates if a given entity revision metadata key exists. - * - * @param string $key - * The name of the entity revision metadata key to check. - * - * @return bool - * TRUE if a given entity revision metadata key exists, FALSE otherwise. - */ - public function hasRevisionMetadataKey($key); - } only in patch2: unchanged: --- a/core/lib/Drupal/Core/Entity/EditorialContentEntityBase.php +++ /dev/null @@ -1,31 +0,0 @@ -setLabel(t('Revision create time')) ->setDescription(t('The time that the current revision was created.')) ->setRevisionable(TRUE); - $fields[static::getRevisionMetadataKey($entity_type, 'revision_user')] = BaseFieldDefinition::create('entity_reference') + $fields['revision_user'] = BaseFieldDefinition::create('entity_reference') ->setLabel(t('Revision user')) ->setDescription(t('The user ID of the author of the current revision.')) ->setSetting('target_type', 'user') ->setRevisionable(TRUE); - $fields[static::getRevisionMetadataKey($entity_type, 'revision_log_message')] = BaseFieldDefinition::create('string_long') + $fields['revision_log_message'] = BaseFieldDefinition::create('string_long') ->setLabel(t('Revision log message')) ->setDescription(t('Briefly describe the changes you have made.')) ->setRevisionable(TRUE) @@ -56,14 +56,14 @@ public static function revisionLogBaseFieldDefinitions(EntityTypeInterface $enti * Implements \Drupal\Core\Entity\RevisionLogInterface::getRevisionCreationTime(). */ public function getRevisionCreationTime() { - return $this->{static::getRevisionMetadataKey($this->getEntityType(), 'revision_created')}->value; + return $this->revision_created->value; } /** * Implements \Drupal\Core\Entity\RevisionLogInterface::setRevisionCreationTime(). */ public function setRevisionCreationTime($timestamp) { - $this->{static::getRevisionMetadataKey($this->getEntityType(), 'revision_created')}->value = $timestamp; + $this->revision_created->value = $timestamp; return $this; } @@ -71,14 +71,14 @@ public function setRevisionCreationTime($timestamp) { * Implements \Drupal\Core\Entity\RevisionLogInterface::getRevisionUser(). */ public function getRevisionUser() { - return $this->{static::getRevisionMetadataKey($this->getEntityType(), 'revision_user')}->entity; + return $this->revision_user->entity; } /** * Implements \Drupal\Core\Entity\RevisionLogInterface::setRevisionUser(). */ public function setRevisionUser(UserInterface $account) { - $this->{static::getRevisionMetadataKey($this->getEntityType(), 'revision_user')}->entity = $account; + $this->revision_user->entity = $account; return $this; } @@ -86,14 +86,14 @@ public function setRevisionUser(UserInterface $account) { * Implements \Drupal\Core\Entity\RevisionLogInterface::getRevisionUserId(). */ public function getRevisionUserId() { - return $this->{static::getRevisionMetadataKey($this->getEntityType(), 'revision_user')}->target_id; + return $this->revision_user->target_id; } /** * Implements \Drupal\Core\Entity\RevisionLogInterface::setRevisionUserId(). */ public function setRevisionUserId($user_id) { - $this->{static::getRevisionMetadataKey($this->getEntityType(), 'revision_user')}->target_id = $user_id; + $this->revision_user->target_id = $user_id; return $this; } @@ -101,41 +101,15 @@ public function setRevisionUserId($user_id) { * Implements \Drupal\Core\Entity\RevisionLogInterface::getRevisionLogMessage(). */ public function getRevisionLogMessage() { - return $this->{static::getRevisionMetadataKey($this->getEntityType(), 'revision_log_message')}->value; + return $this->revision_log_message->value; } /** * Implements \Drupal\Core\Entity\RevisionLogInterface::setRevisionLogMessage(). */ public function setRevisionLogMessage($revision_log_message) { - $this->{static::getRevisionMetadataKey($this->getEntityType(), 'revision_log_message')}->value = $revision_log_message; + $this->revision_log_message->value = $revision_log_message; return $this; } - /** - * Gets the name of a revision metadata field. - * - * @param \Drupal\Core\Entity\EntityTypeInterface $entity_type - * A content entity type definition. - * @param string $key - * The revision metadata key to get, must be one of 'revision_created', - * 'revision_user' or 'revision_log_message'. - * - * @return string - * The name of the field for the specified $key. - */ - protected static function getRevisionMetadataKey(EntityTypeInterface $entity_type, $key) { - // We need to prevent ContentEntityType::getRevisionMetadataKey() from - // providing fallback as that requires fetching the entity type's field - // definition leading to an infinite recursion. - /** @var \Drupal\Core\Entity\ContentEntityTypeInterface $entity_type */ - $revision_metadata_keys = $entity_type->getRevisionMetadataKeys(FALSE) + [ - 'revision_created' => 'revision_created', - 'revision_user' => 'revision_user', - 'revision_log_message' => 'revision_log_message', - ]; - - return $revision_metadata_keys[$key]; - } - } only in patch2: unchanged: --- a/core/lib/Drupal/Core/Entity/Sql/SqlContentEntityStorage.php +++ b/core/lib/Drupal/Core/Entity/Sql/SqlContentEntityStorage.php @@ -294,11 +294,17 @@ public function getTableMapping(array $storage_definitions = NULL) { // Make sure the key fields come first in the list of fields. $all_fields = array_merge($key_fields, array_diff($all_fields, $key_fields)); - // If the entity is revisionable, gather the fields that need to be put - // in the revision table. - $revisionable = $this->entityType->isRevisionable(); - $revision_metadata_fields = $revisionable ? array_values($this->entityType->getRevisionMetadataKeys()) : []; + // Nodes have all three of these fields, while custom blocks only have + // log. + // @todo Provide automatic definitions for revision metadata fields in + // https://www.drupal.org/node/2248983. + $revision_metadata_fields = array_intersect([ + 'revision_timestamp', + 'revision_uid', + 'revision_log', + ], $all_fields); + $revisionable = $this->entityType->isRevisionable(); $translatable = $this->entityType->isTranslatable(); if (!$revisionable && !$translatable) { // The base layout stores all the base field values in the base table. only in patch2: unchanged: --- a/core/lib/Drupal/Core/Entity/entity.api.php +++ b/core/lib/Drupal/Core/Entity/entity.api.php @@ -271,11 +271,6 @@ * either \Drupal\Core\Config\Entity\ConfigEntityBase or * \Drupal\Core\Entity\ContentEntityBase, with annotation for * \@ConfigEntityType or \@ContentEntityType in its documentation block. - * If you are defining a content entity type, it is recommended to extend the - * \Drupal\Core\Entity\EditorialContentEntityBase base class in order to get - * out-of-the-box support for Entity API's revisioning and publishing - * features, which will allow your entity type to be used with Drupal's - * editorial workflow provided by the Content Moderation module. * - The 'id' annotation gives the entity type ID, and the 'label' annotation * gives the human-readable name of the entity type. If you are defining a * content entity type that uses bundles, the 'bundle_label' annotation gives only in patch2: unchanged: --- /dev/null +++ b/core/lib/Drupal/Core/EventSubscriber/DefaultExceptionSubscriber.php @@ -0,0 +1,245 @@ +configFactory = $config_factory; + } + + /** + * Gets the configured error level. + * + * @return string + */ + protected function getErrorLevel() { + if (!isset($this->errorLevel)) { + $this->errorLevel = $this->configFactory->get('system.logging')->get('error_level'); + } + return $this->errorLevel; + } + + /** + * Handles any exception as a generic error page for HTML. + * + * @param \Symfony\Component\HttpKernel\Event\GetResponseForExceptionEvent $event + * The event to process. + */ + protected function onHtml(GetResponseForExceptionEvent $event) { + $exception = $event->getException(); + $error = Error::decodeException($exception); + + // Display the message if the current error reporting level allows this type + // of message to be displayed, and unconditionally in update.php. + $message = ''; + if (error_displayable($error)) { + // If error type is 'User notice' then treat it as debug information + // instead of an error message. + // @see debug() + if ($error['%type'] == 'User notice') { + $error['%type'] = 'Debug'; + } + + // Attempt to reduce verbosity by removing DRUPAL_ROOT from the file path + // in the message. This does not happen for (false) security. + $root_length = strlen(DRUPAL_ROOT); + if (substr($error['%file'], 0, $root_length) == DRUPAL_ROOT) { + $error['%file'] = substr($error['%file'], $root_length + 1); + } + + unset($error['backtrace']); + + if ($this->getErrorLevel() != ERROR_REPORTING_DISPLAY_VERBOSE) { + // Without verbose logging, use a simple message. + + // We call SafeMarkup::format directly here, rather than use t() since + // we are in the middle of error handling, and we don't want t() to + // cause further errors. + $message = SafeMarkup::format('%type: @message in %function (line %line of %file).', $error); + } + else { + // With verbose logging, we will also include a backtrace. + + $backtrace_exception = $exception; + while ($backtrace_exception->getPrevious()) { + $backtrace_exception = $backtrace_exception->getPrevious(); + } + $backtrace = $backtrace_exception->getTrace(); + // First trace is the error itself, already contained in the message. + // While the second trace is the error source and also contained in the + // message, the message doesn't contain argument values, so we output it + // once more in the backtrace. + array_shift($backtrace); + + // Generate a backtrace containing only scalar argument values. + $error['@backtrace'] = Error::formatBacktrace($backtrace); + $message = SafeMarkup::format('%type: @message in %function (line %line of %file).
@backtrace', $error); + } + } + + $content = $this->t('The website encountered an unexpected error. Please try again later.'); + $content .= $message ? '' . $message : ''; + $response = new Response($content, 500); + + if ($exception instanceof HttpExceptionInterface) { + $response->setStatusCode($exception->getStatusCode()); + $response->headers->add($exception->getHeaders()); + } + else { + $response->setStatusCode(Response::HTTP_INTERNAL_SERVER_ERROR, '500 Service unavailable (with message)'); + } + + $event->setResponse($response); + } + + /** + * Handles any exception as a generic error page for JSON. + * + * @todo This should probably check the error reporting level. + * + * @param \Symfony\Component\HttpKernel\Event\GetResponseForExceptionEvent $event + * The event to process. + */ + protected function onJson(GetResponseForExceptionEvent $event) { + $exception = $event->getException(); + $error = Error::decodeException($exception); + + // Display the message if the current error reporting level allows this type + // of message to be displayed, + $data = NULL; + if (error_displayable($error) && $message = $exception->getMessage()) { + $data = ['message' => sprintf('A fatal error occurred: %s', $message)]; + } + + $response = new JsonResponse($data, Response::HTTP_INTERNAL_SERVER_ERROR); + if ($exception instanceof HttpExceptionInterface) { + $response->setStatusCode($exception->getStatusCode()); + $response->headers->add($exception->getHeaders()); + } + + $event->setResponse($response); + } + + /** + * Handles an HttpExceptionInterface exception for unknown formats. + * + * @param \Symfony\Component\HttpKernel\Event\GetResponseForExceptionEvent $event + * The event to process. + */ + protected function onFormatUnknown(GetResponseForExceptionEvent $event) { + /** @var \Symfony\Component\HttpKernel\Exception\HttpExceptionInterface|\Exception $exception */ + $exception = $event->getException(); + + $response = new Response($exception->getMessage(), $exception->getStatusCode(), $exception->getHeaders()); + $event->setResponse($response); + } + + /** + * Handles errors for this subscriber. + * + * @param \Symfony\Component\HttpKernel\Event\GetResponseForExceptionEvent $event + * The event to process. + */ + public function onException(GetResponseForExceptionEvent $event) { + $format = $this->getFormat($event->getRequest()); + $exception = $event->getException(); + + $method = 'on' . $format; + if (!method_exists($this, $method)) { + if ($exception instanceof HttpExceptionInterface) { + $this->onFormatUnknown($event); + $response = $event->getResponse(); + $response->headers->set('Content-Type', 'text/plain'); + } + else { + $this->onHtml($event); + } + } + else { + $this->$method($event); + } + } + + /** + * Gets the error-relevant format from the request. + * + * @param \Symfony\Component\HttpFoundation\Request $request + * The request object. + * + * @return string + * The format as which to treat the exception. + */ + protected function getFormat(Request $request) { + $format = $request->query->get(MainContentViewSubscriber::WRAPPER_FORMAT, $request->getRequestFormat()); + + // These are all JSON errors for our purposes. Any special handling for + // them can/should happen in earlier listeners if desired. + if (in_array($format, ['drupal_modal', 'drupal_dialog', 'drupal_ajax'])) { + $format = 'json'; + } + + // Make an educated guess that any Accept header type that includes "json" + // can probably handle a generic JSON response for errors. As above, for + // any format this doesn't catch or that wants custom handling should + // register its own exception listener. + foreach ($request->getAcceptableContentTypes() as $mime) { + if (strpos($mime, 'html') === FALSE && strpos($mime, 'json') !== FALSE) { + $format = 'json'; + } + } + + return $format; + } + + /** + * Registers the methods in this class that should be listeners. + * + * @return array + * An array of event listener definitions. + */ + public static function getSubscribedEvents() { + $events[KernelEvents::EXCEPTION][] = ['onException', -256]; + return $events; + } + +} only in patch2: unchanged: --- a/core/lib/Drupal/Core/EventSubscriber/ExceptionJsonSubscriber.php +++ b/core/lib/Drupal/Core/EventSubscriber/ExceptionJsonSubscriber.php @@ -14,7 +14,7 @@ class ExceptionJsonSubscriber extends HttpExceptionSubscriberBase { * {@inheritdoc} */ protected function getHandledFormats() { - return ['json', 'drupal_modal', 'drupal_dialog', 'drupal_ajax']; + return ['json']; } /** only in patch2: unchanged: --- a/core/lib/Drupal/Core/EventSubscriber/FinalExceptionSubscriber.php +++ /dev/null @@ -1,195 +0,0 @@ -configFactory = $config_factory; - } - - /** - * Gets the configured error level. - * - * @return string - */ - protected function getErrorLevel() { - if (!isset($this->errorLevel)) { - $this->errorLevel = $this->configFactory->get('system.logging')->get('error_level'); - } - return $this->errorLevel; - } - - /** - * Handles exceptions for this subscriber. - * - * @param \Symfony\Component\HttpKernel\Event\GetResponseForExceptionEvent $event - * The event to process. - */ - public function onException(GetResponseForExceptionEvent $event) { - $exception = $event->getException(); - $error = Error::decodeException($exception); - - // Display the message if the current error reporting level allows this type - // of message to be displayed, and unconditionally in update.php. - $message = ''; - if ($this->isErrorDisplayable($error)) { - // If error type is 'User notice' then treat it as debug information - // instead of an error message. - // @see debug() - if ($error['%type'] == 'User notice') { - $error['%type'] = 'Debug'; - } - - $error = $this->simplifyFileInError($error); - - unset($error['backtrace']); - - if (!$this->isErrorLevelVerbose()) { - // Without verbose logging, use a simple message. - - // We call SafeMarkup::format directly here, rather than use t() since - // we are in the middle of error handling, and we don't want t() to - // cause further errors. - $message = SafeMarkup::format('%type: @message in %function (line %line of %file).', $error); - } - else { - // With verbose logging, we will also include a backtrace. - - $backtrace_exception = $exception; - while ($backtrace_exception->getPrevious()) { - $backtrace_exception = $backtrace_exception->getPrevious(); - } - $backtrace = $backtrace_exception->getTrace(); - // First trace is the error itself, already contained in the message. - // While the second trace is the error source and also contained in the - // message, the message doesn't contain argument values, so we output it - // once more in the backtrace. - array_shift($backtrace); - - // Generate a backtrace containing only scalar argument values. - $error['@backtrace'] = Error::formatBacktrace($backtrace); - $message = SafeMarkup::format('%type: @message in %function (line %line of %file).
@backtrace', $error); - } - } - - $content = $this->t('The website encountered an unexpected error. Please try again later.'); - $content .= $message ? '' . $message : ''; - $response = new Response($content, 500, ['Content-Type' => 'text/plain']); - - if ($exception instanceof HttpExceptionInterface) { - $response->setStatusCode($exception->getStatusCode()); - $response->headers->add($exception->getHeaders()); - } - else { - $response->setStatusCode(Response::HTTP_INTERNAL_SERVER_ERROR, '500 Service unavailable (with message)'); - } - - $event->setResponse($response); - } - - /** - * {@inheritdoc} - */ - public static function getSubscribedEvents() { - // Run as the final (very late) KernelEvents::EXCEPTION subscriber. - $events[KernelEvents::EXCEPTION][] = ['onException', -256]; - return $events; - } - - /** - * Checks whether the error level is verbose or not. - * - * @return bool - */ - protected function isErrorLevelVerbose() { - return $this->getErrorLevel() === ERROR_REPORTING_DISPLAY_VERBOSE; - } - - /** - * Wrapper for error_displayable(). - * - * @param $error - * Optional error to examine for ERROR_REPORTING_DISPLAY_SOME. - * - * @return bool - * - * @see \error_displayable - */ - protected function isErrorDisplayable($error) { - return error_displayable($error); - } - - /** - * Attempts to reduce error verbosity in the error message's file path. - * - * Attempts to reduce verbosity by removing DRUPAL_ROOT from the file path in - * the message. This does not happen for (false) security. - * - * @param $error - * Optional error to examine for ERROR_REPORTING_DISPLAY_SOME. - * - * @return - * The updated $error. - */ - protected function simplifyFileInError($error) { - // Attempt to reduce verbosity by removing DRUPAL_ROOT from the file path - // in the message. This does not happen for (false) security. - $root_length = strlen(DRUPAL_ROOT); - if (substr($error['%file'], 0, $root_length) == DRUPAL_ROOT) { - $error['%file'] = substr($error['%file'], $root_length + 1); - } - return $error; - } - -} only in patch2: unchanged: --- a/core/lib/Drupal/Core/Extension/ThemeHandler.php +++ b/core/lib/Drupal/Core/Extension/ThemeHandler.php @@ -216,16 +216,10 @@ public function addTheme(Extension $theme) { * {@inheritdoc} */ public function refreshInfo() { + $this->reset(); $extension_config = $this->configFactory->get('core.extension'); $installed = $extension_config->get('theme'); - // Only refresh the info if a theme has been installed. Modules are - // installed before themes by the installer and this method is called during - // module installation. - if (empty($installed) && empty($this->list)) { - return; - } - $this->reset(); // @todo Avoid re-scanning all themes by retaining the original (unaltered) // theme info somewhere. $list = $this->rebuildThemeData(); only in patch2: unchanged: --- a/core/lib/Drupal/Core/Field/BaseFieldDefinition.php +++ b/core/lib/Drupal/Core/Field/BaseFieldDefinition.php @@ -89,6 +89,7 @@ public static function createFromFieldStorageDefinition(FieldStorageDefinitionIn ->setLabel($definition->getLabel()) ->setName($definition->getName()) ->setProvider($definition->getProvider()) + ->setQueryable($definition->isQueryable()) ->setRevisionable($definition->isRevisionable()) ->setSettings($definition->getSettings()) ->setTargetEntityTypeId($definition->getTargetEntityTypeId()) @@ -286,8 +287,7 @@ public function isMultiple() { * {@inheritdoc} */ public function isQueryable() { - @trigger_error('BaseFieldDefinition::isQueryable() is deprecated in Drupal 8.4.0 and will be removed before Drupal 9.0.0. Instead, you should use \Drupal\Core\Field\BaseFieldDefinition::hasCustomStorage(). See https://www.drupal.org/node/2856563.', E_USER_DEPRECATED); - return !$this->hasCustomStorage(); + return isset($this->definition['queryable']) ? $this->definition['queryable'] : !$this->isComputed(); } /** @@ -298,14 +298,8 @@ public function isQueryable() { * * @return static * The object itself for chaining. - * - * @deprecated in Drupal 8.4.0 and will be removed before Drupal 9.0.0. Use - * \Drupal\Core\Field\BaseFieldDefinition::setCustomStorage() instead. - * - * @see https://www.drupal.org/node/2856563 */ public function setQueryable($queryable) { - @trigger_error('BaseFieldDefinition::setQueryable() is deprecated in Drupal 8.4.0 and will be removed before Drupal 9.0.0. Instead, you should use \Drupal\Core\Field\BaseFieldDefinition::setCustomStorage(). See https://www.drupal.org/node/2856563.', E_USER_DEPRECATED); $this->definition['queryable'] = $queryable; return $this; } @@ -585,7 +579,7 @@ protected function getFieldItemClass() { public function __sleep() { // Do not serialize the statically cached property definitions. $vars = get_object_vars($this); - unset($vars['propertyDefinitions'], $vars['typedDataManager']); + unset($vars['propertyDefinitions']); return array_keys($vars); } only in patch2: unchanged: --- a/core/lib/Drupal/Core/Field/FieldStorageDefinitionInterface.php +++ b/core/lib/Drupal/Core/Field/FieldStorageDefinitionInterface.php @@ -109,12 +109,6 @@ public function isRevisionable(); * * @return bool * TRUE if the field is queryable. - * - * @deprecated in Drupal 8.4.0 and will be removed before Drupal 9.0.0. Use - * \Drupal\Core\Field\FieldStorageDefinitionInterface::hasCustomStorage() - * instead. - * - * @see https://www.drupal.org/node/2856563 */ public function isQueryable(); only in patch2: unchanged: --- a/core/lib/Drupal/Core/Field/Plugin/Field/FieldType/TimestampItem.php +++ b/core/lib/Drupal/Core/Field/Plugin/Field/FieldType/TimestampItem.php @@ -2,9 +2,8 @@ namespace Drupal\Core\Field\Plugin\Field\FieldType; -use Drupal\Core\Field\FieldDefinitionInterface; -use Drupal\Core\Field\FieldItemBase; use Drupal\Core\Field\FieldStorageDefinitionInterface; +use Drupal\Core\Field\FieldItemBase; use Drupal\Core\TypedData\DataDefinition; /** @@ -54,14 +53,4 @@ public static function schema(FieldStorageDefinitionInterface $field_definition) ]; } - /** - * {@inheritdoc} - */ - public static function generateSampleValue(FieldDefinitionInterface $field_definition) { - // Pick a random timestamp in the past year. - $timestamp = \Drupal::time()->getRequestTime() - mt_rand(0, 86400 * 365); - $values['value'] = $timestamp; - return $values; - } - } only in patch2: unchanged: --- a/core/lib/Drupal/Core/Field/Plugin/Field/FieldWidget/LanguageSelectWidget.php +++ b/core/lib/Drupal/Core/Field/Plugin/Field/FieldWidget/LanguageSelectWidget.php @@ -27,32 +27,7 @@ public function formElement(FieldItemListInterface $items, $delta, array $elemen $element['value'] = $element + [ '#type' => 'language_select', '#default_value' => $items[$delta]->value, - '#languages' => $this->getSetting('include_locked') ? LanguageInterface::STATE_ALL : LanguageInterface::STATE_CONFIGURABLE, - ]; - - return $element; - } - - /** - * {@inheritdoc} - */ - public static function defaultSettings() { - $settings = parent::defaultSettings(); - $settings['include_locked'] = TRUE; - - return $settings; - } - - /** - * {@inheritdoc} - */ - public function settingsForm(array $form, FormStateInterface $form_state) { - $element = parent::settingsForm($form, $form_state); - - $element['include_locked'] = [ - '#type' => 'checkbox', - '#title' => $this->t('Include locked languages such as Not specified and Not applicable'), - '#default_value' => $this->getSetting('include_locked'), + '#languages' => LanguageInterface::STATE_ALL, ]; return $element; only in patch2: unchanged: --- a/core/lib/Drupal/Core/FileTransfer/FTPExtension.php +++ b/core/lib/Drupal/Core/FileTransfer/FTPExtension.php @@ -45,7 +45,7 @@ protected function createDirectoryJailed($directory) { protected function removeDirectoryJailed($directory) { $pwd = ftp_pwd($this->connection); if (!ftp_chdir($this->connection, $directory)) { - throw new FileTransferException("Unable to change the current directory to @directory", NULL, ['@directory' => $directory]); + throw new FileTransferException("Unable to change to directory @directory", NULL, ['@directory' => $directory]); } $list = @ftp_nlist($this->connection, '.'); if (!$list) { @@ -65,7 +65,7 @@ protected function removeDirectoryJailed($directory) { } ftp_chdir($this->connection, $pwd); if (!ftp_rmdir($this->connection, $directory)) { - throw new FileTransferException("Unable to remove the directory @directory", NULL, ['@directory' => $directory]); + throw new FileTransferException("Unable to remove to directory @directory", NULL, ['@directory' => $directory]); } } @@ -74,7 +74,7 @@ protected function removeDirectoryJailed($directory) { */ protected function removeFileJailed($destination) { if (!ftp_delete($this->connection, $destination)) { - throw new FileTransferException("Unable to remove the file @file", NULL, ['@file' => $destination]); + throw new FileTransferException("Unable to remove to file @file", NULL, ['@file' => $destination]); } } only in patch2: unchanged: --- a/core/lib/Drupal/Core/Form/FormValidator.php +++ b/core/lib/Drupal/Core/Form/FormValidator.php @@ -229,12 +229,8 @@ protected function finalizeValidation(&$form, FormStateInterface &$form_state, $ * theming, and hook_form_alter functions. */ protected function doValidateForm(&$elements, FormStateInterface &$form_state, $form_id = NULL) { - // Recurse through all children, sorting the elements so that the order of - // error messages displayed to the user matches the order of elements in - // the form. Use a copy of $elements so that it is not modified by the - // sorting itself. - $elements_sorted = $elements; - foreach (Element::children($elements_sorted, TRUE) as $key) { + // Recurse through all children. + foreach (Element::children($elements) as $key) { if (isset($elements[$key]) && $elements[$key]) { $this->doValidateForm($elements[$key], $form_state); } only in patch2: unchanged: --- a/core/lib/Drupal/Core/Layout/LayoutPluginManager.php +++ b/core/lib/Drupal/Core/Layout/LayoutPluginManager.php @@ -3,13 +3,13 @@ namespace Drupal\Core\Layout; use Drupal\Component\Annotation\Plugin\Discovery\AnnotationBridgeDecorator; +use Drupal\Component\Plugin\Discovery\DerivativeDiscoveryDecorator; use Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException; use Drupal\Core\Cache\CacheBackendInterface; use Drupal\Core\Extension\ModuleHandlerInterface; use Drupal\Core\Extension\ThemeHandlerInterface; use Drupal\Core\Plugin\DefaultPluginManager; use Drupal\Core\Plugin\Discovery\AnnotatedClassDiscovery; -use Drupal\Core\Plugin\Discovery\ContainerDerivativeDiscoveryDecorator; use Drupal\Core\Plugin\Discovery\YamlDiscoveryDecorator; use Drupal\Core\Layout\Annotation\Layout; @@ -66,7 +66,7 @@ protected function getDiscovery() { $discovery = new AnnotatedClassDiscovery($this->subdir, $this->namespaces, $this->pluginDefinitionAnnotationName, $this->additionalAnnotationNamespaces); $discovery = new YamlDiscoveryDecorator($discovery, 'layouts', $this->moduleHandler->getModuleDirectories() + $this->themeHandler->getThemeDirectories()); $discovery = new AnnotationBridgeDecorator($discovery, $this->pluginDefinitionAnnotationName); - $discovery = new ContainerDerivativeDiscoveryDecorator($discovery); + $discovery = new DerivativeDiscoveryDecorator($discovery); $this->discovery = $discovery; } return $this->discovery; only in patch2: unchanged: --- a/core/lib/Drupal/Core/Plugin/DefaultSingleLazyPluginCollection.php +++ b/core/lib/Drupal/Core/Plugin/DefaultSingleLazyPluginCollection.php @@ -52,7 +52,10 @@ class DefaultSingleLazyPluginCollection extends LazyPluginCollection { */ public function __construct(PluginManagerInterface $manager, $instance_id, array $configuration) { $this->manager = $manager; - $this->addInstanceId($instance_id, $configuration); + $this->instanceId = $instance_id; + // This is still needed by the parent LazyPluginCollection class. + $this->instanceIDs = [$instance_id => $instance_id]; + $this->configuration = $configuration; } /** @@ -92,8 +95,6 @@ public function setConfiguration($configuration) { */ public function addInstanceId($id, $configuration = NULL) { $this->instanceId = $id; - // Reset the list of instance IDs since there can be only one. - $this->instanceIDs = []; parent::addInstanceId($id, $configuration); if ($configuration !== NULL) { $this->setConfiguration($configuration); only in patch2: unchanged: --- a/core/lib/Drupal/Core/TypedData/ComplexDataDefinitionBase.php +++ b/core/lib/Drupal/Core/TypedData/ComplexDataDefinitionBase.php @@ -42,7 +42,7 @@ public function getMainPropertyName() { public function __sleep() { // Do not serialize the cached property definitions. $vars = get_object_vars($this); - unset($vars['propertyDefinitions'], $vars['typedDataManager']); + unset($vars['propertyDefinitions']); return array_keys($vars); } only in patch2: unchanged: --- a/core/lib/Drupal/Core/TypedData/DataDefinition.php +++ b/core/lib/Drupal/Core/TypedData/DataDefinition.php @@ -7,8 +7,6 @@ */ class DataDefinition implements DataDefinitionInterface, \ArrayAccess { - use TypedDataTrait; - /** * The array holding values for all definition keys. * @@ -260,7 +258,7 @@ public function setSetting($setting_name, $value) { */ public function getConstraints() { $constraints = isset($this->definition['constraints']) ? $this->definition['constraints'] : []; - $constraints += $this->getTypedDataManager()->getDefaultConstraints($this); + $constraints += \Drupal::typedDataManager()->getDefaultConstraints($this); return $constraints; } @@ -342,14 +340,4 @@ public function toArray() { return $this->definition; } - /** - * {@inheritdoc} - */ - public function __sleep() { - // Never serialize the typed data manager. - $vars = get_object_vars($this); - unset($vars['typedDataManager']); - return array_keys($vars); - } - } only in patch2: unchanged: --- a/core/lib/Drupal/Core/TypedData/TypedDataManager.php +++ b/core/lib/Drupal/Core/TypedData/TypedDataManager.php @@ -117,13 +117,7 @@ public function createDataDefinition($data_type) { throw new \InvalidArgumentException("Invalid data type '$data_type' has been given"); } $class = $type_definition['definition_class']; - $data_definition = $class::createFromDataType($data_type); - - if (method_exists($data_definition, 'setTypedDataManager')) { - $data_definition->setTypedDataManager($this); - } - - return $data_definition; + return $class::createFromDataType($data_type); } /** only in patch2: unchanged: --- a/core/modules/block/src/Tests/Views/DisplayBlockTest.php +++ b/core/modules/block/src/Tests/Views/DisplayBlockTest.php @@ -286,7 +286,7 @@ public function testBlockEmptyRendering() { $this->drupalGet($url); $this->assertEqual(0, count($this->xpath('//div[contains(@class, "block-views-blocktest-view-block-block-1")]'))); - // Ensure that the view cacheability metadata is propagated even, for an + // Ensure that the view cachability metadata is propagated even, for an // empty block. $this->assertCacheTags(array_merge($block->getCacheTags(), ['block_view', 'config:block_list', 'config:views.view.test_view_block' , 'http_response', 'rendered'])); $this->assertCacheContexts(['url.query_args:_wrapper_format']); only in patch2: unchanged: --- a/core/modules/block_content/src/Entity/BlockContent.php +++ b/core/modules/block_content/src/Entity/BlockContent.php @@ -52,11 +52,6 @@ * "langcode" = "langcode", * "uuid" = "uuid" * }, - * revision_metadata_keys = { - * "revision_user" = "revision_user", - * "revision_created" = "revision_created", - * "revision_log_message" = "revision_log" - * }, * bundle_entity_type = "block_content_type", * field_ui_base_route = "entity.block_content_type.edit_form", * render_cache = FALSE, only in patch2: unchanged: --- a/core/modules/comment/comment.module +++ b/core/modules/comment/comment.module @@ -353,7 +353,8 @@ function comment_entity_storage_load($entities, $entity_type) { if (!\Drupal::entityManager()->getDefinition($entity_type)->entityClassImplements(FieldableEntityInterface::class)) { return; } - if (!\Drupal::service('comment.manager')->getFields($entity_type)) { + // @todo Investigate in https://www.drupal.org/node/2527866 why we need that. + if (!\Drupal::hasService('comment.manager') || !\Drupal::service('comment.manager')->getFields($entity_type)) { // Do not query database when entity has no comment fields. return; } only in patch2: unchanged: --- a/core/modules/comment/src/Plugin/views/argument/UserUid.php +++ b/core/modules/comment/src/Plugin/views/argument/UserUid.php @@ -3,7 +3,6 @@ namespace Drupal\comment\Plugin\views\argument; use Drupal\Core\Database\Connection; -use Drupal\Core\Database\Query\Condition; use Drupal\views\Plugin\views\argument\ArgumentPluginBase; use Symfony\Component\DependencyInjection\ContainerInterface; @@ -91,7 +90,7 @@ public function query($group_by = FALSE) { $subselect->where("c.entity_id = $this->tableAlias.$entity_id"); $subselect->condition('c.entity_type', $entity_type); - $condition = (new Condition('OR')) + $condition = db_or() ->condition("$this->tableAlias.uid", $this->argument, '=') ->exists($subselect); only in patch2: unchanged: --- a/core/modules/comment/src/Plugin/views/filter/UserUid.php +++ b/core/modules/comment/src/Plugin/views/filter/UserUid.php @@ -2,7 +2,6 @@ namespace Drupal\comment\Plugin\views\filter; -use Drupal\Core\Database\Query\Condition; use Drupal\views\Plugin\views\filter\FilterPluginBase; /** @@ -27,7 +26,7 @@ public function query() { $subselect->where("c.entity_id = $this->tableAlias.$entity_id"); $subselect->condition('c.entity_type', $entity_type); - $condition = (new Condition('OR')) + $condition = db_or() ->condition("$this->tableAlias.uid", $this->value, $this->operator) ->exists($subselect); only in patch2: unchanged: --- a/core/modules/config/tests/config_schema_test/config/schema/config_schema_test.schema.yml +++ b/core/modules/config/tests/config_schema_test/config/schema/config_schema_test.schema.yml @@ -297,41 +297,3 @@ test.double_brackets.breed: mapping: breed: type: string - -config_schema_test.schema_sequence_sort: - type: config_object - mapping: - keyed_sort: - type: sequence - orderby: key - sequence: - - type: string - value_sort: - type: sequence - orderby: value - sequence: - - type: string - no_sort: - type: sequence - sequence: - - type: string - complex_sort_value: - type: sequence - orderby: value - sequence: - - type: mapping - mapping: - foo: - type: string - bar: - type: string - complex_sort_key: - type: sequence - orderby: key - sequence: - - type: mapping - mapping: - foo: - type: string - bar: - type: string only in patch2: unchanged: --- a/core/modules/config/tests/config_test/config/install/config_test.validation.yml +++ /dev/null @@ -1,7 +0,0 @@ -llama: llama -cat: - type: kitten - count: 2 -giraffe: - hum1: hum1 - hum2: hum2 only in patch2: unchanged: --- a/core/modules/config/tests/config_test/config/schema/config_test.schema.yml +++ b/core/modules/config/tests/config_test/config/schema/config_test.schema.yml @@ -158,39 +158,3 @@ config_test.foo: config_test.bar: type: config_test.foo - -config_test.validation: - type: config_object - label: 'Configuration type' - constraints: - Callback: - callback: [\Drupal\config_test\ConfigValidation, validateMapping] - mapping: - llama: - type: string - constraints: - Callback: - callback: [\Drupal\config_test\ConfigValidation, validateLlama] - cat: - type: mapping - mapping: - type: - type: string - constraints: - Callback: - callback: [\Drupal\config_test\ConfigValidation, validateCats] - count: - type: integer - constraints: - Callback: - callback: [\Drupal\config_test\ConfigValidation, validateCatCount] - giraffe: - type: sequence - constraints: - Callback: - callback: [\Drupal\config_test\ConfigValidation, validateSequence] - sequence: - type: string - constraints: - Callback: - callback: [\Drupal\config_test\ConfigValidation, validateGiraffes] only in patch2: unchanged: --- a/core/modules/config/tests/config_test/src/ConfigValidation.php +++ /dev/null @@ -1,96 +0,0 @@ -addViolation('no valid llama'); - } - } - - /** - * Validates cats. - * - * @param string $string - * The string to validate. - * @param \Symfony\Component\Validator\Context\ExecutionContextInterface $context - * The validation execution context. - */ - public static function validateCats($string, ExecutionContextInterface $context) { - if (!in_array($string, ['kitten', 'cats', 'nyans'])) { - $context->addViolation('no valid cat'); - } - } - - /** - * Validates a number. - * - * @param int $count - * The integer to validate. - * @param \Symfony\Component\Validator\Context\ExecutionContextInterface $context - * The validation execution context. - */ - public static function validateCatCount($count, ExecutionContextInterface $context) { - if ($count <= 1) { - $context->addViolation('no enough cats'); - } - } - - /** - * Validates giraffes. - * - * @param string $string - * The string to validate. - * @param \Symfony\Component\Validator\Context\ExecutionContextInterface $context - * The validation execution context. - */ - public static function validateGiraffes($string, ExecutionContextInterface $context) { - if (strpos($string, 'hum') !== 0) { - $context->addViolation('Giraffes just hum'); - } - } - - /** - * Validates a mapping. - * - * @param array $mapping - * The data to validate. - * @param \Symfony\Component\Validator\Context\ExecutionContextInterface $context - * The validation execution context. - */ - public static function validateMapping($mapping, ExecutionContextInterface $context) { - if ($diff = array_diff(array_keys($mapping), ['llama', 'cat', 'giraffe', '_core'])) { - $context->addViolation('Missing giraffe.'); - } - } - - /** - * Validates a sequence. - * - * @param array $sequence - * The data to validate. - * @param \Symfony\Component\Validator\Context\ExecutionContextInterface $context - * The validation execution context. - */ - public static function validateSequence($sequence, ExecutionContextInterface $context) { - if (isset($sequence['invalid-key'])) { - $context->addViolation('Invalid giraffe key.'); - } - } - -} only in patch2: unchanged: --- a/core/modules/content_moderation/tests/src/Unit/ContentPreprocessTest.php +++ b/core/modules/content_moderation/tests/src/Unit/ContentPreprocessTest.php @@ -5,14 +5,13 @@ use Drupal\content_moderation\ContentPreprocess; use Drupal\Core\Routing\CurrentRouteMatch; use Drupal\node\Entity\Node; -use Drupal\Tests\UnitTestCase; /** * @coversDefaultClass \Drupal\content_moderation\ContentPreprocess * * @group content_moderation */ -class ContentPreprocessTest extends UnitTestCase { +class ContentPreprocessTest extends \PHPUnit_Framework_TestCase { /** * @covers ::isLatestVersionPage only in patch2: unchanged: --- a/core/modules/content_moderation/tests/src/Unit/LatestRevisionCheckTest.php +++ b/core/modules/content_moderation/tests/src/Unit/LatestRevisionCheckTest.php @@ -9,14 +9,13 @@ use Drupal\node\Entity\Node; use Drupal\content_moderation\Access\LatestRevisionCheck; use Drupal\content_moderation\ModerationInformation; -use Drupal\Tests\UnitTestCase; use Symfony\Component\Routing\Route; /** * @coversDefaultClass \Drupal\content_moderation\Access\LatestRevisionCheck * @group content_moderation */ -class LatestRevisionCheckTest extends UnitTestCase { +class LatestRevisionCheckTest extends \PHPUnit_Framework_TestCase { /** * Test the access check of the LatestRevisionCheck service. only in patch2: unchanged: --- a/core/modules/content_moderation/tests/src/Unit/ModerationInformationTest.php +++ b/core/modules/content_moderation/tests/src/Unit/ModerationInformationTest.php @@ -10,14 +10,13 @@ use Drupal\Core\Entity\EntityTypeManagerInterface; use Drupal\Core\Session\AccountInterface; use Drupal\content_moderation\ModerationInformation; -use Drupal\Tests\UnitTestCase; use Drupal\workflows\WorkflowInterface; /** * @coversDefaultClass \Drupal\content_moderation\ModerationInformation * @group content_moderation */ -class ModerationInformationTest extends UnitTestCase { +class ModerationInformationTest extends \PHPUnit_Framework_TestCase { /** * Builds a mock user. only in patch2: unchanged: --- a/core/modules/content_moderation/tests/src/Unit/StateTransitionValidationTest.php +++ b/core/modules/content_moderation/tests/src/Unit/StateTransitionValidationTest.php @@ -7,7 +7,6 @@ use Drupal\Core\Entity\ContentEntityInterface; use Drupal\Core\Session\AccountInterface; use Drupal\content_moderation\StateTransitionValidation; -use Drupal\Tests\UnitTestCase; use Drupal\workflows\Entity\Workflow; use Drupal\workflows\WorkflowTypeInterface; use Drupal\workflows\WorkflowTypeManager; @@ -17,7 +16,7 @@ * @coversDefaultClass \Drupal\content_moderation\StateTransitionValidation * @group content_moderation */ -class StateTransitionValidationTest extends UnitTestCase { +class StateTransitionValidationTest extends \PHPUnit_Framework_TestCase { /** * Verifies user-aware transition validation. @@ -63,9 +62,6 @@ protected function setUpModerationInformation(ContentEntityInterface $entity) { // mocked. $container = new ContainerBuilder(); $workflow_type = $this->prophesize(WorkflowTypeInterface::class); - $workflow_type->setConfiguration(Argument::any())->will(function ($arguments) { - $this->getConfiguration()->willReturn($arguments[0]); - }); $workflow_type->decorateState(Argument::any())->willReturnArgument(0); $workflow_type->decorateTransition(Argument::any())->willReturnArgument(0); $workflow_manager = $this->prophesize(WorkflowTypeManager::class); only in patch2: unchanged: --- a/core/modules/contextual/contextual.module +++ b/core/modules/contextual/contextual.module @@ -36,7 +36,6 @@ function contextual_toolbar() { '#attributes' => [ 'class' => ['toolbar-icon', 'toolbar-icon-edit'], 'aria-pressed' => 'false', - 'type' => 'button', ], ], '#wrapper_attributes' => [ only in patch2: unchanged: --- a/core/modules/datetime/src/Plugin/Field/FieldFormatter/DateTimeCustomFormatter.php +++ b/core/modules/datetime/src/Plugin/Field/FieldFormatter/DateTimeCustomFormatter.php @@ -32,18 +32,30 @@ public static function defaultSettings() { * {@inheritdoc} */ public function viewElements(FieldItemListInterface $items, $langcode) { - // @todo Evaluate removing this method in - // https://www.drupal.org/node/2793143 to determine if the behavior and - // markup in the base class implementation can be used instead. $elements = []; foreach ($items as $delta => $item) { + $output = ''; if (!empty($item->date)) { /** @var \Drupal\Core\Datetime\DrupalDateTime $date */ $date = $item->date; - $elements[$delta] = $this->buildDate($date); + if ($this->getFieldSetting('datetime_type') == 'date') { + // A date without time will pick up the current time, use the default. + datetime_date_default_time($date); + } + $this->setTimeZone($date); + + $output = $this->formatDate($date); } + $elements[$delta] = [ + '#markup' => $output, + '#cache' => [ + 'contexts' => [ + 'timezone', + ], + ], + ]; } return $elements; only in patch2: unchanged: --- a/core/modules/datetime/src/Plugin/Field/FieldFormatter/DateTimeDefaultFormatter.php +++ b/core/modules/datetime/src/Plugin/Field/FieldFormatter/DateTimeDefaultFormatter.php @@ -3,6 +3,7 @@ namespace Drupal\datetime\Plugin\Field\FieldFormatter; use Drupal\Core\Datetime\DrupalDateTime; +use Drupal\Core\Field\FieldItemListInterface; use Drupal\Core\Form\FormStateInterface; /** @@ -30,6 +31,59 @@ public static function defaultSettings() { /** * {@inheritdoc} */ + public function viewElements(FieldItemListInterface $items, $langcode) { + $elements = []; + + foreach ($items as $delta => $item) { + $output = ''; + $iso_date = ''; + + if ($item->date) { + /** @var \Drupal\Core\Datetime\DrupalDateTime $date */ + $date = $item->date; + + if ($this->getFieldSetting('datetime_type') == 'date') { + // A date without time will pick up the current time, use the default. + datetime_date_default_time($date); + } + + // Create the ISO date in Universal Time. + $iso_date = $date->format("Y-m-d\TH:i:s") . 'Z'; + + $this->setTimeZone($date); + + $output = $this->formatDate($date); + } + + // Display the date using theme datetime. + $elements[$delta] = [ + '#cache' => [ + 'contexts' => [ + 'timezone', + ], + ], + '#theme' => 'time', + '#text' => $output, + '#html' => FALSE, + '#attributes' => [ + 'datetime' => $iso_date, + ], + ]; + if (!empty($item->_attributes)) { + $elements[$delta]['#attributes'] += $item->_attributes; + // Unset field item attributes since they have been included in the + // formatter output and should not be rendered in the field template. + unset($item->_attributes); + } + } + + return $elements; + + } + + /** + * {@inheritdoc} + */ protected function formatDate($date) { $format_type = $this->getSetting('format_type'); $timezone = $this->getSetting('timezone_override') ?: $date->getTimezone()->getName(); only in patch2: unchanged: --- a/core/modules/datetime/src/Plugin/Field/FieldFormatter/DateTimeFormatterBase.php +++ b/core/modules/datetime/src/Plugin/Field/FieldFormatter/DateTimeFormatterBase.php @@ -6,7 +6,6 @@ use Drupal\Core\Datetime\DrupalDateTime; use Drupal\Core\Entity\EntityStorageInterface; use Drupal\Core\Field\FieldDefinitionInterface; -use Drupal\Core\Field\FieldItemListInterface; use Drupal\Core\Field\FormatterBase; use Drupal\Core\Form\FormStateInterface; use Drupal\Core\Plugin\ContainerFactoryPluginInterface; @@ -119,30 +118,6 @@ public function settingsSummary() { } /** - * {@inheritdoc} - */ - public function viewElements(FieldItemListInterface $items, $langcode) { - $elements = []; - - foreach ($items as $delta => $item) { - if ($item->date) { - /** @var \Drupal\Core\Datetime\DrupalDateTime $date */ - $date = $item->date; - $elements[$delta] = $this->buildDateWithIsoAttribute($date); - - if (!empty($item->_attributes)) { - $elements[$delta]['#attributes'] += $item->_attributes; - // Unset field item attributes since they have been included in the - // formatter output and should not be rendered in the field template. - unset($item->_attributes); - } - } - } - - return $elements; - } - - /** * Creates a formatted date value as a string. * * @param object $date @@ -192,69 +167,4 @@ protected function getFormatSettings() { return $settings; } - /** - * Creates a render array from a date object. - * - * @param \Drupal\Core\Datetime\DrupalDateTime $date - * A date object. - * - * @return array - * A render array. - */ - protected function buildDate(DrupalDateTime $date) { - if ($this->getFieldSetting('datetime_type') == DateTimeItem::DATETIME_TYPE_DATE) { - // A date without time will pick up the current time, use the default. - datetime_date_default_time($date); - } - $this->setTimeZone($date); - - $build = [ - '#markup' => $this->formatDate($date), - '#cache' => [ - 'contexts' => [ - 'timezone', - ], - ], - ]; - - return $build; - } - - /** - * Creates a render array from a date object with ISO date attribute. - * - * @param \Drupal\Core\Datetime\DrupalDateTime $date - * A date object. - * - * @return array - * A render array. - */ - protected function buildDateWithIsoAttribute(DrupalDateTime $date) { - if ($this->getFieldSetting('datetime_type') == DateTimeItem::DATETIME_TYPE_DATE) { - // A date without time will pick up the current time, use the default. - datetime_date_default_time($date); - } - - // Create the ISO date in Universal Time. - $iso_date = $date->format("Y-m-d\TH:i:s") . 'Z'; - - $this->setTimeZone($date); - - $build = [ - '#theme' => 'time', - '#text' => $this->formatDate($date), - '#html' => FALSE, - '#attributes' => [ - 'datetime' => $iso_date, - ], - '#cache' => [ - 'contexts' => [ - 'timezone', - ], - ], - ]; - - return $build; - } - } only in patch2: unchanged: --- a/core/modules/datetime/src/Plugin/Field/FieldFormatter/DateTimePlainFormatter.php +++ b/core/modules/datetime/src/Plugin/Field/FieldFormatter/DateTimePlainFormatter.php @@ -25,12 +25,27 @@ public function viewElements(FieldItemListInterface $items, $langcode) { $elements = []; foreach ($items as $delta => $item) { + $output = ''; if (!empty($item->date)) { /** @var \Drupal\Core\Datetime\DrupalDateTime $date */ $date = $item->date; - $elements[$delta] = $this->buildDate($date); + if ($this->getFieldSetting('datetime_type') == 'date') { + // A date without time will pick up the current time, use the default. + datetime_date_default_time($date); + } + $this->setTimeZone($date); + + $output = $this->formatDate($date); } + $elements[$delta] = [ + '#cache' => [ + 'contexts' => [ + 'timezone', + ], + ], + '#markup' => $output, + ]; } return $elements; only in patch2: unchanged: --- a/core/modules/datetime_range/src/DateTimeRangeTrait.php +++ b/core/modules/datetime_range/src/DateTimeRangeTrait.php @@ -2,7 +2,8 @@ namespace Drupal\datetime_range; -use Drupal\Core\Field\FieldItemListInterface; +use Drupal\Core\Datetime\DrupalDateTime; +use Drupal\datetime\Plugin\Field\FieldType\DateTimeItem; /** * Provides friendly methods for datetime range. @@ -10,40 +11,68 @@ trait DateTimeRangeTrait { /** - * {@inheritdoc} + * Creates a render array from a date object. + * + * @param \Drupal\Core\Datetime\DrupalDateTime $date + * A date object. + * + * @return array + * A render array. */ - public function viewElements(FieldItemListInterface $items, $langcode) { - $elements = []; - $separator = $this->getSetting('separator'); - - foreach ($items as $delta => $item) { - if (!empty($item->start_date) && !empty($item->end_date)) { - /** @var \Drupal\Core\Datetime\DrupalDateTime $start_date */ - $start_date = $item->start_date; - /** @var \Drupal\Core\Datetime\DrupalDateTime $end_date */ - $end_date = $item->end_date; - - if ($start_date->getTimestamp() !== $end_date->getTimestamp()) { - $elements[$delta] = [ - 'start_date' => $this->buildDateWithIsoAttribute($start_date), - 'separator' => ['#plain_text' => ' ' . $separator . ' '], - 'end_date' => $this->buildDateWithIsoAttribute($end_date), - ]; - } - else { - $elements[$delta] = $this->buildDateWithIsoAttribute($start_date); - - if (!empty($item->_attributes)) { - $elements[$delta]['#attributes'] += $item->_attributes; - // Unset field item attributes since they have been included in the - // formatter output and should not be rendered in the field template. - unset($item->_attributes); - } - } - } + protected function buildDate(DrupalDateTime $date) { + if ($this->getFieldSetting('datetime_type') == DateTimeItem::DATETIME_TYPE_DATE) { + // A date without time will pick up the current time, use the default. + datetime_date_default_time($date); } + $this->setTimeZone($date); - return $elements; + $build = [ + '#plain_text' => $this->formatDate($date), + '#cache' => [ + 'contexts' => [ + 'timezone', + ], + ], + ]; + + return $build; + } + + /** + * Creates a render array from a date object with ISO date attribute. + * + * @param \Drupal\Core\Datetime\DrupalDateTime $date + * A date object. + * + * @return array + * A render array. + */ + protected function buildDateWithIsoAttribute(DrupalDateTime $date) { + if ($this->getFieldSetting('datetime_type') == DateTimeItem::DATETIME_TYPE_DATE) { + // A date without time will pick up the current time, use the default. + datetime_date_default_time($date); + } + + // Create the ISO date in Universal Time. + $iso_date = $date->format("Y-m-d\TH:i:s") . 'Z'; + + $this->setTimeZone($date); + + $build = [ + '#theme' => 'time', + '#text' => $this->formatDate($date), + '#html' => FALSE, + '#attributes' => [ + 'datetime' => $iso_date, + ], + '#cache' => [ + 'contexts' => [ + 'timezone', + ], + ], + ]; + + return $build; } } only in patch2: unchanged: --- a/core/modules/datetime_range/src/Plugin/Field/FieldFormatter/DateRangeCustomFormatter.php +++ b/core/modules/datetime_range/src/Plugin/Field/FieldFormatter/DateRangeCustomFormatter.php @@ -38,9 +38,6 @@ public static function defaultSettings() { * {@inheritdoc} */ public function viewElements(FieldItemListInterface $items, $langcode) { - // @todo Evaluate removing this method in - // https://www.drupal.org/node/2793143 to determine if the behavior and - // markup in the base class implementation can be used instead. $elements = []; $separator = $this->getSetting('separator'); only in patch2: unchanged: --- a/core/modules/datetime_range/src/Plugin/Field/FieldFormatter/DateRangeDefaultFormatter.php +++ b/core/modules/datetime_range/src/Plugin/Field/FieldFormatter/DateRangeDefaultFormatter.php @@ -2,6 +2,7 @@ namespace Drupal\datetime_range\Plugin\Field\FieldFormatter; +use Drupal\Core\Field\FieldItemListInterface; use Drupal\Core\Form\FormStateInterface; use Drupal\datetime\Plugin\Field\FieldFormatter\DateTimeDefaultFormatter; use Drupal\datetime_range\DateTimeRangeTrait; @@ -37,6 +38,42 @@ public static function defaultSettings() { /** * {@inheritdoc} */ + public function viewElements(FieldItemListInterface $items, $langcode) { + $elements = []; + $separator = $this->getSetting('separator'); + + foreach ($items as $delta => $item) { + if (!empty($item->start_date) && !empty($item->end_date)) { + /** @var \Drupal\Core\Datetime\DrupalDateTime $start_date */ + $start_date = $item->start_date; + /** @var \Drupal\Core\Datetime\DrupalDateTime $end_date */ + $end_date = $item->end_date; + + if ($start_date->getTimestamp() !== $end_date->getTimestamp()) { + $elements[$delta] = [ + 'start_date' => $this->buildDateWithIsoAttribute($start_date), + 'separator' => ['#plain_text' => ' ' . $separator . ' '], + 'end_date' => $this->buildDateWithIsoAttribute($end_date), + ]; + } + else { + $elements[$delta] = $this->buildDateWithIsoAttribute($start_date); + if (!empty($item->_attributes)) { + $elements[$delta]['#attributes'] += $item->_attributes; + // Unset field item attributes since they have been included in the + // formatter output and should not be rendered in the field template. + unset($item->_attributes); + } + } + } + } + + return $elements; + } + + /** + * {@inheritdoc} + */ public function settingsForm(array $form, FormStateInterface $form_state) { $form = parent::settingsForm($form, $form_state); only in patch2: unchanged: --- a/core/modules/datetime_range/src/Plugin/Field/FieldFormatter/DateRangePlainFormatter.php +++ b/core/modules/datetime_range/src/Plugin/Field/FieldFormatter/DateRangePlainFormatter.php @@ -57,13 +57,6 @@ public function viewElements(FieldItemListInterface $items, $langcode) { } else { $elements[$delta] = $this->buildDate($start_date); - - if (!empty($item->_attributes)) { - $elements[$delta]['#attributes'] += $item->_attributes; - // Unset field item attributes since they have been included in the - // formatter output and should not be rendered in the field template. - unset($item->_attributes); - } } } } only in patch2: unchanged: --- a/core/modules/datetime_range/tests/src/Functional/DateRangeFieldTest.php +++ b/core/modules/datetime_range/tests/src/Functional/DateRangeFieldTest.php @@ -170,16 +170,6 @@ public function testDateRangeField() { $output = $this->renderTestEntity($id); $this->assertContains($expected, $output, new FormattableMarkup('Formatted date field using daterange_custom format displayed as %expected.', ['%expected' => $expected])); - // Test that allowed markup in custom format is preserved and XSS is - // removed. - $this->displayOptions['settings']['date_format'] = '\\<\\s\\t\\r\\o\\n\\g\\>m/d/Y\\<\\/\\s\\t\\r\\o\\n\\g\\>\\<\\s\\c\\r\\i\\p\\t\\>\\a\\l\\e\\r\\t\\(\\S\\t\\r\\i\\n\\g\\.\\f\\r\\o\\m\\C\\h\\a\\r\\C\\o\\d\\e\\(\\8\\8\\,\\8\\3\\,\\8\\3\\)\\)\\<\\/\\s\\c\\r\\i\\p\\t\\>'; - entity_get_display($this->field->getTargetEntityTypeId(), $this->field->getTargetBundle(), 'full') - ->setComponent($field_name, $this->displayOptions) - ->save(); - $expected = '' . $start_date->format('m/d/Y') . 'alert(String.fromCharCode(88,83,83)) - ' . $end_date->format('m/d/Y') . 'alert(String.fromCharCode(88,83,83))'; - $output = $this->renderTestEntity($id); - $this->assertContains($expected, $output, new FormattableMarkup('Formatted date field using daterange_custom format displayed as %expected.', ['%expected' => $expected])); - // Test formatters when start date and end date are the same $this->drupalGet('entity_test/add'); $value = '2012-12-31 00:00:00'; only in patch2: unchanged: --- a/core/modules/editor/src/Tests/QuickEditIntegrationLoadingTest.php +++ b/core/modules/editor/src/Tests/QuickEditIntegrationLoadingTest.php @@ -89,12 +89,12 @@ public function testUsersWithoutPermission() { $response = $this->drupalPost('editor/' . 'node/1/body/en/full', '', [], ['query' => [MainContentViewSubscriber::WRAPPER_FORMAT => 'drupal_ajax']]); $this->assertResponse(403); if (!$user->hasPermission('access in-place editing')) { - $message = "The 'access in-place editing' permission is required."; + $message = "A fatal error occurred: The 'access in-place editing' permission is required."; + $this->assertIdentical(Json::encode(['message' => $message]), $response); } else { - $message = ''; + $this->assertIdentical('{}', $response); } - $this->assertIdentical(Json::encode(['message' => $message]), $response); } } only in patch2: unchanged: --- a/core/modules/editor/tests/src/Kernel/QuickEditIntegrationTest.php +++ b/core/modules/editor/tests/src/Kernel/QuickEditIntegrationTest.php @@ -9,7 +9,7 @@ use Drupal\entity_test\Entity\EntityTest; use Drupal\quickedit\MetadataGenerator; use Drupal\Tests\quickedit\Kernel\QuickEditTestBase; -use Drupal\quickedit_test\MockQuickEditEntityFieldAccessCheck; +use Drupal\quickedit_test\MockEditEntityFieldAccessCheck; use Drupal\editor\EditorController; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpKernel\Event\FilterResponseEvent; @@ -52,7 +52,7 @@ class QuickEditIntegrationTest extends QuickEditTestBase { /** * The access checker object to be used by the metadata generator object. * - * @var \Drupal\quickedit\Access\QuickEditEntityFieldAccessCheckInterface + * @var \Drupal\quickedit\Access\EditEntityFieldAccessCheckInterface */ protected $accessChecker; @@ -165,7 +165,7 @@ public function testEditorSelection() { */ public function testMetadata() { $this->editorManager = $this->container->get('plugin.manager.quickedit.editor'); - $this->accessChecker = new MockQuickEditEntityFieldAccessCheck(); + $this->accessChecker = new MockEditEntityFieldAccessCheck(); $this->editorSelector = $this->container->get('quickedit.editor.selector'); $this->metadataGenerator = new MetadataGenerator($this->accessChecker, $this->editorSelector, $this->editorManager); only in patch2: unchanged: --- a/core/modules/field/tests/src/Kernel/EntityReference/Views/EntityReferenceRelationshipTest.php +++ b/core/modules/field/tests/src/Kernel/EntityReference/Views/EntityReferenceRelationshipTest.php @@ -34,7 +34,7 @@ class EntityReferenceRelationshipTest extends ViewsKernelTestBase { 'test_entity_reference_entity_test_mul_view', 'test_entity_reference_reverse_entity_test_mul_view', 'test_entity_reference_group_by_empty_relationships', - ]; + ]; /** * Modules to install. only in patch2: unchanged: --- a/core/modules/field/tests/src/Kernel/Timestamp/TimestampItemTest.php +++ /dev/null @@ -1,91 +0,0 @@ -fieldStorage = FieldStorageConfig::create([ - 'field_name' => 'field_timestamp', - 'type' => 'timestamp', - 'entity_type' => 'entity_test', - ]); - $this->fieldStorage->save(); - $this->field = FieldConfig::create([ - 'field_storage' => $this->fieldStorage, - 'bundle' => 'entity_test', - ]); - $this->field->save(); - } - - /** - * Tests using entity fields of the datetime field type. - */ - public function testDateTime() { - // Verify entity creation. - $entity = EntityTest::create(); - $value = 1488914208; - $entity->field_timestamp = $value; - $entity->name->value = $this->randomMachineName(); - $this->entityValidateAndSave($entity); - - // Verify entity has been created properly. - $id = $entity->id(); - $entity = EntityTest::load($id); - $this->assertTrue($entity->field_timestamp instanceof FieldItemListInterface, 'Field implements interface.'); - $this->assertTrue($entity->field_timestamp[0] instanceof FieldItemInterface, 'Field item implements interface.'); - $this->assertEquals($entity->field_timestamp->value, $value); - $this->assertEquals($entity->field_timestamp[0]->value, $value); - - // Verify changing the date value. - $new_value = 1488914000; - $entity->field_timestamp->value = $new_value; - $this->assertEquals($entity->field_timestamp->value, $new_value); - - // Read changed entity and assert changed values. - $this->entityValidateAndSave($entity); - $entity = EntityTest::load($id); - $this->assertEquals($entity->field_timestamp->value, $new_value); - - // Test sample item generation. - $entity = EntityTest::create(); - $entity->field_timestamp->generateSampleItems(); - $this->entityValidateAndSave($entity); - - // Ensure there is sample value a generated for the field. - $this->assertNotNull($entity->field_timestamp->value); - } - -} only in patch2: unchanged: --- a/core/modules/field_ui/src/Tests/FieldUIDeleteTest.php +++ b/core/modules/field_ui/src/Tests/FieldUIDeleteTest.php @@ -5,7 +5,6 @@ use Drupal\field\Entity\FieldConfig; use Drupal\field\Entity\FieldStorageConfig; use Drupal\simpletest\WebTestBase; -use Drupal\views\Entity\View; use Drupal\views\Tests\ViewTestData; /** @@ -75,13 +74,6 @@ public function testDeleteField() { \Drupal::service('module_installer')->install(['views']); ViewTestData::createTestViews(get_class($this), ['field_test_views']); - $view = View::load('test_view_field_delete'); - $this->assertNotNull($view); - $this->assertTrue($view->status()); - // Test that the View depends on the field. - $dependencies = $view->getDependencies() + ['config' => []]; - $this->assertTrue(in_array("field.storage.node.$field_name", $dependencies['config'])); - // Check the config dependencies of the first field, the field storage must // not be shown as being deleted yet. $this->drupalGet("$bundle_path1/fields/node.$type_name1.$field_name/delete"); @@ -99,13 +91,13 @@ public function testDeleteField() { // Check the config dependencies of the first field. $this->drupalGet("$bundle_path2/fields/node.$type_name2.$field_name/delete"); - $this->assertText(t('The listed configuration will be updated.')); + $this->assertText(t('The listed configuration will be deleted.')); $this->assertText(t('View')); $this->assertText('test_view_field_delete'); $xml = $this->cssSelect('#edit-entity-deletes'); - // Test that nothing is scheduled for deletion. - $this->assertFalse(isset($xml[0]), 'The field currently being deleted is not shown in the entity deletions.'); + // Remove the wrapping HTML. + $this->assertIdentical(FALSE, strpos($xml[0]->asXml(), $field_label), 'The currently being deleted field is not shown in the entity deletions.'); // Delete the second field. $this->fieldUIDeleteField($bundle_path2, "node.$type_name2.$field_name", $field_label, $type_name2); @@ -114,14 +106,6 @@ public function testDeleteField() { $this->assertNull(FieldConfig::loadByName('node', $type_name2, $field_name), 'Field was deleted.'); // Check that the field storage was deleted too. $this->assertNull(FieldStorageConfig::loadByName('node', $field_name), 'Field storage was deleted.'); - - // Test that the View isn't deleted and has been disabled. - $view = View::load('test_view_field_delete'); - $this->assertNotNull($view); - $this->assertFalse($view->status()); - // Test that the View no longer depends on the deleted field. - $dependencies = $view->getDependencies() + ['config' => []]; - $this->assertFalse(in_array("field.storage.node.$field_name", $dependencies['config'])); } } only in patch2: unchanged: --- a/core/modules/file/tests/src/Functional/FileFieldTestBase.php +++ b/core/modules/file/tests/src/Functional/FileFieldTestBase.php @@ -259,7 +259,7 @@ public function replaceNodeFile($file, $field_name, $nid, $new_revision = TRUE) /** * Asserts that a file exists physically on disk. * - * Overrides PHPUnit\Framework\Assert::assertFileExists() to also work with + * Overrides PHPUnit_Framework_Assert::assertFileExists() to also work with * file entities. * * @param \Drupal\File\FileInterface|string $file @@ -286,7 +286,7 @@ public function assertFileEntryExists($file, $message = NULL) { /** * Asserts that a file does not exist on disk. * - * Overrides PHPUnit\Framework\Assert::assertFileExists() to also work with + * Overrides PHPUnit_Framework_Assert::assertFileExists() to also work with * file entities. * * @param \Drupal\File\FileInterface|string $file only in patch2: unchanged: --- a/core/modules/forum/src/Form/ContainerForm.php +++ b/core/modules/forum/src/Form/ContainerForm.php @@ -20,8 +20,9 @@ class ContainerForm extends ForumForm { * {@inheritdoc} */ public function form(array $form, FormStateInterface $form_state) { + $taxonomy_term = $this->entity; // Build the bulk of the form from the parent forum form. - $form = parent::form($form, $form_state); + $form = parent::form($form, $form_state, $taxonomy_term); // Set the title and description of the name field. $form['name']['#title'] = $this->t('Container name'); only in patch2: unchanged: --- a/core/modules/forum/src/Form/ForumForm.php +++ b/core/modules/forum/src/Form/ForumForm.php @@ -29,8 +29,9 @@ class ForumForm extends TermForm { * {@inheritdoc} */ public function form(array $form, FormStateInterface $form_state) { + $taxonomy_term = $this->entity; // Build the bulk of the form from the parent taxonomy term form. - $form = parent::form($form, $form_state); + $form = parent::form($form, $form_state, $taxonomy_term); // Set the title and description of the name field. $form['name']['#title'] = $this->t('Forum name'); @@ -47,7 +48,7 @@ public function form(array $form, FormStateInterface $form_state) { // Our parent field is different to the taxonomy term. $form['parent']['#tree'] = TRUE; - $form['parent'][0] = $this->forumParentSelect($this->entity->id(), $this->t('Parent')); + $form['parent'][0] = $this->forumParentSelect($taxonomy_term->id(), $this->t('Parent')); $form['#theme_wrappers'] = ['form__forum']; $this->forumFormType = $this->t('forum'); only in patch2: unchanged: --- a/core/modules/hal/tests/src/Functional/EntityResource/Editor/EditorHalJsonAnonTest.php +++ /dev/null @@ -1,30 +0,0 @@ -serializer->encode($normalization, static::$format); - // DX: 422 when incorrect entity type bundle is specified. + // DX: 400 when incorrect entity type bundle is specified. $response = $this->request($method, $url, $request_options); - $this->assertResourceErrorResponse(422, 'No entity type(s) specified', $response); + $this->assertResourceErrorResponse(400, 'No entity type(s) specified', $response); unset($normalization['_links']['type']); $request_options[RequestOptions::BODY] = $this->serializer->encode($normalization, static::$format); - // DX: 422 when no entity type bundle is specified. + // DX: 400 when no entity type bundle is specified. $response = $this->request($method, $url, $request_options); - $this->assertResourceErrorResponse(422, 'The type link relation must be specified.', $response); + $this->assertResourceErrorResponse(400, 'The type link relation must be specified.', $response); } } only in patch2: unchanged: --- a/core/modules/hal/tests/src/Functional/EntityResource/Node/NodeHalJsonAnonTest.php +++ b/core/modules/hal/tests/src/Functional/EntityResource/Node/NodeHalJsonAnonTest.php @@ -59,20 +59,20 @@ protected function getExpectedNormalizedEntity() { 'type' => [ 'href' => $this->baseUrl . '/rest/type/node/camelids', ], - $this->baseUrl . '/rest/relation/node/camelids/revision_uid' => [ + $this->baseUrl . '/rest/relation/node/camelids/uid' => [ [ 'href' => $this->baseUrl . '/user/' . $author->id() . '?_format=hal_json', + 'lang' => 'en', ], ], - $this->baseUrl . '/rest/relation/node/camelids/uid' => [ + $this->baseUrl . '/rest/relation/node/camelids/revision_uid' => [ [ 'href' => $this->baseUrl . '/user/' . $author->id() . '?_format=hal_json', - 'lang' => 'en', ], ], ], '_embedded' => [ - $this->baseUrl . '/rest/relation/node/camelids/revision_uid' => [ + $this->baseUrl . '/rest/relation/node/camelids/uid' => [ [ '_links' => [ 'self' => [ @@ -85,9 +85,10 @@ protected function getExpectedNormalizedEntity() { 'uuid' => [ ['value' => $author->uuid()] ], + 'lang' => 'en', ], ], - $this->baseUrl . '/rest/relation/node/camelids/uid' => [ + $this->baseUrl . '/rest/relation/node/camelids/revision_uid' => [ [ '_links' => [ 'self' => [ @@ -100,7 +101,6 @@ protected function getExpectedNormalizedEntity() { 'uuid' => [ ['value' => $author->uuid()] ], - 'lang' => 'en', ], ], ], only in patch2: unchanged: --- a/core/modules/hal/tests/src/Functional/EntityResource/ShortcutSet/ShortcutSetHalJsonAnonTest.php +++ /dev/null @@ -1,30 +0,0 @@ - $dimensions['width'], '#height' => $dimensions['height'], '#attributes' => $variables['attributes'], + '#uri' => $style->buildUrl($variables['uri']), '#style_name' => $variables['style_name'], ]; - // If the current image toolkit supports this file type, prepare the URI for - // the derivative image. If not, just use the original image resized to the - // dimensions specified by the style. - if ($style->supportsUri($variables['uri'])) { - $variables['image']['#uri'] = $style->buildUrl($variables['uri']); - } - else { - $variables['image']['#uri'] = $variables['uri']; - // Don't render the image by default, but allow other preprocess functions - // to override that if they need to. - $variables['image']['#access'] = FALSE; - - // Inform the site builders why their image didn't work. - \Drupal::logger('image')->warning('Could not apply @style image style to @uri because the style does not support it.', [ - '@style' => $style->label(), - '@uri' => $variables['uri'], - ]); - } - if (isset($variables['alt']) || array_key_exists('alt', $variables)) { $variables['image']['#alt'] = $variables['alt']; } only in patch2: unchanged: --- a/core/modules/image/src/Entity/ImageStyle.php +++ b/core/modules/image/src/Entity/ImageStyle.php @@ -14,11 +14,9 @@ use Drupal\image\ImageStyleInterface; use Drupal\Component\Utility\Crypt; use Drupal\Component\Utility\UrlHelper; -use Drupal\Component\Utility\Unicode; use Drupal\Core\StreamWrapper\StreamWrapperInterface; use Symfony\Component\DependencyInjection\Exception\ServiceNotFoundException; use Drupal\Core\Entity\Entity\EntityViewDisplay; - /** * Defines an image style configuration entity. * @@ -276,8 +274,9 @@ public function flush($path = NULL) { * {@inheritdoc} */ public function createDerivative($original_uri, $derivative_uri) { + // If the source file doesn't exist, return FALSE without creating folders. - $image = $this->getImageFactory()->get($original_uri); + $image = \Drupal::service('image.factory')->get($original_uri); if (!$image->isValid()) { return FALSE; } @@ -344,18 +343,6 @@ public function deleteImageEffect(ImageEffectInterface $effect) { /** * {@inheritdoc} */ - public function supportsUri($uri) { - // Only support the URI if its extension is supported by the current image - // toolkit. - return in_array( - Unicode::strtolower(pathinfo($uri, PATHINFO_EXTENSION)), - $this->getImageFactory()->getSupportedExtensions() - ); - } - - /** - * {@inheritdoc} - */ public function getEffect($effect) { return $this->getEffects()->get($effect); } @@ -422,16 +409,6 @@ protected function getImageEffectPluginManager() { } /** - * Returns the image factory. - * - * @return \Drupal\Core\Image\ImageFactory - * The image factory. - */ - protected function getImageFactory() { - return \Drupal::service('image.factory'); - } - - /** * Gets the Drupal private key. * * @return string only in patch2: unchanged: --- a/core/modules/image/src/ImageStyleInterface.php +++ b/core/modules/image/src/ImageStyleInterface.php @@ -194,15 +194,4 @@ public function addImageEffect(array $configuration); */ public function deleteImageEffect(ImageEffectInterface $effect); - /** - * Determines if this style can be applied to a given image. - * - * @param string $uri - * The URI of the image. - * - * @return bool - * TRUE if the image is supported, FALSE otherwise. - */ - public function supportsUri($uri); - } only in patch2: unchanged: --- a/core/modules/image/tests/src/Kernel/ImageFormatterTest.php +++ b/core/modules/image/tests/src/Kernel/ImageFormatterTest.php @@ -7,8 +7,6 @@ use Drupal\entity_test\Entity\EntityTest; use Drupal\field\Entity\FieldConfig; use Drupal\field\Entity\FieldStorageConfig; -use Drupal\file\Entity\File; -use Drupal\image\Entity\ImageStyle; use Drupal\Tests\field\Kernel\FieldKernelTestBase; /** @@ -101,89 +99,4 @@ public function testImageFormatterCacheTags() { $this->assertEquals($entity->{$this->fieldName}[1]->entity->getCacheTags(), $build[$this->fieldName][1]['#cache']['tags'], 'Second image cache tags is as expected'); } - /** - * Tests ImageFormatter's handling of SVG images. - * - * @requires extension gd - */ - public function testImageFormatterSvg() { - // Install the default image styles. - $this->installConfig(['image']); - - /** @var \Drupal\Core\Render\RendererInterface $renderer */ - $renderer = $this->container->get('renderer'); - - $png = File::create([ - 'uri' => 'public://test-image.png', - ]); - $png->save(); - - // We need to create an actual empty PNG, or the GD toolkit will not - // consider the image valid. - $png_resource = imagecreate(300, 300); - imagefill($png_resource, 0, 0, imagecolorallocate($png_resource, 0, 0, 0)); - imagepng($png_resource, $png->getFileUri()); - - $svg = File::create([ - 'uri' => 'public://test-image.svg', - ]); - $svg->save(); - // We don't have to put any real SVG data in here, because the GD toolkit - // won't be able to load it anyway. - touch($svg->getFileUri()); - - $entity = EntityTest::create([ - 'name' => $this->randomMachineName(), - $this->fieldName => [$png, $svg], - ]); - $entity->save(); - - // Ensure that the display is using the medium image style. - $component = $this->display->getComponent($this->fieldName); - $component['settings']['image_style'] = 'medium'; - $this->display->setComponent($this->fieldName, $component)->save(); - - $build = $this->display->build($entity); - - // The first image is a PNG, so it is supported by the GD image toolkit. - // The image style should be applied with its cache tags, image derivative - // computed with its URI and dimensions. - $this->assertCacheTags($build[$this->fieldName][0], ImageStyle::load('medium')->getCacheTags()); - $renderer->renderRoot($build[$this->fieldName][0]); - $this->assertEquals('medium', $build[$this->fieldName][0]['#image_style']); - // We check that the image URL contains the expected style directory - // structure. - $this->assertTrue(strpos($build[$this->fieldName][0]['#markup'], 'styles/medium/public/test-image.png') !== FALSE); - $this->assertTrue(strpos($build[$this->fieldName][0]['#markup'], 'width="220"') !== FALSE); - $this->assertTrue(strpos($build[$this->fieldName][0]['#markup'], 'height="220"') !== FALSE); - - // The second image is an SVG, which is not supported by the GD toolkit. - // The image style should still be applied with its cache tags, but image - // derivative will not be available so tag will point to the original - // image. - $this->assertCacheTags($build[$this->fieldName][1], ImageStyle::load('medium')->getCacheTags()); - $renderer->renderRoot($build[$this->fieldName][1]); - $this->assertEquals('medium', $build[$this->fieldName][1]['#image_style']); - // We check that the image URL does not contain the style directory - // structure. - $this->assertFalse(strpos($build[$this->fieldName][1]['#markup'], 'styles/medium/public/test-image.svg')); - // Since we did not store original image dimensions, width and height - // HTML attributes will not be present. - $this->assertFalse(strpos($build[$this->fieldName][1]['#markup'], 'width')); - $this->assertFalse(strpos($build[$this->fieldName][1]['#markup'], 'height')); - } - - /** - * Asserts that a renderable array has a set of cache tags. - * - * @param array $renderable - * The renderable array. Must have a #cache[tags] element. - * @param array $cache_tags - * The expected cache tags. - */ - protected function assertCacheTags(array $renderable, array $cache_tags) { - $diff = array_diff($cache_tags, $renderable['#cache']['tags']); - $this->assertEmpty($diff); - } - } only in patch2: unchanged: --- a/core/modules/language/config/schema/language.schema.yml +++ b/core/modules/language/config/schema/language.schema.yml @@ -131,11 +131,3 @@ condition.plugin.language: type: sequence sequence: type: string - -field.widget.settings.language_select: - type: mapping - label: 'Language format settings' - mapping: - include_locked: - type: boolean - label: 'Include locked languages' only in patch2: unchanged: --- a/core/modules/language/language.post_update.php +++ /dev/null @@ -1,28 +0,0 @@ -get('content'); - $changed = FALSE; - foreach (array_keys($content) as $element) { - if (isset($content[$element]['type']) && $content[$element]['type'] == 'language_select') { - $content[$element]['settings']['include_locked'] = TRUE; - $changed = TRUE; - } - } - if ($changed) { - $display_form->set('content', $content); - $display_form->save(); - } - } -} only in patch2: unchanged: --- a/core/modules/language/src/LanguageNegotiatorInterface.php +++ b/core/modules/language/src/LanguageNegotiatorInterface.php @@ -91,6 +91,7 @@ * } * } * } + * ?> * @endcode * * For more information, see only in patch2: unchanged: --- a/core/modules/language/src/Tests/Update/LanguageSelectWidgetUpdateTest.php +++ /dev/null @@ -1,40 +0,0 @@ -databaseDumpFiles = [ - __DIR__ . '/../../../../system/tests/fixtures/update/drupal-8.filled.standard.php.gz', - ]; - } - - /** - * Tests language_post_update_language_select_widget(). - */ - public function testLanguagePostUpdateLanguageSelectWidget() { - // Tests before the update. - $content_before = EntityFormDisplay::load('node.page.default')->get('content'); - $this->assertEqual([], $content_before['langcode']['settings']); - - // Run the update. - $this->runUpdates(); - - // Tests after the update. - $content_after = EntityFormDisplay::load('node.page.default')->get('content'); - $this->assertEqual(['include_locked' => TRUE], $content_after['langcode']['settings']); - } - -} only in patch2: unchanged: --- a/core/modules/language/tests/src/Kernel/LanguageSelectWidgetTest.php +++ /dev/null @@ -1,77 +0,0 @@ -installEntitySchema('entity_test'); - $this->installEntitySchema('user'); - - $storage = $this->container->get('entity_type.manager')->getStorage('entity_form_display'); - $this->entityFormDisplay = $storage->create([ - 'targetEntityType' => 'entity_test', - 'bundle' => 'entity_test', - 'mode' => 'default', - 'status' => TRUE, - ]); - } - - /** - * Tests the widget with the locked languages. - */ - public function testWithIncludedLockedLanguage() { - $this->entityFormDisplay->setComponent('langcode', [ - 'type' => 'language_select', - ])->save(); - $entity = EntityTest::create(['name' => $this->randomString()]); - $form = $this->container->get('entity.form_builder')->getForm($entity); - $options = array_keys($form['langcode']['widget'][0]['value']['#options']); - $this->assertSame(['en', 'und', 'zxx'], $options); - } - - /** - * Test the widget without the locked languages. - */ - public function testWithoutIncludedLockedLanguage() { - $this->entityFormDisplay->setComponent('langcode', [ - 'type' => 'language_select', - 'settings' => ['include_locked' => FALSE], - ])->save(); - $entity = EntityTest::create(['name' => $this->randomString()]); - $form = $this->container->get('entity.form_builder')->getForm($entity); - $options = array_keys($form['langcode']['widget'][0]['value']['#options']); - $this->assertSame(['en'], $options); - } - -} only in patch2: unchanged: --- a/core/modules/link/src/Plugin/Field/FieldWidget/LinkWidget.php +++ b/core/modules/link/src/Plugin/Field/FieldWidget/LinkWidget.php @@ -175,7 +175,6 @@ public function formElement(FieldItemListInterface $items, $delta, array $elemen '#element_validate' => [[get_called_class(), 'validateUriElement']], '#maxlength' => 2048, '#required' => $element['#required'], - '#link_type' => $this->getFieldSetting('link_type'), ]; // If the field is configured to support internal links, it cannot use the only in patch2: unchanged: --- a/core/modules/link/tests/src/Functional/LinkFieldTest.php +++ b/core/modules/link/tests/src/Functional/LinkFieldTest.php @@ -610,49 +610,6 @@ public function testLinkSeparateFormatter() { } /** - * Test '#link_type' property exists on 'link_default' widget. - * - * Make sure the 'link_default' widget exposes a '#link_type' property on - * its element. Modules can use it to understand if a text form element is - * a link and also which LinkItemInterface::LINK_* is (EXTERNAL, GENERIC, - * INTERNAL). - */ - public function testLinkTypeOnLinkWidget() { - - $link_type = LinkItemInterface::LINK_EXTERNAL; - $field_name = Unicode::strtolower($this->randomMachineName()); - - // Create a field with settings to validate. - $this->fieldStorage = FieldStorageConfig::create([ - 'field_name' => $field_name, - 'entity_type' => 'entity_test', - 'type' => 'link', - 'cardinality' => 1, - ]); - $this->fieldStorage->save(); - FieldConfig::create([ - 'field_storage' => $this->fieldStorage, - 'label' => 'Read more about this entity', - 'bundle' => 'entity_test', - 'settings' => [ - 'title' => DRUPAL_OPTIONAL, - 'link_type' => $link_type, - ], - ])->save(); - - $this->container->get('entity.manager') - ->getStorage('entity_form_display') - ->load('entity_test.entity_test.default') - ->setComponent($field_name, [ - 'type' => 'link_default', - ]) - ->save(); - - $form = \Drupal::service('entity.form_builder')->getForm(EntityTest::create()); - $this->assertEqual($form[$field_name]['widget'][0]['uri']['#link_type'], $link_type); - } - - /** * Renders a test_entity and returns the output. * * @param int $id only in patch2: unchanged: --- a/core/modules/locale/src/StringDatabaseStorage.php +++ b/core/modules/locale/src/StringDatabaseStorage.php @@ -3,7 +3,6 @@ namespace Drupal\locale; use Drupal\Core\Database\Connection; -use Drupal\Core\Database\Query\Condition; /** * Defines a class to store localized strings in the database. @@ -417,7 +416,7 @@ protected function dbStringSelect(array $conditions, array $options = []) { elseif ($table_alias == 't' && $join === 'leftJoin') { // Conditions for target fields when doing an outer join only make // sense if we add also OR field IS NULL. - $query->condition((new Condition('OR')) + $query->condition(db_or() ->condition($field_alias, (array) $value, 'IN') ->isNull($field_alias) ); @@ -430,7 +429,7 @@ protected function dbStringSelect(array $conditions, array $options = []) { // Process other options, string filter, query limit, etc. if (!empty($options['filters'])) { if (count($options['filters']) > 1) { - $filter = new Condition('OR'); + $filter = db_or(); $query->condition($filter); } else { only in patch2: unchanged: --- a/core/modules/migrate/tests/src/Unit/Event/EventBaseTest.php +++ b/core/modules/migrate/tests/src/Unit/Event/EventBaseTest.php @@ -3,13 +3,12 @@ namespace Drupal\Tests\migrate\Unit\Event; use Drupal\migrate\Event\EventBase; -use Drupal\Tests\UnitTestCase; /** * @coversDefaultClass \Drupal\migrate\Event\EventBase * @group migrate */ -class EventBaseTest extends UnitTestCase { +class EventBaseTest extends \PHPUnit_Framework_TestCase { /** * Test getMigration method. only in patch2: unchanged: --- a/core/modules/migrate/tests/src/Unit/Event/MigrateImportEventTest.php +++ b/core/modules/migrate/tests/src/Unit/Event/MigrateImportEventTest.php @@ -3,13 +3,12 @@ namespace Drupal\Tests\migrate\Unit\Event; use Drupal\migrate\Event\MigrateImportEvent; -use Drupal\Tests\UnitTestCase; /** * @coversDefaultClass \Drupal\migrate\Event\MigrateImportEvent * @group migrate */ -class MigrateImportEventTest extends UnitTestCase { +class MigrateImportEventTest extends \PHPUnit_Framework_TestCase { /** * Test getMigration method. only in patch2: unchanged: --- a/core/modules/node/node.permissions.yml +++ b/core/modules/node/node.permissions.yml @@ -18,13 +18,12 @@ view own unpublished content: title: 'View own unpublished content' view all revisions: title: 'View all revisions' - description: 'To view a revision, you also need permission to view the content item.' revert all revisions: title: 'Revert all revisions' - description: 'To revert a revision, you also need permission to edit the content item.' + description: 'Role requires permission view revisions and edit rights for nodes in question or administer nodes.' delete all revisions: title: 'Delete all revisions' - description: 'To delete a revision, you also need permission to delete the content item.' + description: 'Role requires permission to view revisions and delete rights for nodes in question or administer nodes.' permission_callbacks: - \Drupal\node\NodePermissions::nodeTypePermissions only in patch2: unchanged: --- a/core/modules/node/src/Entity/Node.php +++ b/core/modules/node/src/Entity/Node.php @@ -2,7 +2,9 @@ namespace Drupal\node\Entity; -use Drupal\Core\Entity\EditorialContentEntityBase; +use Drupal\Core\Entity\ContentEntityBase; +use Drupal\Core\Entity\EntityChangedTrait; +use Drupal\Core\Entity\EntityPublishedTrait; use Drupal\Core\Entity\EntityStorageInterface; use Drupal\Core\Entity\EntityTypeInterface; use Drupal\Core\Field\BaseFieldDefinition; @@ -59,11 +61,6 @@ * "published" = "status", * "uid" = "uid", * }, - * revision_metadata_keys = { - * "revision_user" = "revision_uid", - * "revision_created" = "revision_timestamp", - * "revision_log_message" = "revision_log" - * }, * bundle_entity_type = "node_type", * field_ui_base_route = "entity.node_type.edit_form", * common_reference_target = TRUE, @@ -77,7 +74,10 @@ * } * ) */ -class Node extends EditorialContentEntityBase implements NodeInterface { +class Node extends ContentEntityBase implements NodeInterface { + + use EntityChangedTrait; + use EntityPublishedTrait; /** * Whether the node is being previewed or not. @@ -281,6 +281,21 @@ public function setOwner(UserInterface $account) { /** * {@inheritdoc} */ + public function getRevisionCreationTime() { + return $this->get('revision_timestamp')->value; + } + + /** + * {@inheritdoc} + */ + public function setRevisionCreationTime($timestamp) { + $this->set('revision_timestamp', $timestamp); + return $this; + } + + /** + * {@inheritdoc} + */ public function getRevisionAuthor() { return $this->getRevisionUser(); } @@ -288,6 +303,13 @@ public function getRevisionAuthor() { /** * {@inheritdoc} */ + public function getRevisionUser() { + return $this->get('revision_uid')->entity; + } + + /** + * {@inheritdoc} + */ public function setRevisionAuthorId($uid) { $this->setRevisionUserId($uid); return $this; @@ -296,8 +318,47 @@ public function setRevisionAuthorId($uid) { /** * {@inheritdoc} */ + public function setRevisionUser(UserInterface $user) { + $this->set('revision_uid', $user); + return $this; + } + + /** + * {@inheritdoc} + */ + public function getRevisionUserId() { + return $this->get('revision_uid')->entity->id(); + } + + /** + * {@inheritdoc} + */ + public function setRevisionUserId($user_id) { + $this->set('revision_uid', $user_id); + return $this; + } + + /** + * {@inheritdoc} + */ + public function getRevisionLogMessage() { + return $this->get('revision_log')->value; + } + + /** + * {@inheritdoc} + */ + public function setRevisionLogMessage($revision_log_message) { + $this->set('revision_log', $revision_log_message); + return $this; + } + + /** + * {@inheritdoc} + */ public static function baseFieldDefinitions(EntityTypeInterface $entity_type) { $fields = parent::baseFieldDefinitions($entity_type); + $fields += static::publishedBaseFieldDefinitions($entity_type); $fields['title'] = BaseFieldDefinition::create('string') ->setLabel(t('Title')) @@ -389,6 +450,32 @@ public static function baseFieldDefinitions(EntityTypeInterface $entity_type) { ]) ->setDisplayConfigurable('form', TRUE); + $fields['revision_timestamp'] = BaseFieldDefinition::create('created') + ->setLabel(t('Revision timestamp')) + ->setDescription(t('The time that the current revision was created.')) + ->setQueryable(FALSE) + ->setRevisionable(TRUE); + + $fields['revision_uid'] = BaseFieldDefinition::create('entity_reference') + ->setLabel(t('Revision user ID')) + ->setDescription(t('The user ID of the author of the current revision.')) + ->setSetting('target_type', 'user') + ->setQueryable(FALSE) + ->setRevisionable(TRUE); + + $fields['revision_log'] = BaseFieldDefinition::create('string_long') + ->setLabel(t('Revision log message')) + ->setDescription(t('Briefly describe the changes you have made.')) + ->setRevisionable(TRUE) + ->setDefaultValue('') + ->setDisplayOptions('form', [ + 'type' => 'string_textarea', + 'weight' => 25, + 'settings' => [ + 'rows' => 4, + ], + ]); + $fields['revision_translation_affected'] = BaseFieldDefinition::create('boolean') ->setLabel(t('Revision translation affected')) ->setDescription(t('Indicates if the last edit of a translation belongs to current revision.')) only in patch2: unchanged: --- a/core/modules/node/src/NodePermissions.php +++ b/core/modules/node/src/NodePermissions.php @@ -62,15 +62,14 @@ protected function buildPermissions(NodeType $type) { ], "view $type_id revisions" => [ 'title' => $this->t('%type_name: View revisions', $type_params), - 'description' => t('To view a revision, you also need permission to view the content item.'), ], "revert $type_id revisions" => [ 'title' => $this->t('%type_name: Revert revisions', $type_params), - 'description' => t('To revert a revision, you also need permission to edit the content item.'), + 'description' => t('Role requires permission view revisions and edit rights for nodes in question, or administer nodes.'), ], "delete $type_id revisions" => [ 'title' => $this->t('%type_name: Delete revisions', $type_params), - 'description' => $this->t('To delete a revision, you also need permission to delete the content item.'), + 'description' => $this->t('Role requires permission to view revisions and delete rights for nodes in question, or administer nodes.'), ], ]; } only in patch2: unchanged: --- a/core/modules/node/src/Plugin/views/filter/Access.php +++ b/core/modules/node/src/Plugin/views/filter/Access.php @@ -2,7 +2,6 @@ namespace Drupal\node\Plugin\views\filter; -use Drupal\Core\Database\Query\Condition; use Drupal\Core\Form\FormStateInterface; use Drupal\views\Plugin\views\filter\FilterPluginBase; @@ -28,10 +27,10 @@ public function query() { $account = $this->view->getUser(); if (!$account->hasPermission('bypass node access')) { $table = $this->ensureMyTable(); - $grants = new Condition('OR'); + $grants = db_or(); foreach (node_access_grants('view', $account) as $realm => $gids) { foreach ($gids as $gid) { - $grants->condition((new Condition('AND')) + $grants->condition(db_and() ->condition($table . '.gid', $gid) ->condition($table . '.realm', $realm) ); only in patch2: unchanged: --- a/core/modules/quickedit/quickedit.services.yml +++ b/core/modules/quickedit/quickedit.services.yml @@ -3,7 +3,7 @@ services: class: Drupal\quickedit\Plugin\InPlaceEditorManager parent: default_plugin_manager access_check.quickedit.entity_field: - class: Drupal\quickedit\Access\QuickEditEntityFieldAccessCheck + class: Drupal\quickedit\Access\EditEntityFieldAccessCheck tags: - { name: access_check, applies_to: _access_quickedit_entity_field } quickedit.editor.selector: only in patch2: unchanged: --- a/core/modules/quickedit/src/Access/EditEntityFieldAccessCheck.php +++ b/core/modules/quickedit/src/Access/EditEntityFieldAccessCheck.php @@ -2,9 +2,61 @@ namespace Drupal\quickedit\Access; +use Drupal\Core\Access\AccessResult; +use Drupal\Core\Routing\Access\AccessInterface; +use Drupal\Core\Session\AccountInterface; +use Drupal\Core\Entity\EntityInterface; + /** - * @deprecated in Drupal 8.4.x and will be removed before Drupal 9.0.0. + * Access check for editing entity fields. */ -class EditEntityFieldAccessCheck extends QuickEditEntityFieldAccessCheck { +class EditEntityFieldAccessCheck implements AccessInterface, EditEntityFieldAccessCheckInterface { + + /** + * Checks Quick Edit access to the field. + * + * @param \Drupal\Core\Entity\EntityInterface $entity + * The entity containing the field. + * @param string $field_name + * The field name. + * @param string $langcode + * The langcode. + * @param \Drupal\Core\Session\AccountInterface $account + * The currently logged in account. + * + * @return \Drupal\Core\Access\AccessResultInterface + * The access result. + * + * @todo Use the $account argument: https://www.drupal.org/node/2266809. + */ + public function access(EntityInterface $entity, $field_name, $langcode, AccountInterface $account) { + if (!$this->validateRequestAttributes($entity, $field_name, $langcode)) { + return AccessResult::forbidden(); + } + + return $this->accessEditEntityField($entity, $field_name); + } + + /** + * {@inheritdoc} + */ + public function accessEditEntityField(EntityInterface $entity, $field_name) { + return $entity->access('update', NULL, TRUE)->andIf($entity->get($field_name)->access('edit', NULL, TRUE)); + } + + /** + * Validates request attributes. + */ + protected function validateRequestAttributes(EntityInterface $entity, $field_name, $langcode) { + // Validate the field name and language. + if (!$field_name || !$entity->hasField($field_name)) { + return FALSE; + } + if (!$langcode || !$entity->hasTranslation($langcode)) { + return FALSE; + } + + return TRUE; + } } only in patch2: unchanged: --- a/core/modules/quickedit/src/Access/EditEntityFieldAccessCheckInterface.php +++ b/core/modules/quickedit/src/Access/EditEntityFieldAccessCheckInterface.php @@ -2,9 +2,24 @@ namespace Drupal\quickedit\Access; +use Drupal\Core\Entity\EntityInterface; + /** - * @deprecated in Drupal 8.4.x and will be removed before Drupal 9.0.0. + * Access check for editing entity fields. */ -interface EditEntityFieldAccessCheckInterface extends QuickEditEntityFieldAccessCheckInterface { +interface EditEntityFieldAccessCheckInterface { + + /** + * Checks access to edit the requested field of the requested entity. + * + * @param \Drupal\Core\Entity\EntityInterface $entity + * The entity. + * @param string $field_name + * The field name. + * + * @return \Drupal\Core\Access\AccessResultInterface + * The access result. + */ + public function accessEditEntityField(EntityInterface $entity, $field_name); } only in patch2: unchanged: --- a/core/modules/quickedit/src/Access/QuickEditEntityFieldAccessCheck.php +++ /dev/null @@ -1,62 +0,0 @@ -validateRequestAttributes($entity, $field_name, $langcode)) { - return AccessResult::forbidden(); - } - - return $this->accessEditEntityField($entity, $field_name); - } - - /** - * {@inheritdoc} - */ - public function accessEditEntityField(EntityInterface $entity, $field_name) { - return $entity->access('update', NULL, TRUE)->andIf($entity->get($field_name)->access('edit', NULL, TRUE)); - } - - /** - * Validates request attributes. - */ - protected function validateRequestAttributes(EntityInterface $entity, $field_name, $langcode) { - // Validate the field name and language. - if (!$field_name || !$entity->hasField($field_name)) { - return FALSE; - } - if (!$langcode || !$entity->hasTranslation($langcode)) { - return FALSE; - } - - return TRUE; - } - -} only in patch2: unchanged: --- a/core/modules/quickedit/src/Access/QuickEditEntityFieldAccessCheckInterface.php +++ /dev/null @@ -1,25 +0,0 @@ -accessChecker = $access_checker; $this->editorSelector = $editor_selector; $this->editorManager = $editor_manager; only in patch2: unchanged: --- a/core/modules/quickedit/src/Tests/QuickEditLoadingTest.php +++ b/core/modules/quickedit/src/Tests/QuickEditLoadingTest.php @@ -115,12 +115,12 @@ public function testUserWithoutPermission() { $this->assertIdentical(Json::encode(['message' => "The 'access in-place editing' permission is required."]), $response); $this->assertResponse(403); - // Quick Edit's JavaScript would never hit these endpoints if the metadata + // Quick Edit's JavaScript would SearchRankingTestnever hit these endpoints if the metadata // was empty as above, but we need to make sure that malicious users aren't // able to use any of the other endpoints either. $post = ['editors[0]' => 'form'] + $this->getAjaxPageStatePostData(); $response = $this->drupalPost('quickedit/attachments', '', $post, ['query' => [MainContentViewSubscriber::WRAPPER_FORMAT => 'drupal_ajax']]); - $message = Json::encode(['message' => "The 'access in-place editing' permission is required."]); + $message = Json::encode(['message' => "A fatal error occurred: The 'access in-place editing' permission is required."]); $this->assertIdentical($message, $response); $this->assertResponse(403); $post = ['nocssjs' => 'true'] + $this->getAjaxPageStatePostData(); only in patch2: unchanged: --- a/core/modules/quickedit/tests/modules/src/MockEditEntityFieldAccessCheck.php +++ b/core/modules/quickedit/tests/modules/src/MockEditEntityFieldAccessCheck.php @@ -2,9 +2,19 @@ namespace Drupal\quickedit_test; +use Drupal\Core\Entity\EntityInterface; +use Drupal\quickedit\Access\EditEntityFieldAccessCheckInterface; + /** - * @deprecated in Drupal 8.4.x and will be removed before Drupal 9.0.0. + * Access check for editing entity fields. */ -class MockEditEntityFieldAccessCheck extends MockQuickEditEntityFieldAccessCheck { +class MockEditEntityFieldAccessCheck implements EditEntityFieldAccessCheckInterface { + + /** + * {@inheritdoc} + */ + public function accessEditEntityField(EntityInterface $entity, $field_name) { + return TRUE; + } } only in patch2: unchanged: --- a/core/modules/quickedit/tests/modules/src/MockQuickEditEntityFieldAccessCheck.php +++ /dev/null @@ -1,20 +0,0 @@ -editorManager = $this->container->get('plugin.manager.quickedit.editor'); - $this->accessChecker = new MockQuickEditEntityFieldAccessCheck(); + $this->accessChecker = new MockEditEntityFieldAccessCheck(); $this->editorSelector = new EditorSelector($this->editorManager, $this->container->get('plugin.manager.field.formatter')); $this->metadataGenerator = new MetadataGenerator($this->accessChecker, $this->editorSelector, $this->editorManager); } only in patch2: unchanged: --- a/core/modules/quickedit/tests/src/Unit/Access/QuickEditEntityFieldAccessCheckTest.php +++ b/core/modules/quickedit/tests/src/Unit/Access/EditEntityFieldAccessCheckTest.php @@ -5,21 +5,21 @@ use Drupal\Core\Access\AccessResult; use Drupal\Core\Cache\Context\CacheContextsManager; use Drupal\Core\DependencyInjection\Container; -use Drupal\quickedit\Access\QuickEditEntityFieldAccessCheck; +use Drupal\quickedit\Access\EditEntityFieldAccessCheck; use Drupal\Tests\UnitTestCase; use Drupal\Core\Language\LanguageInterface; /** - * @coversDefaultClass \Drupal\quickedit\Access\QuickEditEntityFieldAccessCheck + * @coversDefaultClass \Drupal\quickedit\Access\EditEntityFieldAccessCheck * @group Access * @group quickedit */ -class QuickEditEntityFieldAccessCheckTest extends UnitTestCase { +class EditEntityFieldAccessCheckTest extends UnitTestCase { /** * The tested access checker. * - * @var \Drupal\quickedit\Access\QuickEditEntityFieldAccessCheck + * @var \Drupal\quickedit\Access\EditEntityFieldAccessCheck */ protected $editAccessCheck; @@ -27,7 +27,7 @@ class QuickEditEntityFieldAccessCheckTest extends UnitTestCase { * {@inheritdoc} */ protected function setUp() { - $this->editAccessCheck = new QuickEditEntityFieldAccessCheck(); + $this->editAccessCheck = new EditEntityFieldAccessCheck(); $cache_contexts_manager = $this->prophesize(CacheContextsManager::class); $cache_contexts_manager->assertValidTokens()->willReturn(TRUE); @@ -40,7 +40,7 @@ protected function setUp() { /** * Provides test data for testAccess(). * - * @see \Drupal\Tests\edit\Unit\quickedit\Access\QuickEditEntityFieldAccessCheckTest::testAccess() + * @see \Drupal\Tests\edit\Unit\quickedit\Access\EditEntityFieldAccessCheckTest::testAccess() */ public function providerTestAccess() { $data = []; only in patch2: unchanged: --- a/core/modules/responsive_image/tests/src/Functional/ResponsiveImageAdminUITest.php +++ b/core/modules/responsive_image/src/Tests/ResponsiveImageAdminUITest.php @@ -1,15 +1,15 @@ assertFieldByName('keyed_styles[responsive_image_test_module.' . $case[0] . '][' . $case[1] . '][image_mapping_type]', NULL); + $this->assertFieldByName('keyed_styles[responsive_image_test_module.' . $case[0] . '][' . $case[1] . '][image_mapping_type]', ''); // Check if the image style dropdowns are present. - $this->assertFieldByName('keyed_styles[responsive_image_test_module.' . $case[0] . '][' . $case[1] . '][image_style]', NULL); + $this->assertFieldByName('keyed_styles[responsive_image_test_module.' . $case[0] . '][' . $case[1] . '][image_style]', ''); // Check if the sizes textfields are present. - $this->assertFieldByName('keyed_styles[responsive_image_test_module.' . $case[0] . '][' . $case[1] . '][sizes]', NULL); + $this->assertFieldByName('keyed_styles[responsive_image_test_module.' . $case[0] . '][' . $case[1] . '][sizes]', ''); foreach ($image_styles as $image_style_name) { // Check if the image styles are available in the dropdowns. only in patch2: unchanged: --- a/core/modules/rest/rest.module +++ b/core/modules/rest/rest.module @@ -15,13 +15,13 @@ function rest_help($route_name, RouteMatchInterface $route_match) { case 'help.page.rest': $output = ''; $output .= '
' . t('The RESTful Web Services module provides a framework for exposing REST resources on your site. It provides support for content entity types such as the main site content, comments, custom blocks, taxonomy terms, and user accounts, etc. (see the Field module help page for more information about entities). REST support for content items of the Node module is enabled by default, and support for other types of content entities can be enabled. Other modules may add support for other types of REST resources. For more information, see the online documentation for the RESTful Web Services module.', [':rest' => 'https://www.drupal.org/documentation/modules/rest', ':field' => (\Drupal::moduleHandler()->moduleExists('field')) ? \Drupal::url('help.page', ['name' => 'field']) : '#']) . '
'; + $output .= '' . t('The RESTful Web Services module provides a framework for exposing REST resources on your site. It provides support for content entities (see the Field module help page for more information about entities) such as content, users, taxonomy terms, etc.; REST support for content items of the Node module is enabled by default, and support for other types of content entities can be enabled. Other modules may add support for other types of REST resources. For more information, see the online documentation for the RESTful Web Services module.', [':rest' => 'https://www.drupal.org/documentation/modules/rest', ':field' => (\Drupal::moduleHandler()->moduleExists('field')) ? \Drupal::url('help.page', ['name' => 'field']) : '#']) . '
'; $output .= '