From 820aeb12461e53604823030183f9eaeb77ce0a15 Mon Sep 17 00:00:00 2001 From: bcweaver <brianweaver@gmail.com> Date: Wed, 16 Sep 2020 16:27:39 -0400 Subject: [PATCH] SECURITY update: drupal core 8.9.6 --- composer.json | 4 +- composer.lock | 36 +-- vendor/composer/installed.json | 40 +-- .../Controller/ControllerResolver.php | 2 +- .../ArgumentMetadataFactory.php | 2 +- .../DataCollector/ConfigDataCollector.php | 2 +- .../AddAnnotatedClassesToCachePass.php | 4 +- .../symfony/http-kernel/HttpCache/Store.php | 41 ++- vendor/symfony/http-kernel/Kernel.php | 6 +- .../ContainerControllerResolverTest.php | 27 +- .../DataCollector/ConfigDataCollectorTest.php | 6 +- .../RequestDataCollectorTest.php | 2 +- .../FilterControllerArgumentsEventTest.php | 2 +- .../EventListener/TranslatorListenerTest.php | 28 +- .../Tests/HttpCache/HttpCacheTest.php | 20 +- .../Tests/HttpCache/HttpCacheTestCase.php | 4 +- .../http-kernel/Tests/HttpCache/StoreTest.php | 33 +++ .../http-kernel/Tests/HttpKernelTest.php | 4 +- .../symfony/http-kernel/Tests/KernelTest.php | 14 +- .../Profiler/FileProfilerStorageTest.php | 10 +- web/core/lib/Drupal.php | 2 +- .../lib/Drupal/Component/Utility/Image.php | 2 - .../Core/Asset/LibraryDiscoveryParser.php | 2 +- .../DeprecatedServicePropertyTrait.php | 2 +- .../ExceptionLoggingSubscriber.php | 1 + web/core/lib/Drupal/Core/Form/FormBuilder.php | 3 +- .../lib/Drupal/Core/Logger/RfcLogLevel.php | 4 +- .../lib/Drupal/Core/Render/Element/Email.php | 8 +- web/core/misc/ajax.es6.js | 1 + web/core/misc/ajax.js | 1 + web/core/misc/autocomplete.es6.js | 1 + web/core/misc/autocomplete.js | 3 +- .../src/Functional/IpAddressBlockingTest.php | 4 +- .../tests/src/Functional/BigPipeTest.php | 11 +- .../plugins/drupalimagecaption/plugin.es6.js | 3 + .../js/plugins/drupalimagecaption/plugin.js | 3 + .../views/filter/ModerationStateFilter.php | 13 +- ...tate_filter_base_table_filter_group_or.yml | 268 ++++++++++++++++++ .../Kernel/ViewsModerationStateFilterTest.php | 32 ++- .../src/Functional/DbLogResourceTest.php | 7 +- .../dblog/tests/src/Functional/DbLogTest.php | 47 ++- .../src/Kernel/ConnectionFailureTest.php | 5 +- .../dblog/tests/src/Kernel/DbLogTest.php | 10 +- .../field/tests/src/Kernel/BulkDeleteTest.php | 15 +- .../modules/file/src/Element/ManagedFile.php | 4 + .../tests/src/Functional/FilePrivateTest.php | 16 +- .../modules/filter/src/Element/TextFormat.php | 4 +- .../filter/src/Entity/FilterFormat.php | 24 +- .../filter/src/FilterFormatInterface.php | 8 +- .../src/Plugin/Filter/FilterCaption.php | 63 +++- .../filter/src/Plugin/Filter/FilterHtml.php | 22 +- .../tests/src/Kernel/FilterKernelTest.php | 10 +- web/core/modules/jsonapi/jsonapi.api.php | 4 +- .../src/Access/EntityAccessChecker.php | 6 +- .../src/Access/RelationshipFieldAccess.php | 2 +- .../src/Access/TemporaryQueryGuard.php | 2 +- .../jsonapi/src/Context/FieldResolver.php | 18 +- .../jsonapi/src/Controller/EntityResource.php | 6 +- .../jsonapi/src/Controller/EntryPoint.php | 2 +- .../jsonapi/src/Controller/FileUpload.php | 4 +- ...gisterSerializationClassesCompilerPass.php | 2 +- .../jsonapi/src/Encoder/JsonEncoder.php | 2 +- .../src/Entity/EntityValidationTrait.php | 2 +- .../DefaultExceptionSubscriber.php | 2 +- .../JsonApiRequestValidator.php | 2 +- .../ResourceResponseSubscriber.php | 2 +- .../ResourceResponseValidator.php | 2 +- .../EntityAccessDeniedHttpException.php | 4 +- .../UnprocessableHttpEntityException.php | 2 +- .../modules/jsonapi/src/IncludeResolver.php | 2 +- .../jsonapi/src/JsonApiResource/Data.php | 2 +- .../src/JsonApiResource/ErrorCollection.php | 2 +- .../src/JsonApiResource/IncludedData.php | 2 +- .../JsonApiDocumentTopLevel.php | 2 +- .../LabelOnlyResourceObject.php | 2 +- .../jsonapi/src/JsonApiResource/Link.php | 2 +- .../src/JsonApiResource/LinkCollection.php | 2 +- .../src/JsonApiResource/NullIncludedData.php | 2 +- .../src/JsonApiResource/OmittedData.php | 2 +- .../src/JsonApiResource/Relationship.php | 2 +- .../src/JsonApiResource/RelationshipData.php | 2 +- .../JsonApiResource/ResourceIdentifier.php | 4 +- .../ResourceIdentifierInterface.php | 2 +- .../ResourceIdentifierTrait.php | 2 +- .../src/JsonApiResource/ResourceObject.php | 2 +- .../JsonApiResource/ResourceObjectData.php | 2 +- .../JsonApiResource/TopLevelDataInterface.php | 2 +- web/core/modules/jsonapi/src/JsonApiSpec.php | 2 +- .../jsonapi/src/JsonapiServiceProvider.php | 2 +- .../Normalizer/ConfigEntityDenormalizer.php | 2 +- .../Normalizer/ContentEntityDenormalizer.php | 2 +- ...ityAccessDeniedHttpExceptionNormalizer.php | 2 +- .../src/Normalizer/EntityDenormalizerBase.php | 2 +- .../EntityReferenceFieldNormalizer.php | 2 +- .../src/Normalizer/FieldItemNormalizer.php | 2 +- .../src/Normalizer/FieldNormalizer.php | 2 +- .../Normalizer/HttpExceptionNormalizer.php | 4 +- .../JsonApiDocumentTopLevelNormalizer.php | 6 +- .../Normalizer/LinkCollectionNormalizer.php | 2 +- .../jsonapi/src/Normalizer/NormalizerBase.php | 2 +- .../ResourceIdentifierNormalizer.php | 2 +- .../Normalizer/ResourceObjectNormalizer.php | 2 +- ...ocessableHttpEntityExceptionNormalizer.php | 2 +- .../Value/CacheableNormalization.php | 2 +- .../Normalizer/Value/CacheableOmission.php | 2 +- .../Value/HttpExceptionNormalizerValue.php | 2 +- .../ParamConverter/EntityUuidConverter.php | 2 +- .../ParamConverter/ResourceTypeConverter.php | 2 +- .../jsonapi/src/Query/EntityCondition.php | 2 +- .../src/Query/EntityConditionGroup.php | 2 +- web/core/modules/jsonapi/src/Query/Filter.php | 5 +- .../modules/jsonapi/src/Query/OffsetPage.php | 2 +- web/core/modules/jsonapi/src/Query/Sort.php | 2 +- .../modules/jsonapi/src/ResourceResponse.php | 2 +- .../jsonapi/src/ResourceType/ResourceType.php | 2 +- .../ResourceType/ResourceTypeAttribute.php | 2 +- .../src/ResourceType/ResourceTypeField.php | 2 +- .../ResourceType/ResourceTypeRelationship.php | 2 +- .../ResourceType/ResourceTypeRepository.php | 2 +- .../ResourceTypeRepositoryInterface.php | 2 +- .../InvalidVersionIdentifierException.php | 2 +- .../jsonapi/src/Revisions/NegotiatorBase.php | 2 +- .../ResourceVersionRouteEnhancer.php | 4 +- .../jsonapi/src/Revisions/VersionById.php | 2 +- .../jsonapi/src/Revisions/VersionByRel.php | 2 +- .../src/Revisions/VersionNegotiator.php | 2 +- .../Revisions/VersionNegotiatorInterface.php | 2 +- .../Revisions/VersionNotFoundException.php | 2 +- .../jsonapi/src/Routing/RouteEnhancer.php | 2 +- .../modules/jsonapi/src/Routing/Routes.php | 2 +- .../jsonapi/src/Serializer/Serializer.php | 4 +- .../tests/src/Functional/BlockContentTest.php | 2 +- .../tests/src/Functional/CommentTest.php | 2 +- .../Functional/ConfigurableLanguageTest.php | 4 +- .../Functional/ExternalNormalizersTest.php | 2 +- .../src/Functional/JsonApiRegressionTest.php | 92 ++++-- .../tests/src/Functional/MediaTest.php | 2 +- .../src/Functional/MenuLinkContentTest.php | 2 +- .../jsonapi/tests/src/Functional/NodeTest.php | 8 +- .../tests/src/Functional/ResourceTestBase.php | 23 +- .../jsonapi/tests/src/Functional/TermTest.php | 6 +- .../Update/ReadOnlyModeUpdateTest.php | 2 +- .../jsonapi/tests/src/Functional/UserTest.php | 6 +- .../JsonApiDocumentTopLevelNormalizerTest.php | 2 +- .../tests/src/Kernel/Query/FilterTest.php | 2 +- .../Functional/LocaleImportFunctionalTest.php | 6 +- .../src/Functional/LocalePluralFormatTest.php | 21 +- .../tests/src/Functional/LocaleUpdateBase.php | 8 +- .../tests/src/Functional/LocaleUpdateTest.php | 12 +- .../migrate_drupal/tests/fixtures/drupal6.php | 191 ++++++++----- .../tests/src/Functional/NodeCreationTest.php | 4 +- .../src/Kernel/Migrate/d6/MigrateNodeTest.php | 18 +- .../src/Kernel/NodeAccessRecordsTest.php | 30 +- web/core/modules/rdf/rdf.module | 13 +- .../src/Functional/CommentAttributesTest.php | 20 +- .../src/Functional/UserAttributesTest.php | 9 +- .../src/Kernel/RdfCommentStorageLoadTest.php | 46 +++ .../SearchNodeUpdateAndDeletionTest.php | 12 +- .../src/Controller/ErrorTestController.php | 4 +- .../Database/SelectPagerDefaultTest.php | 4 +- .../tests/src/Functional/Form/StorageTest.php | 7 +- .../src/Functional/Module/InstallTest.php | 2 +- .../Functional/Session/SessionHttpsTest.php | 5 +- .../src/Functional/Session/SessionTest.php | 23 +- .../Functional/System/ErrorHandlerTest.php | 6 +- .../Plugin/views/filter/TaxonomyIndexTid.php | 26 +- .../tests/src/Functional/TermIndexTest.php | 110 ++++--- .../Views/TaxonomyIndexTidUiTest.php | 37 +++ web/core/modules/user/src/AccountForm.php | 7 +- .../user/src/Plugin/Block/UserLoginBlock.php | 3 +- .../tests/src/Functional/UserEditTest.php | 49 ++++ .../Kernel/Plugin/RelationshipJoinInTest.php | 21 +- .../src/Kernel/Plugin/RelationshipTest.php | 35 ++- .../src/Controller/ViewsUIController.php | 17 +- .../views_ui/tests/src/Kernel/TagTest.php | 39 ++- .../workspaces/src/WorkspaceManager.php | 6 +- .../ActiveWorkspaceUpdateTest.php | 10 +- .../Core/Asset/LibraryDiscoveryParserTest.php | 18 ++ .../library_test_files/empty.libraries.yml | 1 + web/core/themes/claro/css/components/form.css | 15 +- .../themes/claro/css/components/form.pcss.css | 15 +- web/sites/default/settings.pantheon.php | 4 +- 182 files changed, 1504 insertions(+), 594 deletions(-) create mode 100644 web/core/modules/content_moderation/tests/modules/content_moderation_test_views/config/install/views.view.test_content_moderation_state_filter_base_table_filter_group_or.yml create mode 100644 web/core/modules/rdf/tests/src/Kernel/RdfCommentStorageLoadTest.php create mode 100644 web/core/tests/Drupal/Tests/Core/Asset/library_test_files/empty.libraries.yml diff --git a/composer.json b/composer.json index 767e82ff78..da752f6466 100644 --- a/composer.json +++ b/composer.json @@ -105,7 +105,7 @@ "drupal/config_update": "1.5", "drupal/console": "1.8", "drupal/content_access": "1.0-alpha1", - "drupal/core-recommended": "8.9.3", + "drupal/core-recommended": "8.9.6", "drupal/crop": "2.1", "drupal/ctools": "3.4", "drupal/devel": "2.0", @@ -309,4 +309,4 @@ "php": "7.3" } } -} +} \ No newline at end of file diff --git a/composer.lock b/composer.lock index 96b3bdc45f..5da0ac4c85 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "e50c5b47d7ac57cabe5d1578e6c466b1", + "content-hash": "4b5b35efe0ddebe629171eb4c1046ab9", "packages": [ { "name": "alchemy/zippy", @@ -3375,16 +3375,16 @@ }, { "name": "drupal/core", - "version": "8.9.3", + "version": "8.9.6", "source": { "type": "git", "url": "https://github.com/drupal/core.git", - "reference": "ee02fd4cbe4ac148b4d7e297ec63b3459983862e" + "reference": "caf4e756d31dfb0c2e52cd0748e900efe4b57766" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/drupal/core/zipball/ee02fd4cbe4ac148b4d7e297ec63b3459983862e", - "reference": "ee02fd4cbe4ac148b4d7e297ec63b3459983862e", + "url": "https://api.github.com/repos/drupal/core/zipball/caf4e756d31dfb0c2e52cd0748e900efe4b57766", + "reference": "caf4e756d31dfb0c2e52cd0748e900efe4b57766", "shasum": "" }, "require": { @@ -3607,20 +3607,20 @@ "GPL-2.0-or-later" ], "description": "Drupal is an open source content management platform powering millions of websites and applications.", - "time": "2020-08-05T21:49:40+00:00" + "time": "2020-09-16T11:22:21+00:00" }, { "name": "drupal/core-recommended", - "version": "8.9.3", + "version": "8.9.6", "source": { "type": "git", "url": "https://github.com/drupal/core-recommended.git", - "reference": "db5c2fdd4bf3e72aee8c862eca72dd445e704d71" + "reference": "6c5c4739afc5549e6089ef34b59c712c8872f154" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/drupal/core-recommended/zipball/db5c2fdd4bf3e72aee8c862eca72dd445e704d71", - "reference": "db5c2fdd4bf3e72aee8c862eca72dd445e704d71", + "url": "https://api.github.com/repos/drupal/core-recommended/zipball/6c5c4739afc5549e6089ef34b59c712c8872f154", + "reference": "6c5c4739afc5549e6089ef34b59c712c8872f154", "shasum": "" }, "require": { @@ -3632,7 +3632,7 @@ "doctrine/common": "v2.7.3", "doctrine/inflector": "v1.2.0", "doctrine/lexer": "1.0.2", - "drupal/core": "8.9.3", + "drupal/core": "8.9.6", "easyrdf/easyrdf": "0.9.1", "egulias/email-validator": "2.1.17", "guzzlehttp/guzzle": "6.5.4", @@ -3661,7 +3661,7 @@ "symfony/dependency-injection": "v3.4.41", "symfony/event-dispatcher": "v3.4.41", "symfony/http-foundation": "v3.4.41", - "symfony/http-kernel": "v3.4.41", + "symfony/http-kernel": "v3.4.44", "symfony/polyfill-ctype": "v1.17.0", "symfony/polyfill-iconv": "v1.17.0", "symfony/polyfill-intl-idn": "v1.17.0", @@ -3689,7 +3689,7 @@ "GPL-2.0-or-later" ], "description": "Locked core dependencies; require this project INSTEAD OF drupal/core.", - "time": "2020-08-05T21:49:40+00:00" + "time": "2020-09-16T11:22:21+00:00" }, { "name": "drupal/crop", @@ -11944,16 +11944,16 @@ }, { "name": "symfony/http-kernel", - "version": "v3.4.41", + "version": "v3.4.44", "source": { "type": "git", "url": "https://github.com/symfony/http-kernel.git", - "reference": "e4e4ed6c008c983645b4eee6b67d8f258cde54df" + "reference": "27dcaa8c6b18c75df9f37badeb4d3564ffaa1326" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-kernel/zipball/e4e4ed6c008c983645b4eee6b67d8f258cde54df", - "reference": "e4e4ed6c008c983645b4eee6b67d8f258cde54df", + "url": "https://api.github.com/repos/symfony/http-kernel/zipball/27dcaa8c6b18c75df9f37badeb4d3564ffaa1326", + "reference": "27dcaa8c6b18c75df9f37badeb4d3564ffaa1326", "shasum": "" }, "require": { @@ -12030,7 +12030,7 @@ ], "description": "Symfony HttpKernel Component", "homepage": "https://symfony.com", - "time": "2020-05-31T05:14:17+00:00" + "time": "2020-08-31T05:53:42+00:00" }, { "name": "symfony/polyfill-ctype", diff --git a/vendor/composer/installed.json b/vendor/composer/installed.json index e7e8a031b5..504d93180f 100644 --- a/vendor/composer/installed.json +++ b/vendor/composer/installed.json @@ -3484,17 +3484,17 @@ }, { "name": "drupal/core", - "version": "8.9.3", - "version_normalized": "8.9.3.0", + "version": "8.9.6", + "version_normalized": "8.9.6.0", "source": { "type": "git", "url": "https://github.com/drupal/core.git", - "reference": "ee02fd4cbe4ac148b4d7e297ec63b3459983862e" + "reference": "caf4e756d31dfb0c2e52cd0748e900efe4b57766" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/drupal/core/zipball/ee02fd4cbe4ac148b4d7e297ec63b3459983862e", - "reference": "ee02fd4cbe4ac148b4d7e297ec63b3459983862e", + "url": "https://api.github.com/repos/drupal/core/zipball/caf4e756d31dfb0c2e52cd0748e900efe4b57766", + "reference": "caf4e756d31dfb0c2e52cd0748e900efe4b57766", "shasum": "" }, "require": { @@ -3661,7 +3661,7 @@ "drupal/workflows": "self.version", "drupal/workspaces": "self.version" }, - "time": "2020-08-05T21:49:40+00:00", + "time": "2020-09-16T11:22:21+00:00", "type": "drupal-core", "extra": { "drupal-scaffold": { @@ -3722,17 +3722,17 @@ }, { "name": "drupal/core-recommended", - "version": "8.9.3", - "version_normalized": "8.9.3.0", + "version": "8.9.6", + "version_normalized": "8.9.6.0", "source": { "type": "git", "url": "https://github.com/drupal/core-recommended.git", - "reference": "db5c2fdd4bf3e72aee8c862eca72dd445e704d71" + "reference": "6c5c4739afc5549e6089ef34b59c712c8872f154" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/drupal/core-recommended/zipball/db5c2fdd4bf3e72aee8c862eca72dd445e704d71", - "reference": "db5c2fdd4bf3e72aee8c862eca72dd445e704d71", + "url": "https://api.github.com/repos/drupal/core-recommended/zipball/6c5c4739afc5549e6089ef34b59c712c8872f154", + "reference": "6c5c4739afc5549e6089ef34b59c712c8872f154", "shasum": "" }, "require": { @@ -3744,7 +3744,7 @@ "doctrine/common": "v2.7.3", "doctrine/inflector": "v1.2.0", "doctrine/lexer": "1.0.2", - "drupal/core": "8.9.3", + "drupal/core": "8.9.6", "easyrdf/easyrdf": "0.9.1", "egulias/email-validator": "2.1.17", "guzzlehttp/guzzle": "6.5.4", @@ -3773,7 +3773,7 @@ "symfony/dependency-injection": "v3.4.41", "symfony/event-dispatcher": "v3.4.41", "symfony/http-foundation": "v3.4.41", - "symfony/http-kernel": "v3.4.41", + "symfony/http-kernel": "v3.4.44", "symfony/polyfill-ctype": "v1.17.0", "symfony/polyfill-iconv": "v1.17.0", "symfony/polyfill-intl-idn": "v1.17.0", @@ -3795,7 +3795,7 @@ "conflict": { "webflo/drupal-core-strict": "*" }, - "time": "2020-08-05T21:49:40+00:00", + "time": "2020-09-16T11:22:21+00:00", "type": "metapackage", "notification-url": "https://packagist.org/downloads/", "license": [ @@ -12335,17 +12335,17 @@ }, { "name": "symfony/http-kernel", - "version": "v3.4.41", - "version_normalized": "3.4.41.0", + "version": "v3.4.44", + "version_normalized": "3.4.44.0", "source": { "type": "git", "url": "https://github.com/symfony/http-kernel.git", - "reference": "e4e4ed6c008c983645b4eee6b67d8f258cde54df" + "reference": "27dcaa8c6b18c75df9f37badeb4d3564ffaa1326" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-kernel/zipball/e4e4ed6c008c983645b4eee6b67d8f258cde54df", - "reference": "e4e4ed6c008c983645b4eee6b67d8f258cde54df", + "url": "https://api.github.com/repos/symfony/http-kernel/zipball/27dcaa8c6b18c75df9f37badeb4d3564ffaa1326", + "reference": "27dcaa8c6b18c75df9f37badeb4d3564ffaa1326", "shasum": "" }, "require": { @@ -12392,7 +12392,7 @@ "symfony/finder": "", "symfony/var-dumper": "" }, - "time": "2020-05-31T05:14:17+00:00", + "time": "2020-08-31T05:53:42+00:00", "type": "library", "extra": { "branch-alias": { diff --git a/vendor/symfony/http-kernel/Controller/ControllerResolver.php b/vendor/symfony/http-kernel/Controller/ControllerResolver.php index 015448b510..8ed79ff7b2 100644 --- a/vendor/symfony/http-kernel/Controller/ControllerResolver.php +++ b/vendor/symfony/http-kernel/Controller/ControllerResolver.php @@ -274,7 +274,7 @@ private function typeMatchesRequestClass(\ReflectionParameter $param, Request $r return false; } - $class = new \ReflectionClass(method_exists($type, 'getName') ? $type->getName() : (string) $type); + $class = new \ReflectionClass($type instanceof \ReflectionNamedType ? $type->getName() : (string) $type); return $class && $class->isInstance($request); } diff --git a/vendor/symfony/http-kernel/ControllerMetadata/ArgumentMetadataFactory.php b/vendor/symfony/http-kernel/ControllerMetadata/ArgumentMetadataFactory.php index 2548a2a083..14e7ca3d11 100644 --- a/vendor/symfony/http-kernel/ControllerMetadata/ArgumentMetadataFactory.php +++ b/vendor/symfony/http-kernel/ControllerMetadata/ArgumentMetadataFactory.php @@ -105,7 +105,7 @@ private function getType(\ReflectionParameter $parameter, \ReflectionFunctionAbs if (!$type = $parameter->getType()) { return null; } - $name = $type instanceof \ReflectionNamedType ? $type->getName() : $type->__toString(); + $name = $type instanceof \ReflectionNamedType ? $type->getName() : (string) $type; if ('array' === $name && !$type->isBuiltin()) { // Special case for HHVM with variadics return null; diff --git a/vendor/symfony/http-kernel/DataCollector/ConfigDataCollector.php b/vendor/symfony/http-kernel/DataCollector/ConfigDataCollector.php index 673bf5c5fd..5895ef37d7 100644 --- a/vendor/symfony/http-kernel/DataCollector/ConfigDataCollector.php +++ b/vendor/symfony/http-kernel/DataCollector/ConfigDataCollector.php @@ -64,7 +64,7 @@ public function collect(Request $request, Response $response, \Exception $except 'env' => isset($this->kernel) ? $this->kernel->getEnvironment() : 'n/a', 'debug' => isset($this->kernel) ? $this->kernel->isDebug() : 'n/a', 'php_version' => PHP_VERSION, - 'php_architecture' => PHP_INT_SIZE * 8, + 'php_architecture' => \PHP_INT_SIZE * 8, 'php_intl_locale' => class_exists('Locale', false) && \Locale::getDefault() ? \Locale::getDefault() : 'n/a', 'php_timezone' => date_default_timezone_get(), 'xdebug_enabled' => \extension_loaded('xdebug'), diff --git a/vendor/symfony/http-kernel/DependencyInjection/AddAnnotatedClassesToCachePass.php b/vendor/symfony/http-kernel/DependencyInjection/AddAnnotatedClassesToCachePass.php index 8bb03bd0c7..b59949379d 100644 --- a/vendor/symfony/http-kernel/DependencyInjection/AddAnnotatedClassesToCachePass.php +++ b/vendor/symfony/http-kernel/DependencyInjection/AddAnnotatedClassesToCachePass.php @@ -136,10 +136,10 @@ private function patternsToRegexps($patterns) private function matchAnyRegexps($class, $regexps) { - $blacklisted = false !== strpos($class, 'Test'); + $isTest = false !== strpos($class, 'Test'); foreach ($regexps as $regex) { - if ($blacklisted && false === strpos($regex, 'Test')) { + if ($isTest && false === strpos($regex, 'Test')) { continue; } diff --git a/vendor/symfony/http-kernel/HttpCache/Store.php b/vendor/symfony/http-kernel/HttpCache/Store.php index fd04a7b23d..72793f582d 100644 --- a/vendor/symfony/http-kernel/HttpCache/Store.php +++ b/vendor/symfony/http-kernel/HttpCache/Store.php @@ -152,8 +152,8 @@ public function lookup(Request $request) } $headers = $match[1]; - if (file_exists($body = $this->getPath($headers['x-content-digest'][0]))) { - return $this->restoreResponse($headers, $body); + if (file_exists($path = $this->getPath($headers['x-content-digest'][0]))) { + return $this->restoreResponse($headers, $path); } // TODO the metaStore referenced an entity that doesn't exist in @@ -177,15 +177,28 @@ public function write(Request $request, Response $response) $key = $this->getCacheKey($request); $storedEnv = $this->persistRequest($request); - $digest = $this->generateContentDigest($response); - $response->headers->set('X-Content-Digest', $digest); + if ($response->headers->has('X-Body-File')) { + // Assume the response came from disk, but at least perform some safeguard checks + if (!$response->headers->has('X-Content-Digest')) { + throw new \RuntimeException('A restored response must have the X-Content-Digest header.'); + } - if (!$this->save($digest, $response->getContent(), false)) { - throw new \RuntimeException('Unable to store the entity.'); - } + $digest = $response->headers->get('X-Content-Digest'); + if ($this->getPath($digest) !== $response->headers->get('X-Body-File')) { + throw new \RuntimeException('X-Body-File and X-Content-Digest do not match.'); + } + // Everything seems ok, omit writing content to disk + } else { + $digest = $this->generateContentDigest($response); + $response->headers->set('X-Content-Digest', $digest); - if (!$response->headers->has('Transfer-Encoding')) { - $response->headers->set('Content-Length', \strlen($response->getContent())); + if (!$this->save($digest, $response->getContent(), false)) { + throw new \RuntimeException('Unable to store the entity.'); + } + + if (!$response->headers->has('Transfer-Encoding')) { + $response->headers->set('Content-Length', \strlen($response->getContent())); + } } // read existing cache entries, remove non-varying, and add this one to the list @@ -477,19 +490,19 @@ private function persistResponse(Response $response) * Restores a Response from the HTTP headers and body. * * @param array $headers An array of HTTP headers for the Response - * @param string $body The Response body + * @param string $path Path to the Response body * * @return Response */ - private function restoreResponse($headers, $body = null) + private function restoreResponse($headers, $path = null) { $status = $headers['X-Status'][0]; unset($headers['X-Status']); - if (null !== $body) { - $headers['X-Body-File'] = [$body]; + if (null !== $path) { + $headers['X-Body-File'] = [$path]; } - return new Response($body, $status, $headers); + return new Response($path, $status, $headers); } } diff --git a/vendor/symfony/http-kernel/Kernel.php b/vendor/symfony/http-kernel/Kernel.php index 00382a95c1..e0aa029eb6 100644 --- a/vendor/symfony/http-kernel/Kernel.php +++ b/vendor/symfony/http-kernel/Kernel.php @@ -67,11 +67,11 @@ abstract class Kernel implements KernelInterface, RebootableInterface, Terminabl private $requestStackSize = 0; private $resetServices = false; - const VERSION = '3.4.41'; - const VERSION_ID = 30441; + const VERSION = '3.4.44'; + const VERSION_ID = 30444; const MAJOR_VERSION = 3; const MINOR_VERSION = 4; - const RELEASE_VERSION = 41; + const RELEASE_VERSION = 44; const EXTRA_VERSION = ''; const END_OF_MAINTENANCE = '11/2020'; diff --git a/vendor/symfony/http-kernel/Tests/Controller/ContainerControllerResolverTest.php b/vendor/symfony/http-kernel/Tests/Controller/ContainerControllerResolverTest.php index 4c4abf5aa4..8275154657 100644 --- a/vendor/symfony/http-kernel/Tests/Controller/ContainerControllerResolverTest.php +++ b/vendor/symfony/http-kernel/Tests/Controller/ContainerControllerResolverTest.php @@ -15,6 +15,7 @@ use Psr\Log\LoggerInterface; use Symfony\Component\Debug\ErrorHandler; use Symfony\Component\DependencyInjection\Container; +use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpKernel\Controller\ContainerControllerResolver; @@ -117,16 +118,10 @@ public function testNonConstructController() $this->expectException('LogicException'); $this->expectExceptionMessage('Controller "Symfony\Component\HttpKernel\Tests\Controller\ImpossibleConstructController" cannot be fetched from the container because it is private. Did you forget to tag the service with "controller.service_arguments"?'); $container = $this->getMockBuilder(Container::class)->getMock(); - $container->expects($this->at(0)) + $container->expects($this->exactly(2)) ->method('has') ->with(ImpossibleConstructController::class) - ->willReturn(true) - ; - - $container->expects($this->at(1)) - ->method('has') - ->with(ImpossibleConstructController::class) - ->willReturn(false) + ->willReturnOnConsecutiveCalls(true, false) ; $container->expects($this->atLeastOnce()) @@ -181,18 +176,10 @@ public function testExceptionWhenUsingRemovedControllerService() { $this->expectException('LogicException'); $this->expectExceptionMessage('Controller "app.my_controller" cannot be fetched from the container because it is private. Did you forget to tag the service with "controller.service_arguments"?'); - $container = $this->getMockBuilder(Container::class)->getMock(); - $container->expects($this->at(0)) - ->method('has') - ->with('app.my_controller') - ->willReturn(false) - ; - $container->expects($this->atLeastOnce()) - ->method('getRemovedIds') - ->with() - ->willReturn(['app.my_controller' => true]) - ; + $container = new ContainerBuilder(); + $container->register('app.my_controller'); + $container->removeDefinition('app.my_controller'); $resolver = $this->createControllerResolver(null, $container); @@ -232,7 +219,7 @@ public function testGetControllerOnNonUndefinedFunction($controller, $exceptionN // All this logic needs to be duplicated, since calling parent::testGetControllerOnNonUndefinedFunction will override the expected exception and not use the regex $resolver = $this->createControllerResolver(); $this->expectException($exceptionName); - $this->expectExceptionMessageRegExp($exceptionMessage); + $this->expectExceptionMessageMatches($exceptionMessage); $request = Request::create('/'); $request->attributes->set('_controller', $controller); diff --git a/vendor/symfony/http-kernel/Tests/DataCollector/ConfigDataCollectorTest.php b/vendor/symfony/http-kernel/Tests/DataCollector/ConfigDataCollectorTest.php index a858eabe15..dc455915fa 100644 --- a/vendor/symfony/http-kernel/Tests/DataCollector/ConfigDataCollectorTest.php +++ b/vendor/symfony/http-kernel/Tests/DataCollector/ConfigDataCollectorTest.php @@ -31,9 +31,9 @@ public function testCollect() $this->assertTrue($c->isDebug()); $this->assertSame('config', $c->getName()); $this->assertSame('testkernel', $c->getAppName()); - $this->assertRegExp('~^'.preg_quote($c->getPhpVersion(), '~').'~', PHP_VERSION); - $this->assertRegExp('~'.preg_quote((string) $c->getPhpVersionExtra(), '~').'$~', PHP_VERSION); - $this->assertSame(PHP_INT_SIZE * 8, $c->getPhpArchitecture()); + $this->assertMatchesRegularExpression('~^'.preg_quote($c->getPhpVersion(), '~').'~', PHP_VERSION); + $this->assertMatchesRegularExpression('~'.preg_quote((string) $c->getPhpVersionExtra(), '~').'$~', PHP_VERSION); + $this->assertSame(\PHP_INT_SIZE * 8, $c->getPhpArchitecture()); $this->assertSame(class_exists('Locale', false) && \Locale::getDefault() ? \Locale::getDefault() : 'n/a', $c->getPhpIntlLocale()); $this->assertSame(date_default_timezone_get(), $c->getPhpTimezone()); $this->assertSame(Kernel::VERSION, $c->getSymfonyVersion()); diff --git a/vendor/symfony/http-kernel/Tests/DataCollector/RequestDataCollectorTest.php b/vendor/symfony/http-kernel/Tests/DataCollector/RequestDataCollectorTest.php index 38979bba72..9bf5bf968d 100644 --- a/vendor/symfony/http-kernel/Tests/DataCollector/RequestDataCollectorTest.php +++ b/vendor/symfony/http-kernel/Tests/DataCollector/RequestDataCollectorTest.php @@ -51,7 +51,7 @@ public function testCollect() $this->assertEquals(['name' => 'foo'], $c->getRouteParams()); $this->assertSame([], $c->getSessionAttributes()); $this->assertSame('en', $c->getLocale()); - $this->assertContains(__FILE__, $attributes->get('resource')); + $this->assertContainsEquals(__FILE__, $attributes->get('resource')); $this->assertSame('stdClass', $attributes->get('object')->getType()); $this->assertInstanceOf('Symfony\Component\HttpFoundation\ParameterBag', $c->getResponseHeaders()); diff --git a/vendor/symfony/http-kernel/Tests/Event/FilterControllerArgumentsEventTest.php b/vendor/symfony/http-kernel/Tests/Event/FilterControllerArgumentsEventTest.php index abc51ac51e..53962347d0 100644 --- a/vendor/symfony/http-kernel/Tests/Event/FilterControllerArgumentsEventTest.php +++ b/vendor/symfony/http-kernel/Tests/Event/FilterControllerArgumentsEventTest.php @@ -12,6 +12,6 @@ class FilterControllerArgumentsEventTest extends TestCase public function testFilterControllerArgumentsEvent() { $filterController = new FilterControllerArgumentsEvent(new TestHttpKernel(), function () {}, ['test'], new Request(), 1); - $this->assertEquals($filterController->getArguments(), ['test']); + $this->assertEquals(['test'], $filterController->getArguments()); } } diff --git a/vendor/symfony/http-kernel/Tests/EventListener/TranslatorListenerTest.php b/vendor/symfony/http-kernel/Tests/EventListener/TranslatorListenerTest.php index 77c2c1c694..79e0d6f1ac 100644 --- a/vendor/symfony/http-kernel/Tests/EventListener/TranslatorListenerTest.php +++ b/vendor/symfony/http-kernel/Tests/EventListener/TranslatorListenerTest.php @@ -45,13 +45,15 @@ public function testLocaleIsSetInOnKernelRequest() public function testDefaultLocaleIsUsedOnExceptionsInOnKernelRequest() { $this->translator - ->expects($this->at(0)) + ->expects($this->exactly(2)) ->method('setLocale') - ->willThrowException(new \InvalidArgumentException()); - $this->translator - ->expects($this->at(1)) - ->method('setLocale') - ->with($this->equalTo('en')); + ->withConsecutive( + ['fr'], + ['en'] + ) + ->willReturnOnConsecutiveCalls( + $this->throwException(new \InvalidArgumentException()) + ); $event = new GetResponseEvent($this->createHttpKernel(), $this->createRequest('fr'), HttpKernelInterface::MASTER_REQUEST); $this->listener->onKernelRequest($event); @@ -82,13 +84,15 @@ public function testLocaleIsNotSetInOnKernelFinishRequestWhenParentRequestDoesNo public function testDefaultLocaleIsUsedOnExceptionsInOnKernelFinishRequest() { $this->translator - ->expects($this->at(0)) - ->method('setLocale') - ->willThrowException(new \InvalidArgumentException()); - $this->translator - ->expects($this->at(1)) + ->expects($this->exactly(2)) ->method('setLocale') - ->with($this->equalTo('en')); + ->withConsecutive( + ['fr'], + ['en'] + ) + ->willReturnOnConsecutiveCalls( + $this->throwException(new \InvalidArgumentException()) + ); $this->setMasterRequest($this->createRequest('fr')); $event = new FinishRequestEvent($this->createHttpKernel(), $this->createRequest('de'), HttpKernelInterface::SUB_REQUEST); diff --git a/vendor/symfony/http-kernel/Tests/HttpCache/HttpCacheTest.php b/vendor/symfony/http-kernel/Tests/HttpCache/HttpCacheTest.php index cac06a80e5..444db71a3e 100644 --- a/vendor/symfony/http-kernel/Tests/HttpCache/HttpCacheTest.php +++ b/vendor/symfony/http-kernel/Tests/HttpCache/HttpCacheTest.php @@ -654,7 +654,7 @@ public function testAssignsDefaultTtlWhenResponseHasNoFreshnessInformation() $this->assertTraceContains('miss'); $this->assertTraceContains('store'); $this->assertEquals('Hello World', $this->response->getContent()); - $this->assertRegExp('/s-maxage=10/', $this->response->headers->get('Cache-Control')); + $this->assertMatchesRegularExpression('/s-maxage=10/', $this->response->headers->get('Cache-Control')); $this->cacheConfig['default_ttl'] = 10; $this->request('GET', '/'); @@ -663,7 +663,7 @@ public function testAssignsDefaultTtlWhenResponseHasNoFreshnessInformation() $this->assertTraceContains('fresh'); $this->assertTraceNotContains('store'); $this->assertEquals('Hello World', $this->response->getContent()); - $this->assertRegExp('/s-maxage=10/', $this->response->headers->get('Cache-Control')); + $this->assertMatchesRegularExpression('/s-maxage=10/', $this->response->headers->get('Cache-Control')); } public function testAssignsDefaultTtlWhenResponseHasNoFreshnessInformationAndAfterTtlWasExpired() @@ -676,7 +676,7 @@ public function testAssignsDefaultTtlWhenResponseHasNoFreshnessInformationAndAft $this->assertTraceContains('miss'); $this->assertTraceContains('store'); $this->assertEquals('Hello World', $this->response->getContent()); - $this->assertRegExp('/s-maxage=(2|3)/', $this->response->headers->get('Cache-Control')); + $this->assertMatchesRegularExpression('/s-maxage=(2|3)/', $this->response->headers->get('Cache-Control')); $this->request('GET', '/'); $this->assertHttpKernelIsNotCalled(); @@ -684,7 +684,7 @@ public function testAssignsDefaultTtlWhenResponseHasNoFreshnessInformationAndAft $this->assertTraceContains('fresh'); $this->assertTraceNotContains('store'); $this->assertEquals('Hello World', $this->response->getContent()); - $this->assertRegExp('/s-maxage=(2|3)/', $this->response->headers->get('Cache-Control')); + $this->assertMatchesRegularExpression('/s-maxage=(2|3)/', $this->response->headers->get('Cache-Control')); // expires the cache $values = $this->getMetaStorageValues(); @@ -704,7 +704,7 @@ public function testAssignsDefaultTtlWhenResponseHasNoFreshnessInformationAndAft $this->assertTraceContains('invalid'); $this->assertTraceContains('store'); $this->assertEquals('Hello World', $this->response->getContent()); - $this->assertRegExp('/s-maxage=(2|3)/', $this->response->headers->get('Cache-Control')); + $this->assertMatchesRegularExpression('/s-maxage=(2|3)/', $this->response->headers->get('Cache-Control')); $this->setNextResponse(); @@ -714,7 +714,7 @@ public function testAssignsDefaultTtlWhenResponseHasNoFreshnessInformationAndAft $this->assertTraceContains('fresh'); $this->assertTraceNotContains('store'); $this->assertEquals('Hello World', $this->response->getContent()); - $this->assertRegExp('/s-maxage=(2|3)/', $this->response->headers->get('Cache-Control')); + $this->assertMatchesRegularExpression('/s-maxage=(2|3)/', $this->response->headers->get('Cache-Control')); } public function testAssignsDefaultTtlWhenResponseHasNoFreshnessInformationAndAfterTtlWasExpiredWithStatus304() @@ -727,7 +727,7 @@ public function testAssignsDefaultTtlWhenResponseHasNoFreshnessInformationAndAft $this->assertTraceContains('miss'); $this->assertTraceContains('store'); $this->assertEquals('Hello World', $this->response->getContent()); - $this->assertRegExp('/s-maxage=(2|3)/', $this->response->headers->get('Cache-Control')); + $this->assertMatchesRegularExpression('/s-maxage=(2|3)/', $this->response->headers->get('Cache-Control')); $this->request('GET', '/'); $this->assertHttpKernelIsNotCalled(); @@ -755,7 +755,7 @@ public function testAssignsDefaultTtlWhenResponseHasNoFreshnessInformationAndAft $this->assertTraceContains('store'); $this->assertTraceNotContains('miss'); $this->assertEquals('Hello World', $this->response->getContent()); - $this->assertRegExp('/s-maxage=(2|3)/', $this->response->headers->get('Cache-Control')); + $this->assertMatchesRegularExpression('/s-maxage=(2|3)/', $this->response->headers->get('Cache-Control')); $this->request('GET', '/'); $this->assertHttpKernelIsNotCalled(); @@ -763,7 +763,7 @@ public function testAssignsDefaultTtlWhenResponseHasNoFreshnessInformationAndAft $this->assertTraceContains('fresh'); $this->assertTraceNotContains('store'); $this->assertEquals('Hello World', $this->response->getContent()); - $this->assertRegExp('/s-maxage=(2|3)/', $this->response->headers->get('Cache-Control')); + $this->assertMatchesRegularExpression('/s-maxage=(2|3)/', $this->response->headers->get('Cache-Control')); } public function testDoesNotAssignDefaultTtlWhenResponseHasMustRevalidateDirective() @@ -776,7 +776,7 @@ public function testDoesNotAssignDefaultTtlWhenResponseHasMustRevalidateDirectiv $this->assertEquals(200, $this->response->getStatusCode()); $this->assertTraceContains('miss'); $this->assertTraceNotContains('store'); - $this->assertNotRegExp('/s-maxage/', $this->response->headers->get('Cache-Control')); + $this->assertDoesNotMatchRegularExpression('/s-maxage/', $this->response->headers->get('Cache-Control')); $this->assertEquals('Hello World', $this->response->getContent()); } diff --git a/vendor/symfony/http-kernel/Tests/HttpCache/HttpCacheTestCase.php b/vendor/symfony/http-kernel/Tests/HttpCache/HttpCacheTestCase.php index 1eb4617447..3cbea5e4ee 100644 --- a/vendor/symfony/http-kernel/Tests/HttpCache/HttpCacheTestCase.php +++ b/vendor/symfony/http-kernel/Tests/HttpCache/HttpCacheTestCase.php @@ -91,7 +91,7 @@ public function assertTraceContains($trace) $traces = $this->cache->getTraces(); $traces = current($traces); - $this->assertRegExp('/'.$trace.'/', implode(', ', $traces)); + $this->assertMatchesRegularExpression('/'.$trace.'/', implode(', ', $traces)); } public function assertTraceNotContains($trace) @@ -99,7 +99,7 @@ public function assertTraceNotContains($trace) $traces = $this->cache->getTraces(); $traces = current($traces); - $this->assertNotRegExp('/'.$trace.'/', implode(', ', $traces)); + $this->assertDoesNotMatchRegularExpression('/'.$trace.'/', implode(', ', $traces)); } public function assertExceptionsAreCaught() diff --git a/vendor/symfony/http-kernel/Tests/HttpCache/StoreTest.php b/vendor/symfony/http-kernel/Tests/HttpCache/StoreTest.php index 07c4154269..eee8970b96 100644 --- a/vendor/symfony/http-kernel/Tests/HttpCache/StoreTest.php +++ b/vendor/symfony/http-kernel/Tests/HttpCache/StoreTest.php @@ -118,6 +118,39 @@ public function testWritesResponseEvenIfXContentDigestIsPresent() $this->assertNotNull($response); } + public function testWritingARestoredResponseDoesNotCorruptCache() + { + /* + * This covers the regression reported in https://github.com/symfony/symfony/issues/37174. + * + * A restored response does *not* load the body, but only keep the file path in a special X-Body-File + * header. For reasons (?), the file path was also used as the restored response body. + * It would be up to others (HttpCache...?) to honor this header and actually load the response content + * from there. + * + * When a restored response was stored again, the Store itself would ignore the header. In the first + * step, this would compute a new Content Digest based on the file path in the restored response body; + * this is covered by "Checkpoint 1" below. But, since the X-Body-File header was left untouched (Checkpoint 2), downstream + * code (HttpCache...) would not immediately notice. + * + * Only upon performing the lookup for a second time, we'd get a Response where the (wrong) Content Digest + * is also reflected in the X-Body-File header, this time also producing wrong content when the downstream + * evaluates it. + */ + $this->store->write($this->request, $this->response); + $digest = $this->response->headers->get('X-Content-Digest'); + $path = $this->getStorePath($digest); + + $response = $this->store->lookup($this->request); + $this->store->write($this->request, $response); + $this->assertEquals($digest, $response->headers->get('X-Content-Digest')); // Checkpoint 1 + $this->assertEquals($path, $response->headers->get('X-Body-File')); // Checkpoint 2 + + $response = $this->store->lookup($this->request); + $this->assertEquals($digest, $response->headers->get('X-Content-Digest')); + $this->assertEquals($path, $response->headers->get('X-Body-File')); + } + public function testFindsAStoredEntryWithLookup() { $this->storeSimpleEntry(); diff --git a/vendor/symfony/http-kernel/Tests/HttpKernelTest.php b/vendor/symfony/http-kernel/Tests/HttpKernelTest.php index af81f021ed..97c58305db 100644 --- a/vendor/symfony/http-kernel/Tests/HttpKernelTest.php +++ b/vendor/symfony/http-kernel/Tests/HttpKernelTest.php @@ -314,8 +314,8 @@ public function testVerifyRequestStackPushPopDuringHandle() $request = new Request(); $stack = $this->getMockBuilder('Symfony\Component\HttpFoundation\RequestStack')->setMethods(['push', 'pop'])->getMock(); - $stack->expects($this->at(0))->method('push')->with($this->equalTo($request)); - $stack->expects($this->at(1))->method('pop'); + $stack->expects($this->once())->method('push')->with($this->equalTo($request)); + $stack->expects($this->once())->method('pop'); $dispatcher = new EventDispatcher(); $kernel = $this->getHttpKernel($dispatcher, null, $stack); diff --git a/vendor/symfony/http-kernel/Tests/KernelTest.php b/vendor/symfony/http-kernel/Tests/KernelTest.php index e4e2e0727b..fd840bbb7b 100644 --- a/vendor/symfony/http-kernel/Tests/KernelTest.php +++ b/vendor/symfony/http-kernel/Tests/KernelTest.php @@ -15,6 +15,7 @@ use Symfony\Component\Config\Loader\LoaderInterface; use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface; use Symfony\Component\DependencyInjection\ContainerBuilder; +use Symfony\Component\DependencyInjection\ContainerInterface; use Symfony\Component\Filesystem\Filesystem; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; @@ -78,7 +79,7 @@ public function testInitializeContainerClearsOldContainers() $containerDir = __DIR__.'/Fixtures/cache/custom/'.substr(\get_class($kernel->getContainer()), 0, 16); $this->assertTrue(unlink(__DIR__.'/Fixtures/cache/custom/FixturesCustomDebugProjectContainer.php.meta')); $this->assertFileExists($containerDir); - $this->assertFileNotExists($containerDir.'.legacy'); + $this->assertFileDoesNotExist($containerDir.'.legacy'); $kernel = new CustomProjectDirKernel(function ($container) { $container->register('foo', 'stdClass')->setPublic(true); }); $kernel->boot(); @@ -86,8 +87,8 @@ public function testInitializeContainerClearsOldContainers() $this->assertFileExists($containerDir); $this->assertFileExists($containerDir.'.legacy'); - $this->assertFileNotExists($legacyContainerDir); - $this->assertFileNotExists($legacyContainerDir.'.legacy'); + $this->assertFileDoesNotExist($legacyContainerDir); + $this->assertFileDoesNotExist($legacyContainerDir.'.legacy'); } public function testBootInitializesBundlesAndContainer() @@ -219,9 +220,12 @@ public function testShutdownCallsShutdownOnAllBundles() public function testShutdownGivesNullContainerToAllBundles() { $bundle = $this->getMockBuilder('Symfony\Component\HttpKernel\Bundle\Bundle')->getMock(); - $bundle->expects($this->at(3)) + $bundle->expects($this->exactly(2)) ->method('setContainer') - ->with(null); + ->withConsecutive( + [$this->isInstanceOf(ContainerInterface::class)], + [null] + ); $kernel = $this->getKernel(['getBundles']); $kernel->expects($this->any()) diff --git a/vendor/symfony/http-kernel/Tests/Profiler/FileProfilerStorageTest.php b/vendor/symfony/http-kernel/Tests/Profiler/FileProfilerStorageTest.php index 1cc05e41ec..4e23f13b02 100644 --- a/vendor/symfony/http-kernel/Tests/Profiler/FileProfilerStorageTest.php +++ b/vendor/symfony/http-kernel/Tests/Profiler/FileProfilerStorageTest.php @@ -205,9 +205,9 @@ public function testStoreTime() $records = $this->storage->find('', '', 3, 'GET', $start, time() + 3 * 60); $this->assertCount(3, $records, '->find() returns all previously added records'); - $this->assertEquals($records[0]['token'], 'time_2', '->find() returns records ordered by time in descendant order'); - $this->assertEquals($records[1]['token'], 'time_1', '->find() returns records ordered by time in descendant order'); - $this->assertEquals($records[2]['token'], 'time_0', '->find() returns records ordered by time in descendant order'); + $this->assertEquals('time_2', $records[0]['token'], '->find() returns records ordered by time in descendant order'); + $this->assertEquals('time_1', $records[1]['token'], '->find() returns records ordered by time in descendant order'); + $this->assertEquals('time_0', $records[2]['token'], '->find() returns records ordered by time in descendant order'); $records = $this->storage->find('', '', 3, 'GET', $start, time() + 2 * 60); $this->assertCount(2, $records, '->find() should return only first two of the previously added records'); @@ -293,8 +293,8 @@ public function testStatusCode() $tokens = $this->storage->find('', '', 10, ''); $this->assertCount(2, $tokens); - $this->assertContains($tokens[0]['status_code'], [200, 404]); - $this->assertContains($tokens[1]['status_code'], [200, 404]); + $this->assertContains((int) $tokens[0]['status_code'], [200, 404]); + $this->assertContains((int) $tokens[1]['status_code'], [200, 404]); } public function testMultiRowIndexFile() diff --git a/web/core/lib/Drupal.php b/web/core/lib/Drupal.php index 28863da052..2d5754aa94 100644 --- a/web/core/lib/Drupal.php +++ b/web/core/lib/Drupal.php @@ -82,7 +82,7 @@ class Drupal { /** * The current system version. */ - const VERSION = '8.9.3'; + const VERSION = '8.9.6'; /** * Core API compatibility. diff --git a/web/core/lib/Drupal/Component/Utility/Image.php b/web/core/lib/Drupal/Component/Utility/Image.php index fcfedb1a26..f1368c1b83 100644 --- a/web/core/lib/Drupal/Component/Utility/Image.php +++ b/web/core/lib/Drupal/Component/Utility/Image.php @@ -30,8 +30,6 @@ class Image { * * @return bool * TRUE if $dimensions was modified, FALSE otherwise. - * - * @see image_scale() */ public static function scaleDimensions(array &$dimensions, $width = NULL, $height = NULL, $upscale = FALSE) { $aspect = $dimensions['height'] / $dimensions['width']; diff --git a/web/core/lib/Drupal/Core/Asset/LibraryDiscoveryParser.php b/web/core/lib/Drupal/Core/Asset/LibraryDiscoveryParser.php index 99328413da..d2cf20a22a 100644 --- a/web/core/lib/Drupal/Core/Asset/LibraryDiscoveryParser.php +++ b/web/core/lib/Drupal/Core/Asset/LibraryDiscoveryParser.php @@ -345,7 +345,7 @@ protected function parseLibraryInfo($extension, $path) { $library_file = $path . '/' . $extension . '.libraries.yml'; if (file_exists($this->root . '/' . $library_file)) { try { - $libraries = Yaml::decode(file_get_contents($this->root . '/' . $library_file)); + $libraries = Yaml::decode(file_get_contents($this->root . '/' . $library_file)) ?? []; } catch (InvalidDataTypeException $e) { // Rethrow a more helpful exception to provide context. diff --git a/web/core/lib/Drupal/Core/DependencyInjection/DeprecatedServicePropertyTrait.php b/web/core/lib/Drupal/Core/DependencyInjection/DeprecatedServicePropertyTrait.php index b0681ec0b8..55c6bd63a5 100644 --- a/web/core/lib/Drupal/Core/DependencyInjection/DeprecatedServicePropertyTrait.php +++ b/web/core/lib/Drupal/Core/DependencyInjection/DeprecatedServicePropertyTrait.php @@ -8,7 +8,7 @@ trait DeprecatedServicePropertyTrait { /** - * Alows to access deprecated/removed properties. + * Allows to access deprecated/removed properties. * * This method must be public. */ diff --git a/web/core/lib/Drupal/Core/EventSubscriber/ExceptionLoggingSubscriber.php b/web/core/lib/Drupal/Core/EventSubscriber/ExceptionLoggingSubscriber.php index 7a39969bab..998213ea31 100644 --- a/web/core/lib/Drupal/Core/EventSubscriber/ExceptionLoggingSubscriber.php +++ b/web/core/lib/Drupal/Core/EventSubscriber/ExceptionLoggingSubscriber.php @@ -42,6 +42,7 @@ public function on403(GetResponseForExceptionEvent $event) { // why access was denied. $exception = $event->getException(); $error = Error::decodeException($exception); + unset($error['@backtrace_string']); $error['@uri'] = $event->getRequest()->getRequestUri(); $this->logger->get('access denied')->warning('Path: @uri. %type: @message in %function (line %line of %file).', $error); } diff --git a/web/core/lib/Drupal/Core/Form/FormBuilder.php b/web/core/lib/Drupal/Core/Form/FormBuilder.php index 5e8e22a604..4447534658 100644 --- a/web/core/lib/Drupal/Core/Form/FormBuilder.php +++ b/web/core/lib/Drupal/Core/Form/FormBuilder.php @@ -861,7 +861,8 @@ protected function buildFormAction() { // https://www.drupal.org/node/2504709. $parsed = UrlHelper::parse($request_uri); unset($parsed['query'][static::AJAX_FORM_REQUEST], $parsed['query'][MainContentViewSubscriber::WRAPPER_FORMAT]); - return $parsed['path'] . ($parsed['query'] ? ('?' . UrlHelper::buildQuery($parsed['query'])) : ''); + $action = $parsed['path'] . ($parsed['query'] ? ('?' . UrlHelper::buildQuery($parsed['query'])) : ''); + return UrlHelper::filterBadProtocol($action); } /** diff --git a/web/core/lib/Drupal/Core/Logger/RfcLogLevel.php b/web/core/lib/Drupal/Core/Logger/RfcLogLevel.php index cff99fa533..76a83ca469 100644 --- a/web/core/lib/Drupal/Core/Logger/RfcLogLevel.php +++ b/web/core/lib/Drupal/Core/Logger/RfcLogLevel.php @@ -10,13 +10,13 @@ * Logging severity levels as defined in RFC 5424. * * The constant definitions of this class correspond to the logging severity - * levels defined in RFC 5424, section 4.1.1. PHP supplies predefined LOG_* + * levels defined in RFC 5424, section 6.2.1. PHP supplies predefined LOG_* * constants for use in the syslog() function, but their values on Windows * builds do not correspond to RFC 5424. The associated PHP bug report was * closed with the comment, "And it's also not a bug, as Windows just have less * log levels," and "So the behavior you're seeing is perfectly normal." * - * @see http://tools.ietf.org/html/rfc5424 + * @see https://tools.ietf.org/html/rfc5424#section-6.2.1 * @see http://bugs.php.net/bug.php?id=18090 * @see http://php.net/manual/function.syslog.php * @see http://php.net/manual/network.constants.php diff --git a/web/core/lib/Drupal/Core/Render/Element/Email.php b/web/core/lib/Drupal/Core/Render/Element/Email.php index 84bb35265c..908d71ea6a 100644 --- a/web/core/lib/Drupal/Core/Render/Element/Email.php +++ b/web/core/lib/Drupal/Core/Render/Element/Email.php @@ -15,14 +15,14 @@ * * Example usage: * @code - * $form['email'] = array( + * $form['email'] = [ * '#type' => 'email', * '#title' => $this->t('Email'), * '#pattern' => '*@example.com', - * ); - * @end + * ]; + * @endcode * - * @see \Drupal\Core\Render\Element\Render\Textfield + * @see \Drupal\Core\Render\Element\Textfield * * @FormElement("email") */ diff --git a/web/core/misc/ajax.es6.js b/web/core/misc/ajax.es6.js index 6eeddf3df7..119642dba7 100644 --- a/web/core/misc/ajax.es6.js +++ b/web/core/misc/ajax.es6.js @@ -559,6 +559,7 @@ } }, dataType: 'json', + jsonp: false, type: 'POST', }; diff --git a/web/core/misc/ajax.js b/web/core/misc/ajax.js index cc3936ca6a..b817b77b05 100644 --- a/web/core/misc/ajax.js +++ b/web/core/misc/ajax.js @@ -243,6 +243,7 @@ function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr }, dataType: 'json', + jsonp: false, type: 'POST' }; diff --git a/web/core/misc/autocomplete.es6.js b/web/core/misc/autocomplete.es6.js index 65f6332af6..1b5d879146 100644 --- a/web/core/misc/autocomplete.es6.js +++ b/web/core/misc/autocomplete.es6.js @@ -281,6 +281,7 @@ }, ajax: { dataType: 'json', + jsonp: false, }, }; diff --git a/web/core/misc/autocomplete.js b/web/core/misc/autocomplete.js index 52ddfd2ab4..fc90d77558 100644 --- a/web/core/misc/autocomplete.js +++ b/web/core/misc/autocomplete.js @@ -156,7 +156,8 @@ isComposing: false }, ajax: { - dataType: 'json' + dataType: 'json', + jsonp: false } }; diff --git a/web/core/modules/ban/tests/src/Functional/IpAddressBlockingTest.php b/web/core/modules/ban/tests/src/Functional/IpAddressBlockingTest.php index 0df08b0f74..1b4ecd84b7 100644 --- a/web/core/modules/ban/tests/src/Functional/IpAddressBlockingTest.php +++ b/web/core/modules/ban/tests/src/Functional/IpAddressBlockingTest.php @@ -39,7 +39,7 @@ public function testIPAddressValidation() { $edit = []; $edit['ip'] = '1.2.3.3'; $this->drupalPostForm('admin/config/people/ban', $edit, t('Add')); - $ip = $connection->query("SELECT iid from {ban_ip} WHERE ip = :ip", [':ip' => $edit['ip']])->fetchField(); + $ip = $connection->select('ban_ip', 'bi')->fields('bi', ['iid'])->condition('ip', $edit['ip'])->execute()->fetchField(); $this->assertNotEmpty($ip, 'IP address found in database.'); $this->assertRaw(t('The IP address %ip has been banned.', ['%ip' => $edit['ip']]), 'IP address was banned.'); @@ -70,7 +70,7 @@ public function testIPAddressValidation() { // Pass an IP address as a URL parameter and submit it. $submit_ip = '1.2.3.4'; $this->drupalPostForm('admin/config/people/ban/' . $submit_ip, [], t('Add')); - $ip = $connection->query("SELECT iid from {ban_ip} WHERE ip = :ip", [':ip' => $submit_ip])->fetchField(); + $ip = $connection->select('ban_ip', 'bi')->fields('bi', ['iid'])->condition('ip', $submit_ip)->execute()->fetchField(); $this->assertNotEmpty($ip, 'IP address found in database'); $this->assertRaw(t('The IP address %ip has been banned.', ['%ip' => $submit_ip]), 'IP address was banned.'); diff --git a/web/core/modules/big_pipe/tests/src/Functional/BigPipeTest.php b/web/core/modules/big_pipe/tests/src/Functional/BigPipeTest.php index d5bb0bcf04..5d6775c0ec 100644 --- a/web/core/modules/big_pipe/tests/src/Functional/BigPipeTest.php +++ b/web/core/modules/big_pipe/tests/src/Functional/BigPipeTest.php @@ -153,7 +153,7 @@ public function testBigPipe() { $this->assertBigPipeNoJsCookieExists(FALSE); $connection = Database::getConnection(); - $log_count = $connection->query('SELECT COUNT(*) FROM {watchdog}')->fetchField(); + $log_count = $connection->select('watchdog')->countQuery()->execute()->fetchField(); // By not calling performMetaRefresh() here, we simulate JavaScript being // enabled, because as far as the BigPipe module is concerned, JavaScript is @@ -191,10 +191,11 @@ public function testBigPipe() { $this->assertContains('big_pipe/big_pipe', explode(',', $this->getDrupalSettings()['ajaxPageState']['libraries']), 'BigPipe asset library is present.'); // Verify that the two expected exceptions are logged as errors. - $this->assertEqual($log_count + 2, $connection->query('SELECT COUNT(*) FROM {watchdog}')->fetchField(), 'Two new watchdog entries.'); - // Using the method queryRange() allows contrib database drivers the ability - // to insert their own limit and offset functionality. - $records = $connection->queryRange('SELECT * FROM {watchdog} ORDER BY wid DESC', 0, 2)->fetchAll(); + $this->assertEqual($log_count + 2, (int) $connection->select('watchdog')->countQuery()->execute()->fetchField(), 'Two new watchdog entries.'); + // Using dynamic select queries with the method range() allows contrib + // database drivers the ability to insert their own limit and offset + // functionality. + $records = $connection->select('watchdog', 'w')->fields('w')->orderBy('wid', 'DESC')->range(0, 2)->execute()->fetchAll(); $this->assertEqual(RfcLogLevel::ERROR, $records[0]->severity); $this->assertStringContainsString('Oh noes!', (string) unserialize($records[0]->variables)['@message']); $this->assertEqual(RfcLogLevel::ERROR, $records[1]->severity); diff --git a/web/core/modules/ckeditor/js/plugins/drupalimagecaption/plugin.es6.js b/web/core/modules/ckeditor/js/plugins/drupalimagecaption/plugin.es6.js index 1e63c4b782..f90a77088d 100644 --- a/web/core/modules/ckeditor/js/plugins/drupalimagecaption/plugin.es6.js +++ b/web/core/modules/ckeditor/js/plugins/drupalimagecaption/plugin.es6.js @@ -215,6 +215,9 @@ 'figcaption', ); + const captionFilter = new CKEDITOR.filter(widgetDefinition.editables.caption.allowedContent); + captionFilter.applyTo(caption); + // Use Drupal's data-placeholder attribute to insert a CSS-based, // translation-ready placeholder for empty captions. Note that it // also must to be done for new instances (see diff --git a/web/core/modules/ckeditor/js/plugins/drupalimagecaption/plugin.js b/web/core/modules/ckeditor/js/plugins/drupalimagecaption/plugin.js index 7cd215a705..2f43b9d9c6 100644 --- a/web/core/modules/ckeditor/js/plugins/drupalimagecaption/plugin.js +++ b/web/core/modules/ckeditor/js/plugins/drupalimagecaption/plugin.js @@ -139,6 +139,9 @@ var figure = new CKEDITOR.htmlParser.element('figure'); caption = new CKEDITOR.htmlParser.fragment.fromHtml(caption, 'figcaption'); + var captionFilter = new CKEDITOR.filter(widgetDefinition.editables.caption.allowedContent); + captionFilter.applyTo(caption); + caption.attributes['data-placeholder'] = placeholderText; element.replaceWith(figure); diff --git a/web/core/modules/content_moderation/src/Plugin/views/filter/ModerationStateFilter.php b/web/core/modules/content_moderation/src/Plugin/views/filter/ModerationStateFilter.php index 69309f00d3..4c7ea7c525 100644 --- a/web/core/modules/content_moderation/src/Plugin/views/filter/ModerationStateFilter.php +++ b/web/core/modules/content_moderation/src/Plugin/views/filter/ModerationStateFilter.php @@ -123,6 +123,7 @@ protected function opSimple() { $this->ensureMyTable(); $entity_type = $this->entityTypeManager->getDefinition($this->getEntityType()); + $bundle_condition = NULL; if ($entity_type->hasKey('bundle')) { // Get a list of bundles that are being moderated by the workflows // configured in this filter. @@ -156,7 +157,8 @@ protected function opSimple() { $entity_base_table_alias = $this->query->addRelationship($entity_base_table, $join, $entity_revision_base_table); } - $this->query->addWhere($this->options['group'], "$entity_base_table_alias.{$entity_type->getKey('bundle')}", $moderated_bundles, 'IN'); + $bundle_condition = new Condition('AND'); + $bundle_condition->condition("$entity_base_table_alias.{$entity_type->getKey('bundle')}", $moderated_bundles, 'IN'); } // Otherwise, force the query to return an empty result. else { @@ -186,7 +188,14 @@ protected function opSimple() { $field->condition($and); } - $this->query->addWhere($this->options['group'], $field); + if ($bundle_condition) { + // The query must match the bundle AND the workflow/state conditions. + $bundle_condition->condition($field); + $this->query->addWhere($this->options['group'], $bundle_condition); + } + else { + $this->query->addWhere($this->options['group'], $field); + } } /** diff --git a/web/core/modules/content_moderation/tests/modules/content_moderation_test_views/config/install/views.view.test_content_moderation_state_filter_base_table_filter_group_or.yml b/web/core/modules/content_moderation/tests/modules/content_moderation_test_views/config/install/views.view.test_content_moderation_state_filter_base_table_filter_group_or.yml new file mode 100644 index 0000000000..5a45433c7b --- /dev/null +++ b/web/core/modules/content_moderation/tests/modules/content_moderation_test_views/config/install/views.view.test_content_moderation_state_filter_base_table_filter_group_or.yml @@ -0,0 +1,268 @@ +langcode: en +status: true +dependencies: + module: + - content_moderation + - node + - user +id: test_content_moderation_state_filter_base_table_filter_group_or +label: test_content_moderation_state_filter_base_table_filter_group_or +module: views +description: '' +tag: '' +base_table: node_field_data +base_field: nid +display: + default: + display_plugin: default + id: default + display_title: Master + position: 0 + display_options: + access: + type: perm + options: + perm: 'access content' + cache: + type: tag + options: { } + query: + type: views_query + options: + disable_sql_rewrite: false + distinct: false + replica: false + query_comment: '' + query_tags: { } + exposed_form: + type: basic + options: + submit_button: Apply + reset_button: false + reset_button_label: Reset + exposed_sorts_label: 'Sort by' + expose_sort_order: true + sort_asc_label: Asc + sort_desc_label: Desc + pager: + type: none + options: + offset: 0 + style: + type: default + options: + grouping: { } + row_class: '' + default_row_class: true + uses_fields: false + row: + type: fields + options: + inline: { } + separator: '' + hide_empty: false + default_field_elements: true + fields: + nid: + id: nid + table: node_field_data + field: nid + relationship: none + group_type: group + admin_label: '' + label: '' + exclude: false + alter: + alter_text: false + text: '' + make_link: false + path: '' + absolute: false + external: false + replace_spaces: false + path_case: none + trim_whitespace: false + alt: '' + rel: '' + link_class: '' + prefix: '' + suffix: '' + target: '' + nl2br: false + max_length: 0 + word_boundary: true + ellipsis: true + more_link: false + more_link_text: '' + more_link_path: '' + strip_tags: false + trim: false + preserve_tags: '' + html: false + element_type: '' + element_class: '' + element_label_type: '' + element_label_class: '' + element_label_colon: false + element_wrapper_type: '' + element_wrapper_class: '' + element_default_classes: true + empty: '' + hide_empty: false + empty_zero: false + hide_alter_empty: true + click_sort_column: value + type: number_integer + settings: + thousand_separator: '' + prefix_suffix: false + group_column: value + group_columns: { } + group_rows: true + delta_limit: 0 + delta_offset: 0 + delta_reversed: false + delta_first_last: false + multi_type: separator + separator: ', ' + field_api_classes: false + entity_type: node + entity_field: nid + plugin_id: field + filters: + moderation_state: + id: moderation_state + table: node_field_data + field: moderation_state + relationship: none + group_type: group + admin_label: '' + operator: in + value: { } + group: 1 + exposed: true + expose: + operator_id: moderation_state_op + label: 'Default Revision State' + description: '' + use_operator: false + operator: moderation_state_op + identifier: default_revision_state + required: false + remember: false + multiple: false + remember_roles: + authenticated: authenticated + anonymous: '0' + administrator: '0' + reduce: false + operator_limit_selection: false + operator_list: { } + is_grouped: false + group_info: + label: '' + description: '' + identifier: '' + optional: true + widget: select + multiple: false + remember: false + default_group: All + default_group_multiple: { } + group_items: { } + entity_type: node + plugin_id: moderation_state_filter + moderation_state_1: + id: moderation_state_1 + table: node_field_data + field: moderation_state + relationship: none + group_type: group + admin_label: '' + operator: 'not empty' + value: { } + group: 2 + exposed: false + expose: + operator_id: '' + label: '' + description: '' + use_operator: false + operator: '' + identifier: '' + required: false + remember: false + multiple: false + remember_roles: + authenticated: authenticated + reduce: false + operator_limit_selection: false + operator_list: { } + is_grouped: false + group_info: + label: '' + description: '' + identifier: '' + optional: true + widget: select + multiple: false + remember: false + default_group: All + default_group_multiple: { } + group_items: { } + entity_type: node + plugin_id: moderation_state_filter + sorts: + nid: + id: nid + table: node_field_data + field: nid + relationship: none + group_type: group + admin_label: '' + order: ASC + exposed: false + expose: + label: '' + entity_type: node + entity_field: nid + plugin_id: standard + header: { } + footer: { } + empty: { } + relationships: { } + arguments: { } + display_extenders: { } + filter_groups: + operator: AND + groups: + 1: OR + 2: OR + cache_metadata: + max-age: -1 + contexts: + - 'languages:language_content' + - 'languages:language_interface' + - url + - 'user.node_grants:view' + - user.permissions + tags: + - 'config:workflow_list' + page_1: + display_plugin: page + id: page_1 + display_title: Page + position: 1 + display_options: + display_extenders: { } + path: filter-test-path + cache_metadata: + max-age: -1 + contexts: + - 'languages:language_content' + - 'languages:language_interface' + - url + - 'user.node_grants:view' + - user.permissions + tags: + - 'config:workflow_list' diff --git a/web/core/modules/content_moderation/tests/src/Kernel/ViewsModerationStateFilterTest.php b/web/core/modules/content_moderation/tests/src/Kernel/ViewsModerationStateFilterTest.php index 13f9c688de..328f7c8095 100644 --- a/web/core/modules/content_moderation/tests/src/Kernel/ViewsModerationStateFilterTest.php +++ b/web/core/modules/content_moderation/tests/src/Kernel/ViewsModerationStateFilterTest.php @@ -133,18 +133,26 @@ public function testStateFilterViewsRelationship() { $translated_forward_revision->moderation_state = 'translated_draft'; $translated_forward_revision->save(); - // The three default revisions are listed when no filter is specified. - $this->assertNodesWithFilters([$node, $second_node, $third_node], []); - - // The default revision of node one and three are published. - $this->assertNodesWithFilters([$node, $third_node], [ - 'default_revision_state' => 'editorial-published', - ]); - - // The default revision of node two is draft. - $this->assertNodesWithFilters([$second_node], [ - 'default_revision_state' => 'editorial-draft', - ]); + // Test the filter within an AND filter group (the default) and an OR filter + // group. + $base_table_views = [ + 'test_content_moderation_state_filter_base_table', + 'test_content_moderation_state_filter_base_table_filter_group_or', + ]; + foreach ($base_table_views as $view_id) { + // The three default revisions are listed when no filter is specified. + $this->assertNodesWithFilters([$node, $second_node, $third_node], [], $view_id); + + // The default revision of node one and three are published. + $this->assertNodesWithFilters([$node, $third_node], [ + 'default_revision_state' => 'editorial-published', + ], $view_id); + + // The default revision of node two is draft. + $this->assertNodesWithFilters([$second_node], [ + 'default_revision_state' => 'editorial-draft', + ], $view_id); + } // Test the same three revisions on a view displaying content revisions. // Both nodes have one draft revision. diff --git a/web/core/modules/dblog/tests/src/Functional/DbLogResourceTest.php b/web/core/modules/dblog/tests/src/Functional/DbLogResourceTest.php index d36ab8a7d0..86a800c907 100644 --- a/web/core/modules/dblog/tests/src/Functional/DbLogResourceTest.php +++ b/web/core/modules/dblog/tests/src/Functional/DbLogResourceTest.php @@ -64,7 +64,12 @@ public function testWatchdog() { // Write a log message to the DB. $this->container->get('logger.channel.rest')->notice('Test message'); // Get the ID of the written message. - $id = Database::getConnection()->queryRange("SELECT wid FROM {watchdog} WHERE type = :type ORDER BY wid DESC", 0, 1, [':type' => 'rest']) + $id = Database::getConnection()->select('watchdog', 'w') + ->fields('w', ['wid']) + ->condition('type', 'rest') + ->orderBy('wid', 'DESC') + ->range(0, 1) + ->execute() ->fetchField(); $this->initAuthentication(); diff --git a/web/core/modules/dblog/tests/src/Functional/DbLogTest.php b/web/core/modules/dblog/tests/src/Functional/DbLogTest.php index e83ef261e0..b835a5debd 100644 --- a/web/core/modules/dblog/tests/src/Functional/DbLogTest.php +++ b/web/core/modules/dblog/tests/src/Functional/DbLogTest.php @@ -123,7 +123,9 @@ public function testLogEventPage() { 'timestamp' => REQUEST_TIME, ]; \Drupal::service('logger.dblog')->log(RfcLogLevel::NOTICE, 'Test message', $context); - $wid = Database::getConnection()->query('SELECT MAX(wid) FROM {watchdog}')->fetchField(); + $query = Database::getConnection()->select('watchdog'); + $query->addExpression('MAX(wid)'); + $wid = $query->execute()->fetchField(); // Verify the links appear correctly. $this->drupalGet('admin/reports/dblog/event/' . $wid); @@ -153,7 +155,10 @@ public function test403LogEventPage() { $this->drupalLogin($this->adminUser); - $wid = Database::getConnection()->query("SELECT MAX(wid) FROM {watchdog} WHERE type='access denied'")->fetchField(); + $query = Database::getConnection()->select('watchdog') + ->condition('type', 'access denied'); + $query->addExpression('MAX(wid)'); + $wid = $query->execute()->fetchField(); $this->drupalGet('admin/reports/dblog/event/' . $wid); $table = $this->xpath("//table[@class='dblog-event']"); @@ -208,7 +213,9 @@ public function testLogEventPageWithMissingInfo() { $this->generateLogEntries(1, [ 'referer' => NULL, ]); - $wid = $connection->query('SELECT MAX(wid) FROM {watchdog}')->fetchField(); + $query = $connection->select('watchdog'); + $query->addExpression('MAX(wid)'); + $wid = $query->execute()->fetchField(); $this->drupalGet('admin/reports/dblog/event/' . $wid); // Verify table headers are present, even though the referrer is missing. @@ -222,7 +229,9 @@ public function testLogEventPageWithMissingInfo() { $this->generateLogEntries(1, [ 'request_uri' => $request_uri, ]); - $wid = $connection->query('SELECT MAX(wid) FROM {watchdog}')->fetchField(); + $query = $connection->select('watchdog'); + $query->addExpression('MAX(wid)'); + $wid = $query->execute()->fetchField(); $this->drupalGet('admin/reports/dblog/event/' . $wid); // Verify table headers are present. @@ -322,7 +331,9 @@ private function verifyReports($response = 200) { } // View the database log event page. - $wid = Database::getConnection()->query('SELECT MIN(wid) FROM {watchdog}')->fetchField(); + $query = Database::getConnection()->select('watchdog'); + $query->addExpression('MIN(wid)'); + $wid = $query->execute()->fetchField(); $this->drupalGet('admin/reports/dblog/event/' . $wid); $this->assertSession()->statusCodeEquals($response); if ($response == 200) { @@ -335,7 +346,9 @@ private function verifyReports($response = 200) { */ private function verifyBreadcrumbs() { // View the database log event page. - $wid = Database::getConnection()->query('SELECT MIN(wid) FROM {watchdog}')->fetchField(); + $query = Database::getConnection()->select('watchdog'); + $query->addExpression('MIN(wid)'); + $wid = $query->execute()->fetchField(); $this->drupalGet('admin/reports/dblog/event/' . $wid); $xpath = '//nav[@class="breadcrumb"]/ol/li[last()]/a'; $this->assertEqual(current($this->xpath($xpath))->getText(), 'Recent log messages', 'DBLogs link displayed at breadcrumb in event page.'); @@ -384,7 +397,7 @@ private function verifyLinkEscaping() { 'link' => $link, ]); - $result = Database::getConnection()->queryRange('SELECT wid FROM {watchdog} ORDER BY wid DESC', 0, 1); + $result = Database::getConnection()->select('watchdog', 'w')->fields('w', ['wid'])->orderBy('wid', 'DESC')->range(0, 1)->execute(); $this->drupalGet('admin/reports/dblog/event/' . $result->fetchField()); // Check if the link exists (unescaped). @@ -418,7 +431,7 @@ private function doUser() { // Log out user. $this->drupalLogout(); // Fetch the row IDs in watchdog that relate to the user. - $result = Database::getConnection()->query('SELECT wid FROM {watchdog} WHERE uid = :uid', [':uid' => $user->id()]); + $result = Database::getConnection()->select('watchdog', 'w')->fields('w', ['wid'])->condition('uid', $user->id())->execute(); foreach ($result as $row) { $ids[] = $row->wid; } @@ -590,7 +603,7 @@ public function testDBLogAddAndClear() { global $base_root; $connection = Database::getConnection(); // Get a count of how many watchdog entries already exist. - $count = $connection->query('SELECT COUNT(*) FROM {watchdog}')->fetchField(); + $count = $connection->select('watchdog')->countQuery()->execute()->fetchField(); $log = [ 'channel' => 'system', 'message' => 'Log entry added to test the doClearTest clear down.', @@ -606,7 +619,7 @@ public function testDBLogAddAndClear() { // Add a watchdog entry. $this->container->get('logger.dblog')->log($log['severity'], $log['message'], $log); // Make sure the table count has actually been incremented. - $this->assertEqual($count + 1, $connection->query('SELECT COUNT(*) FROM {watchdog}')->fetchField(), new FormattableMarkup('\Drupal\dblog\Logger\DbLog->log() added an entry to the dblog :count', [':count' => $count])); + $this->assertEqual($count + 1, (int) $connection->select('watchdog')->countQuery()->execute()->fetchField(), new FormattableMarkup('\Drupal\dblog\Logger\DbLog->log() added an entry to the dblog :count', [':count' => $count])); // Log in the admin user. $this->drupalLogin($this->adminUser); // Post in order to clear the database table. @@ -614,7 +627,7 @@ public function testDBLogAddAndClear() { // Confirm that the logs should be cleared. $this->drupalPostForm(NULL, [], 'Confirm'); // Count the rows in watchdog that previously related to the deleted user. - $count = $connection->query('SELECT COUNT(*) FROM {watchdog}')->fetchField(); + $count = $connection->select('watchdog')->countQuery()->execute()->fetchField(); $this->assertEqual($count, 0, new FormattableMarkup('DBLog contains :count records after a clear.', [':count' => $count])); } @@ -803,7 +816,9 @@ public function testTemporaryUser() { // Generate a single watchdog entry. $this->generateLogEntries(1, ['user' => $tempuser, 'uid' => $tempuser_uid]); - $wid = Database::getConnection()->query('SELECT MAX(wid) FROM {watchdog}')->fetchField(); + $query = Database::getConnection()->select('watchdog'); + $query->addExpression('MAX(wid)'); + $wid = $query->execute()->fetchField(); // Check if the full message displays on the details page. $this->drupalGet('admin/reports/dblog/event/' . $wid); @@ -833,7 +848,9 @@ public function testOverviewLinks() { // Make sure HTML tags are filtered out in admin/reports/dblog/event/ too. $this->generateLogEntries(1, ['message' => "<script>alert('foo');</script> <strong>Lorem ipsum</strong>"]); - $wid = Database::getConnection()->query('SELECT MAX(wid) FROM {watchdog}')->fetchField(); + $query = Database::getConnection()->select('watchdog'); + $query->addExpression('MAX(wid)'); + $wid = $query->execute()->fetchField(); $this->drupalGet('admin/reports/dblog/event/' . $wid); $this->assertNoRaw("<script>alert('foo');</script>"); $this->assertRaw("alert('foo'); <strong>Lorem ipsum</strong>"); @@ -864,7 +881,9 @@ public function testBacktrace() { $this->drupalLogin($this->adminUser); $this->drupalGet('/error-test/generate-warnings'); - $wid = Database::getConnection()->query('SELECT MAX(wid) FROM {watchdog}')->fetchField(); + $query = Database::getConnection()->select('watchdog'); + $query->addExpression('MAX(wid)'); + $wid = $query->execute()->fetchField(); $this->drupalGet('admin/reports/dblog/event/' . $wid); $error_user_notice = [ diff --git a/web/core/modules/dblog/tests/src/Kernel/ConnectionFailureTest.php b/web/core/modules/dblog/tests/src/Kernel/ConnectionFailureTest.php index 4914f9f4c9..b17c138d13 100644 --- a/web/core/modules/dblog/tests/src/Kernel/ConnectionFailureTest.php +++ b/web/core/modules/dblog/tests/src/Kernel/ConnectionFailureTest.php @@ -39,7 +39,10 @@ public function testConnectionFailureLogging() { // Re-establish the default database connection. $database = Database::getConnection(); - $wid = $database->query("SELECT MAX(wid) FROM {watchdog} WHERE message = 'testConnectionFailureLogging'")->fetchField(); + $query = $database->select('watchdog') + ->condition('message', 'testConnectionFailureLogging'); + $query->addExpression('MAX(wid)'); + $wid = $query->execute()->fetchField(); $this->assertNotEmpty($wid, 'Watchdog entry has been stored in database.'); } diff --git a/web/core/modules/dblog/tests/src/Kernel/DbLogTest.php b/web/core/modules/dblog/tests/src/Kernel/DbLogTest.php index b211cc7414..3d0af4cefa 100644 --- a/web/core/modules/dblog/tests/src/Kernel/DbLogTest.php +++ b/web/core/modules/dblog/tests/src/Kernel/DbLogTest.php @@ -40,7 +40,7 @@ public function testDbLogCron() { // Generate additional log entries. $this->generateLogEntries($row_limit + 10); // Verify that the database log row count exceeds the row limit. - $count = Database::getConnection()->query('SELECT COUNT(wid) FROM {watchdog}')->fetchField(); + $count = Database::getConnection()->select('watchdog')->countQuery()->execute()->fetchField(); $this->assertGreaterThan($row_limit, $count, new FormattableMarkup('Dblog row count of @count exceeds row limit of @limit', ['@count' => $count, '@limit' => $row_limit])); // Get the number of enabled modules. Cron adds a log entry for each module. @@ -66,13 +66,17 @@ private function runCron() { // Get last ID to compare against; log entries get deleted, so we can't // reliably add the number of newly created log entries to the current count // to measure number of log entries created by cron. - $last_id = $connection->query('SELECT MAX(wid) FROM {watchdog}')->fetchField(); + $query = $connection->select('watchdog'); + $query->addExpression('MAX(wid)'); + $last_id = $query->execute()->fetchField(); // Run a cron job. $this->container->get('cron')->run(); // Get last ID after cron was run. - $current_id = $connection->query('SELECT MAX(wid) FROM {watchdog}')->fetchField(); + $query = $connection->select('watchdog'); + $query->addExpression('MAX(wid)'); + $current_id = $query->execute()->fetchField(); return $current_id - $last_id; } diff --git a/web/core/modules/field/tests/src/Kernel/BulkDeleteTest.php b/web/core/modules/field/tests/src/Kernel/BulkDeleteTest.php index 2ab7b921e4..44964c89bb 100644 --- a/web/core/modules/field/tests/src/Kernel/BulkDeleteTest.php +++ b/web/core/modules/field/tests/src/Kernel/BulkDeleteTest.php @@ -344,10 +344,7 @@ public function testPurgeField() { // bundle. $actual_hooks = field_test_memorize(); $hooks = []; - $entities = $this->entitiesByBundles[$bundle]; - foreach ($entities as $id => $entity) { - $hooks['field_test_field_delete'][] = $entity; - } + $hooks['field_test_field_delete'] = $this->entitiesByBundles[$bundle]; $this->checkHooksInvocations($hooks, $actual_hooks); // The field still exists, deleted. @@ -395,10 +392,7 @@ public function testPurgeFieldStorage() { // bundle. $actual_hooks = field_test_memorize(); $hooks = []; - $entities = $this->entitiesByBundles[$bundle]; - foreach ($entities as $id => $entity) { - $hooks['field_test_field_delete'][] = $entity; - } + $hooks['field_test_field_delete'] = $this->entitiesByBundles[$bundle]; $this->checkHooksInvocations($hooks, $actual_hooks); // The field still exists, deleted. @@ -430,10 +424,7 @@ public function testPurgeFieldStorage() { // Check hooks invocations (same as above, for the 2nd bundle). $actual_hooks = field_test_memorize(); $hooks = []; - $entities = $this->entitiesByBundles[$bundle]; - foreach ($entities as $id => $entity) { - $hooks['field_test_field_delete'][] = $entity; - } + $hooks['field_test_field_delete'] = $this->entitiesByBundles[$bundle]; $this->checkHooksInvocations($hooks, $actual_hooks); // The field and the storage still exist, deleted. diff --git a/web/core/modules/file/src/Element/ManagedFile.php b/web/core/modules/file/src/Element/ManagedFile.php index 8e7843fcbb..d1728b1202 100644 --- a/web/core/modules/file/src/Element/ManagedFile.php +++ b/web/core/modules/file/src/Element/ManagedFile.php @@ -96,6 +96,10 @@ public static function valueCallback(&$element, $input, FormStateInterface $form foreach ($input['fids'] as $fid) { if ($file = File::load($fid)) { $fids[] = $file->id(); + if (!$file->access('download')) { + $force_default = TRUE; + break; + } // Temporary files that belong to other users should never be // allowed. if ($file->isTemporary()) { diff --git a/web/core/modules/file/tests/src/Functional/FilePrivateTest.php b/web/core/modules/file/tests/src/Functional/FilePrivateTest.php index d9f30d53fa..93c7523de1 100644 --- a/web/core/modules/file/tests/src/Functional/FilePrivateTest.php +++ b/web/core/modules/file/tests/src/Functional/FilePrivateTest.php @@ -92,11 +92,10 @@ public function testPrivateFile() { $this->drupalGet('node/' . $new_node->id() . '/edit'); $this->getSession()->getPage()->find('css', 'input[name="' . $field_name . '[0][fids]"]')->setValue($node_file->id()); $this->getSession()->getPage()->pressButton(t('Save')); - // Make sure the form submit failed - we stayed on the edit form. - $this->assertUrl('node/' . $new_node->id() . '/edit'); - // Check that we got the expected constraint form error. - $constraint = new ReferenceAccessConstraint(); - $this->assertRaw(new FormattableMarkup($constraint->message, ['%type' => 'file', '%id' => $node_file->id()])); + $this->assertUrl('node/' . $new_node->id()); + // Make sure the submitted hidden file field is empty. + $new_node = \Drupal::entityTypeManager()->getStorage('node')->loadUnchanged($new_node->id()); + $this->assertTrue($new_node->get($field_name)->isEmpty()); // Attempt to reuse the existing file when creating a new node, and confirm // that access is still denied. $edit = []; @@ -107,9 +106,10 @@ public function testPrivateFile() { $this->getSession()->getPage()->find('css', 'input[name="' . $field_name . '[0][fids]"]')->setValue($node_file->id()); $this->getSession()->getPage()->pressButton(t('Save')); $new_node = $this->drupalGetNodeByTitle($edit['title[0][value]']); - $this->assertTrue(empty($new_node), 'Node was not created.'); - $this->assertUrl('node/add/' . $type_name); - $this->assertRaw(new FormattableMarkup($constraint->message, ['%type' => 'file', '%id' => $node_file->id()])); + $this->assertUrl('node/' . $new_node->id()); + // Make sure the submitted hidden file field is empty. + $new_node = \Drupal::entityTypeManager()->getStorage('node')->loadUnchanged($new_node->id()); + $this->assertTrue($new_node->get($field_name)->isEmpty()); // Now make file_test_file_download() return everything. \Drupal::state()->set('file_test.allow_all', TRUE); diff --git a/web/core/modules/filter/src/Element/TextFormat.php b/web/core/modules/filter/src/Element/TextFormat.php index 75bcaeaab1..caa14c8c65 100644 --- a/web/core/modules/filter/src/Element/TextFormat.php +++ b/web/core/modules/filter/src/Element/TextFormat.php @@ -84,7 +84,7 @@ public static function processFormat(&$element, FormStateInterface $form_state, // Ensure that children appear as subkeys of this element. $element['#tree'] = TRUE; - $blacklist = [ + $keys_not_to_copy = [ // Make \Drupal::formBuilder()->doBuildForm() regenerate child properties. '#parents', '#id', @@ -108,7 +108,7 @@ public static function processFormat(&$element, FormStateInterface $form_state, // Move this element into sub-element 'value'. unset($element['value']); foreach (Element::properties($element) as $key) { - if (!in_array($key, $blacklist)) { + if (!in_array($key, $keys_not_to_copy)) { $element['value'][$key] = $element[$key]; } } diff --git a/web/core/modules/filter/src/Entity/FilterFormat.php b/web/core/modules/filter/src/Entity/FilterFormat.php index 604ce01ac2..abd9b6aae8 100644 --- a/web/core/modules/filter/src/Entity/FilterFormat.php +++ b/web/core/modules/filter/src/Entity/FilterFormat.php @@ -304,7 +304,7 @@ public function getHtmlRestrictions() { // with the existing set, to ensure we only end up with the tags that are // allowed by *all* filters with an "allowed html" setting. else { - // Track the union of forbidden (blacklisted) tags. + // Track the union of forbidden tags. if (isset($new_restrictions['forbidden_tags'])) { if (!isset($restrictions['forbidden_tags'])) { $restrictions['forbidden_tags'] = $new_restrictions['forbidden_tags']; @@ -314,15 +314,15 @@ public function getHtmlRestrictions() { } } - // Track the intersection of allowed (whitelisted) tags. + // Track the intersection of allowed tags. if (isset($restrictions['allowed'])) { $intersection = $restrictions['allowed']; foreach ($intersection as $tag => $attributes) { - // If the current tag is not whitelisted by the new filter, then - // it's outside of the intersection. + // If the current tag is not allowed by the new filter, then it's + // outside of the intersection. if (!array_key_exists($tag, $new_restrictions['allowed'])) { // The exception is the asterisk (which applies to all tags): it - // does not need to be whitelisted by every filter in order to be + // does not need to be allowed by every filter in order to be // used; not every filter needs attribute restrictions on all tags. if ($tag === '*') { continue; @@ -375,10 +375,10 @@ public function getHtmlRestrictions() { } }, NULL); - // Simplification: if we have both a (intersected) whitelist and a (unioned) - // blacklist, then remove any tags from the whitelist that also exist in the - // blacklist. Now the whitelist alone expresses all tag-level restrictions, - // and we can delete the blacklist. + // Simplification: if we have both allowed (intersected) and forbidden + // (unioned) tags, then remove any allowed tags that are also forbidden. + // Once complete, the list of allowed tags expresses all tag-level + // restrictions, and the list of forbidden tags can be removed. if (isset($restrictions['allowed']) && isset($restrictions['forbidden_tags'])) { foreach ($restrictions['forbidden_tags'] as $tag) { if (isset($restrictions['allowed'][$tag])) { @@ -388,9 +388,9 @@ public function getHtmlRestrictions() { unset($restrictions['forbidden_tags']); } - // Simplification: if the only remaining allowed tag is the asterisk (which - // contains attribute restrictions that apply to all tags), and only - // whitelisting filters were used, then effectively nothing is allowed. + // Simplification: if the only remaining allowed tag is the asterisk + // (which contains attribute restrictions that apply to all tags), and + // there are no forbidden tags, then effectively nothing is allowed. if (isset($restrictions['allowed'])) { if (count($restrictions['allowed']) === 1 && array_key_exists('*', $restrictions['allowed']) && !isset($restrictions['forbidden_tags'])) { $restrictions['allowed'] = []; diff --git a/web/core/modules/filter/src/FilterFormatInterface.php b/web/core/modules/filter/src/FilterFormatInterface.php index 6008f3fa40..707776b39a 100644 --- a/web/core/modules/filter/src/FilterFormatInterface.php +++ b/web/core/modules/filter/src/FilterFormatInterface.php @@ -72,10 +72,10 @@ public function getFilterTypes(); * * @return array|false * A structured array as returned by FilterInterface::getHTMLRestrictions(), - * but with the intersection of all filters in this text format. - * Will either indicate blacklisting of tags or whitelisting of tags. In - * the latter case, it's possible that restrictions on attributes are also - * stored. FALSE means there are no HTML restrictions. + * but with the intersection of all filters in this text format. The + * restrictions will either forbid or allow a list of tags. In the latter + * case, it's possible that restrictions on attributes are also stored. + * FALSE means there are no HTML restrictions. */ public function getHtmlRestrictions(); diff --git a/web/core/modules/filter/src/Plugin/Filter/FilterCaption.php b/web/core/modules/filter/src/Plugin/Filter/FilterCaption.php index a03c95f5c8..b5a58563d3 100644 --- a/web/core/modules/filter/src/Plugin/Filter/FilterCaption.php +++ b/web/core/modules/filter/src/Plugin/Filter/FilterCaption.php @@ -4,9 +4,12 @@ use Drupal\Component\Utility\Html; use Drupal\Component\Utility\Xss; +use Drupal\Core\Plugin\ContainerFactoryPluginInterface; +use Drupal\filter\FilterPluginManager; use Drupal\filter\FilterProcessResult; use Drupal\filter\Plugin\FilterBase; use Drupal\filter\Render\FilteredMarkup; +use Symfony\Component\DependencyInjection\ContainerInterface; /** * Provides a filter to caption elements. @@ -20,7 +23,43 @@ * type = Drupal\filter\Plugin\FilterInterface::TYPE_TRANSFORM_REVERSIBLE * ) */ -class FilterCaption extends FilterBase { +class FilterCaption extends FilterBase implements ContainerFactoryPluginInterface { + + /** + * Filter manager. + * + * @var \Drupal\filter\FilterPluginManager + */ + protected $filterManager; + + /** + * Constructs a new FilterCaption. + * + * @param array $configuration + * Configuration. + * @param string $plugin_id + * Plugin ID. + * @param mixed $plugin_definition + * Definition. + * @param \Drupal\filter\FilterPluginManager $filter_manager + * Filter plugin manager. + */ + public function __construct(array $configuration, $plugin_id, $plugin_definition, FilterPluginManager $filter_manager = NULL) { + parent::__construct($configuration, $plugin_id, $plugin_definition); + $this->filterManager = $filter_manager ?: \Drupal::service('plugin.manager.filter'); + } + + /** + * {@inheritdoc} + */ + public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) { + return new static( + $configuration, + $plugin_id, + $plugin_definition, + $container->get('plugin.manager.filter') + ); + } /** * {@inheritdoc} @@ -31,6 +70,13 @@ public function process($text, $langcode) { if (stristr($text, 'data-caption') !== FALSE) { $dom = Html::load($text); $xpath = new \DOMXPath($dom); + $html_filter = $this->filterManager->createInstance('filter_html', [ + 'settings' => [ + 'allowed_html' => '<a href hreflang target rel> <em> <strong> <cite> <code> <br>', + 'filter_html_help' => FALSE, + 'filter_html_nofollow' => FALSE, + ], + ]); foreach ($xpath->query('//*[@data-caption]') as $node) { // Read the data-caption attribute's value, then delete it. $caption = Html::escape($node->getAttribute('data-caption')); @@ -39,10 +85,19 @@ public function process($text, $langcode) { // Sanitize caption: decode HTML encoding, limit allowed HTML tags; only // allow inline tags that are allowed by default, plus <br>. $caption = Html::decodeEntities($caption); - $caption = FilteredMarkup::create(Xss::filter($caption, ['a', 'em', 'strong', 'cite', 'code', 'br'])); + $raw_caption = $caption; + $filtered_caption = $html_filter->process($caption, $langcode); + $result->addCacheableDependency($filtered_caption); + $caption = FilteredMarkup::create($filtered_caption->getProcessedText()); - // The caption must be non-empty. - if (mb_strlen($caption) === 0) { + // The caption must be non-empty - however the Media Embed CKEditor + // plugin uses a single space to represent a newly added caption. The + // HTML filter will transform this into an empty string and prevent the + // content editor from adding a new caption. To allow for this we treat + // a raw caption value of ' ' as valid and adding the wrapping figure + // element. + // @see core/modules/media/js/plugins/drupalmedia/plugin.es6.js + if (mb_strlen($caption) === 0 && $raw_caption !== ' ') { continue; } diff --git a/web/core/modules/filter/src/Plugin/Filter/FilterHtml.php b/web/core/modules/filter/src/Plugin/Filter/FilterHtml.php index 86b8bbdeb1..9c1c9c2a90 100644 --- a/web/core/modules/filter/src/Plugin/Filter/FilterHtml.php +++ b/web/core/modules/filter/src/Plugin/Filter/FilterHtml.php @@ -113,7 +113,7 @@ public function filterAttributes($text) { $xpath = new \DOMXPath($html_dom); foreach ($restrictions['allowed'] as $allowed_tag => $tag_attributes) { // By default, no attributes are allowed for a tag, but due to the - // globally whitelisted attributes, it is impossible for a tag to actually + // globally allowed attributes, it is impossible for a tag to actually // completely disallow attributes. if ($tag_attributes === FALSE) { $tag_attributes = []; @@ -149,23 +149,23 @@ public function filterAttributes($text) { } /** - * Filter attributes on an element by name and value according to a whitelist. + * Filters attributes on an element according to a list of allowed values. * * @param \DOMElement $element * The element to be processed. * @param array $allowed_attributes - * The attributes whitelist as an array of names and values. + * The list of allowed attributes as an array of names and values. */ protected function filterElementAttributes(\DOMElement $element, array $allowed_attributes) { $modified_attributes = []; foreach ($element->attributes as $name => $attribute) { - // Remove attributes not in the whitelist. + // Remove attributes not in the list of allowed attributes. $allowed_value = $this->findAllowedValue($allowed_attributes, $name); if (empty($allowed_value)) { $modified_attributes[$name] = FALSE; } elseif ($allowed_value !== TRUE) { - // Check the attribute values whitelist. + // Check the list of allowed attribute values. $attribute_values = preg_split('/\s+/', $attribute->value, -1, PREG_SPLIT_NO_EMPTY); $modified_attributes[$name] = []; foreach ($attribute_values as $value) { @@ -247,8 +247,8 @@ public function getHTMLRestrictions() { return $this->restrictions; } - // Parse the allowed HTML setting, and gradually make the whitelist more - // specific. + // Parse the allowed HTML setting, and gradually make the list of allowed + // tags more specific. $restrictions = ['allowed' => []]; // Make all the tags self-closing, so they will be parsed into direct @@ -283,7 +283,7 @@ public function getHTMLRestrictions() { // but one allowed attribute value that some may be tempted to use // is specifically nonsensical: the asterisk. A prefix is required for // allowed attribute values with a wildcard. A wildcard by itself - // would mean whitelisting all possible attribute values. But in that + // would mean allowing all possible attribute values. But in that // case, one would not specify an attribute value at all. $allowed_attribute_values = array_filter($allowed_attribute_values, function ($value) use ($star_protector) { return $value !== '*'; @@ -311,14 +311,14 @@ public function getHTMLRestrictions() { // The 'style' and 'on*' ('onClick' etc.) attributes are always forbidden, // and are removed by Xss::filter(). // The 'lang', and 'dir' attributes apply to all elements and are always - // allowed. The value whitelist for the 'dir' attribute is enforced by - // self::filterAttributes(). Note that those two attributes are in the + // allowed. The list of allowed values for the 'dir' attribute is enforced + // by self::filterAttributes(). Note that those two attributes are in the // short list of globally usable attributes in HTML5. They are always // allowed since the correct values of lang and dir may only be known to // the content author. Of the other global attributes, they are not usually // added by hand to content, and especially the class attribute can have // undesired visual effects by allowing content authors to apply any - // available style, so specific values should be explicitly whitelisted. + // available style, so specific values should be explicitly allowed. // @see http://www.w3.org/TR/html5/dom.html#global-attributes $restrictions['allowed']['*'] = [ 'style' => FALSE, diff --git a/web/core/modules/filter/tests/src/Kernel/FilterKernelTest.php b/web/core/modules/filter/tests/src/Kernel/FilterKernelTest.php index 5c2ea33a12..a0637e385d 100644 --- a/web/core/modules/filter/tests/src/Kernel/FilterKernelTest.php +++ b/web/core/modules/filter/tests/src/Kernel/FilterKernelTest.php @@ -404,8 +404,8 @@ public function testLineBreakFilter() { * @todo It is possible to add script, iframe etc. to allowed tags, but this * makes HTML filter completely ineffective. * - * @todo Class, id, name and xmlns should be added to disallowed attributes, - * or better a whitelist approach should be used for that too. + * @todo Class, id, name and xmlns should be added to the list of forbidden + * attributes, or, better yet, use an allowed attribute list. */ public function testHtmlFilter() { // Get FilterHtml object. @@ -460,11 +460,11 @@ public function testHtmlFilter() { $f = (string) $filter->process('<br />', Language::LANGCODE_NOT_SPECIFIED); $this->assertNormalized($f, '<br />', 'HTML filter should allow self-closing line breaks.'); - // All attributes of whitelisted tags are stripped by default. + // All attributes of allowed tags are stripped by default. $f = (string) $filter->process('<a kitten="cute" llama="awesome">link</a>', Language::LANGCODE_NOT_SPECIFIED); $this->assertNormalized($f, '<a>link</a>', 'HTML filter should remove attributes that are not explicitly allowed.'); - // Now whitelist the "llama" attribute on <a>. + // Now allow the "llama" attribute on <a>. $filter->setConfiguration([ 'settings' => [ 'allowed_html' => '<a href llama> <em> <strong> <cite> <blockquote> <code> <ul> <ol> <li> <dl> <dt> <dd> <br>', @@ -475,7 +475,7 @@ public function testHtmlFilter() { $f = (string) $filter->process('<a kitten="cute" llama="awesome">link</a>', Language::LANGCODE_NOT_SPECIFIED); $this->assertNormalized($f, '<a llama="awesome">link</a>', 'HTML filter keeps explicitly allowed attributes, and removes attributes that are not explicitly allowed.'); - // Restrict the whitelisted "llama" attribute on <a> to only allow the value + // Restrict the allowed "llama" attribute on <a> to only allow the value // "majestical", or "epic". $filter->setConfiguration([ 'settings' => [ diff --git a/web/core/modules/jsonapi/jsonapi.api.php b/web/core/modules/jsonapi/jsonapi.api.php index c011e77f79..2d09100e09 100644 --- a/web/core/modules/jsonapi/jsonapi.api.php +++ b/web/core/modules/jsonapi/jsonapi.api.php @@ -63,7 +63,7 @@ * * @see https://github.com/json-api/json-api/pull/1268 * @see https://github.com/json-api/json-api/pull/1311 - * @see https://www.drupal.org/project/jsonapi/issues/2955020 + * @see https://www.drupal.org/project/drupal/issues/2955020 * * By implementing revision support as a profile, the JSON:API module should be * maximally compatible with other systems. @@ -117,7 +117,7 @@ * It is not yet possible to request a collection of revisions. This is still * under development in issue [#3009588]. * - * @see https://www.drupal.org/project/jsonapi/issues/3009588. + * @see https://www.drupal.org/project/drupal/issues/3009588. * @see https://tools.ietf.org/html/rfc5829 * @see https://www.drupal.org/docs/8/modules/jsonapi/revisions * diff --git a/web/core/modules/jsonapi/src/Access/EntityAccessChecker.php b/web/core/modules/jsonapi/src/Access/EntityAccessChecker.php index d3d4fa06e0..1a5b3ea19c 100644 --- a/web/core/modules/jsonapi/src/Access/EntityAccessChecker.php +++ b/web/core/modules/jsonapi/src/Access/EntityAccessChecker.php @@ -31,7 +31,7 @@ * @internal JSON:API maintains no PHP API. The API is the HTTP API. This class * may change at any time and could break any dependencies on it. * - * @see https://www.drupal.org/project/jsonapi/issues/3032787 + * @see https://www.drupal.org/project/drupal/issues/3032787 * @see jsonapi.api.php */ class EntityAccessChecker { @@ -238,7 +238,7 @@ public function checkEntityAccess(EntityInterface $entity, $operation, AccountIn * * @todo: remove when a generic revision access API exists in Drupal core, and * also remove the injected "node" and "media" services. - * @see https://www.drupal.org/project/jsonapi/issues/2992833#comment-12818386 + * @see https://www.drupal.org/project/drupal/issues/2992833#comment-12818386 */ protected function checkRevisionViewAccess(EntityInterface $entity, AccountInterface $account) { assert($entity instanceof RevisionableInterface); @@ -257,7 +257,7 @@ protected function checkRevisionViewAccess(EntityInterface $entity, AccountInter default: $reason = 'Only node and media revisions are supported by JSON:API.'; - $reason .= ' For context, see https://www.drupal.org/project/jsonapi/issues/2992833#comment-12818258.'; + $reason .= ' For context, see https://www.drupal.org/project/drupal/issues/2992833#comment-12818258.'; $reason .= ' To contribute, see https://www.drupal.org/project/drupal/issues/2350939 and https://www.drupal.org/project/drupal/issues/2809177.'; $access = AccessResult::neutral($reason); } diff --git a/web/core/modules/jsonapi/src/Access/RelationshipFieldAccess.php b/web/core/modules/jsonapi/src/Access/RelationshipFieldAccess.php index ff0e103745..244dee3e57 100644 --- a/web/core/modules/jsonapi/src/Access/RelationshipFieldAccess.php +++ b/web/core/modules/jsonapi/src/Access/RelationshipFieldAccess.php @@ -20,7 +20,7 @@ * @internal JSON:API maintains no PHP API. The API is the HTTP API. This class * may change at any time and could break any dependencies on it. * - * @see https://www.drupal.org/project/jsonapi/issues/3032787 + * @see https://www.drupal.org/project/drupal/issues/3032787 * @see jsonapi.api.php */ class RelationshipFieldAccess implements AccessInterface { diff --git a/web/core/modules/jsonapi/src/Access/TemporaryQueryGuard.php b/web/core/modules/jsonapi/src/Access/TemporaryQueryGuard.php index dd3b0a8e3d..a919611cc0 100644 --- a/web/core/modules/jsonapi/src/Access/TemporaryQueryGuard.php +++ b/web/core/modules/jsonapi/src/Access/TemporaryQueryGuard.php @@ -32,7 +32,7 @@ * @see https://www.drupal.org/project/drupal/issues/2809177 * @see https://www.drupal.org/project/drupal/issues/777578 * - * @see https://www.drupal.org/project/jsonapi/issues/3032787 + * @see https://www.drupal.org/project/drupal/issues/3032787 * @see jsonapi.api.php */ class TemporaryQueryGuard { diff --git a/web/core/modules/jsonapi/src/Context/FieldResolver.php b/web/core/modules/jsonapi/src/Context/FieldResolver.php index b67c1cc752..b1e6a025d8 100644 --- a/web/core/modules/jsonapi/src/Context/FieldResolver.php +++ b/web/core/modules/jsonapi/src/Context/FieldResolver.php @@ -67,7 +67,7 @@ * @internal JSON:API maintains no PHP API. The API is the HTTP API. This class * may change at any time and could break any dependencies on it. * - * @see https://www.drupal.org/project/jsonapi/issues/3032787 + * @see https://www.drupal.org/project/drupal/issues/3032787 * @see jsonapi.api.php */ class FieldResolver { @@ -256,18 +256,21 @@ public static function resolveInternalIncludePath(ResourceType $resource_type, a * The JSON:API resource type from which to resolve the field name. * @param string $external_field_name * The public field name to map to a Drupal field name. + * @param string $operator + * (optional) The operator of the condition for which the path should be + * resolved. * * @return string * The mapped field name. * * @throws \Drupal\Core\Http\Exception\CacheableBadRequestHttpException */ - public function resolveInternalEntityQueryPath($resource_type, $external_field_name) { + public function resolveInternalEntityQueryPath($resource_type, $external_field_name, $operator = NULL) { $function_args = func_get_args(); // @todo Remove this conditional block in drupal:9.0.0 and add a type hint // to the first argument of this method. // @see https://www.drupal.org/project/drupal/issues/3078045 - if (count($function_args) === 3) { + if (count($function_args) === 3 && is_string($resource_type)) { @trigger_error('Passing the entity type ID and bundle to ' . __METHOD__ . ' is deprecated in drupal:8.8.0 and will throw a fatal error in drupal:9.0.0. Pass a JSON:API resource type instead. See https://www.drupal.org/node/3078036', E_USER_DEPRECATED); list($entity_type_id, $bundle, $external_field_name) = $function_args; $resource_type = $this->resourceTypeRepository->get($entity_type_id, $bundle); @@ -368,7 +371,10 @@ public function resolveInternalEntityQueryPath($resource_type, $external_field_n // If there are no remaining path parts, the process is finished unless // the field has multiple properties, in which case one must be specified. if (empty($parts)) { - if ($property_specifier_needed) { + // If the operator is asserting the presence or absence of a + // relationship entirely, it does not make sense to require a property + // specifier. + if ($property_specifier_needed && (!$at_least_one_entity_reference_field || !in_array($operator, ['IS NULL', 'IS NOT NULL'], TRUE))) { $possible_specifiers = array_map(function ($specifier) use ($at_least_one_entity_reference_field) { return $at_least_one_entity_reference_field && $specifier !== 'id' ? "meta.$specifier" : $specifier; }, $candidate_property_names); @@ -538,7 +544,7 @@ protected function getInternalName($field_name, array $resource_types) { */ protected function isMemberFilterable($external_name, array $resource_types) { return array_reduce($resource_types, function ($carry, ResourceType $resource_type) use ($external_name) { - // @todo: remove the next line and uncomment the following one in https://www.drupal.org/project/jsonapi/issues/3017047. + // @todo: remove the next line and uncomment the following one in https://www.drupal.org/project/drupal/issues/3017047. return $carry ?: $external_name === 'id' || $resource_type->isFieldEnabled($resource_type->getInternalName($external_name)); /*return $carry ?: in_array($external_name, ['id', 'type']) || $resource_type->isFieldEnabled($resource_type->getInternalName($external_name));*/ }, FALSE); @@ -640,7 +646,7 @@ protected static function getDataReferencePropertyName(array $candidate_definiti $prior_parts = array_slice($unresolved_path_parts, 0, count($unresolved_path_parts) - count($remaining_parts)); return implode('.', array_merge($prior_parts, [$reference_name], $remaining_parts)); }, $unique_reference_names); - // @todo Add test coverage for this in https://www.drupal.org/project/jsonapi/issues/2971281 + // @todo Add test coverage for this in https://www.drupal.org/project/drupal/issues/2971281 $message = sprintf('Ambiguous path. Try one of the following: %s, in place of the given path: %s', implode(', ', $choices), implode('.', $unresolved_path_parts)); $cacheability = (new CacheableMetadata())->addCacheContexts(['url.query_args:filter', 'url.query_args:sort']); throw new CacheableBadRequestHttpException($cacheability, $message); diff --git a/web/core/modules/jsonapi/src/Controller/EntityResource.php b/web/core/modules/jsonapi/src/Controller/EntityResource.php index 4bd865bc0a..30d322774e 100644 --- a/web/core/modules/jsonapi/src/Controller/EntityResource.php +++ b/web/core/modules/jsonapi/src/Controller/EntityResource.php @@ -65,7 +65,7 @@ * @internal JSON:API maintains no PHP API. The API is the HTTP API. This class * may change at any time and could break any dependencies on it. * - * @see https://www.drupal.org/project/jsonapi/issues/3032787 + * @see https://www.drupal.org/project/drupal/issues/3032787 * @see jsonapi.api.php */ class EntityResource { @@ -307,7 +307,7 @@ public function createIndividual(ResourceType $resource_type, Request $request) */ public function patchIndividual(ResourceType $resource_type, EntityInterface $entity, Request $request) { if ($entity instanceof RevisionableInterface && !($entity->isLatestRevision() && $entity->isDefaultRevision())) { - throw new BadRequestHttpException('Updating a resource object that has a working copy is not yet supported. See https://www.drupal.org/project/jsonapi/issues/2795279.'); + throw new BadRequestHttpException('Updating a resource object that has a working copy is not yet supported. See https://www.drupal.org/project/drupal/issues/2795279.'); } $parsed_entity = $this->deserialize($resource_type, $request, JsonApiDocumentTopLevel::class); @@ -408,7 +408,7 @@ public function getCollection(ResourceType $resource_type, Request $request) { catch (\LogicException $e) { // Ensure good DX when an entity query involves a config entity type. // For example: getting users with a particular role, which is a config - // entity type: https://www.drupal.org/project/jsonapi/issues/2959445. + // entity type: https://www.drupal.org/project/drupal/issues/2959445. // @todo Remove the message parsing in https://www.drupal.org/project/drupal/issues/3028967. if (strpos($e->getMessage(), 'Getting the base fields is not supported for entity type') === 0) { preg_match('/entity type (.*)\./', $e->getMessage(), $matches); diff --git a/web/core/modules/jsonapi/src/Controller/EntryPoint.php b/web/core/modules/jsonapi/src/Controller/EntryPoint.php index a564580523..29a4276572 100644 --- a/web/core/modules/jsonapi/src/Controller/EntryPoint.php +++ b/web/core/modules/jsonapi/src/Controller/EntryPoint.php @@ -23,7 +23,7 @@ * @internal JSON:API maintains no PHP API. The API is the HTTP API. This class * may change at any time and could break any dependencies on it. * - * @see https://www.drupal.org/project/jsonapi/issues/3032787 + * @see https://www.drupal.org/project/drupal/issues/3032787 * @see jsonapi.api.php */ class EntryPoint extends ControllerBase { diff --git a/web/core/modules/jsonapi/src/Controller/FileUpload.php b/web/core/modules/jsonapi/src/Controller/FileUpload.php index b4a5800ca2..c11244a799 100644 --- a/web/core/modules/jsonapi/src/Controller/FileUpload.php +++ b/web/core/modules/jsonapi/src/Controller/FileUpload.php @@ -34,7 +34,7 @@ * @internal JSON:API maintains no PHP API. The API is the HTTP API. This class * may change at any time and could break any dependencies on it. * - * @see https://www.drupal.org/project/jsonapi/issues/3032787 + * @see https://www.drupal.org/project/drupal/issues/3032787 * @see jsonapi.api.php */ class FileUpload { @@ -179,7 +179,7 @@ public function handleFileUploadForNewResource(Request $request, ResourceType $r throw new UnprocessableEntityHttpException($message); } - // @todo Remove line below in favor of commented line in https://www.drupal.org/project/jsonapi/issues/2878463. + // @todo Remove line below in favor of commented line in https://www.drupal.org/project/drupal/issues/2878463. $self_link = new Link(new CacheableMetadata(), Url::fromRoute('jsonapi.file--file.individual', ['entity' => $file->uuid()]), 'self'); /* $self_link = new Link(new CacheableMetadata(), $this->entity->toUrl('jsonapi'), ['self']); */ $links = new LinkCollection(['self' => $self_link]); diff --git a/web/core/modules/jsonapi/src/DependencyInjection/Compiler/RegisterSerializationClassesCompilerPass.php b/web/core/modules/jsonapi/src/DependencyInjection/Compiler/RegisterSerializationClassesCompilerPass.php index 7c7d21e146..7587cb3242 100644 --- a/web/core/modules/jsonapi/src/DependencyInjection/Compiler/RegisterSerializationClassesCompilerPass.php +++ b/web/core/modules/jsonapi/src/DependencyInjection/Compiler/RegisterSerializationClassesCompilerPass.php @@ -17,7 +17,7 @@ * @internal JSON:API maintains no PHP API. The API is the HTTP API. This class * may change at any time and could break any dependencies on it. * - * @see https://www.drupal.org/project/jsonapi/issues/3032787 + * @see https://www.drupal.org/project/drupal/issues/3032787 * @see jsonapi.api.php */ class RegisterSerializationClassesCompilerPass extends DrupalRegisterSerializationClassesCompilerPass { diff --git a/web/core/modules/jsonapi/src/Encoder/JsonEncoder.php b/web/core/modules/jsonapi/src/Encoder/JsonEncoder.php index 2f7f04f6f2..fdc83ff2b4 100644 --- a/web/core/modules/jsonapi/src/Encoder/JsonEncoder.php +++ b/web/core/modules/jsonapi/src/Encoder/JsonEncoder.php @@ -10,7 +10,7 @@ * @internal JSON:API maintains no PHP API. The API is the HTTP API. This class * may change at any time and could break any dependencies on it. * - * @see https://www.drupal.org/project/jsonapi/issues/3032787 + * @see https://www.drupal.org/project/drupal/issues/3032787 * @see jsonapi.api.php */ class JsonEncoder extends SerializationJsonEncoder { diff --git a/web/core/modules/jsonapi/src/Entity/EntityValidationTrait.php b/web/core/modules/jsonapi/src/Entity/EntityValidationTrait.php index 8dca70b273..99291254ca 100644 --- a/web/core/modules/jsonapi/src/Entity/EntityValidationTrait.php +++ b/web/core/modules/jsonapi/src/Entity/EntityValidationTrait.php @@ -12,7 +12,7 @@ * @internal JSON:API maintains no PHP API. The API is the HTTP API. This class * may change at any time and could break any dependencies on it. * - * @see https://www.drupal.org/project/jsonapi/issues/3032787 + * @see https://www.drupal.org/project/drupal/issues/3032787 * @see jsonapi.api.php */ trait EntityValidationTrait { diff --git a/web/core/modules/jsonapi/src/EventSubscriber/DefaultExceptionSubscriber.php b/web/core/modules/jsonapi/src/EventSubscriber/DefaultExceptionSubscriber.php index 0220ef55dd..b7ad921c9e 100644 --- a/web/core/modules/jsonapi/src/EventSubscriber/DefaultExceptionSubscriber.php +++ b/web/core/modules/jsonapi/src/EventSubscriber/DefaultExceptionSubscriber.php @@ -18,7 +18,7 @@ * @internal JSON:API maintains no PHP API. The API is the HTTP API. This class * may change at any time and could break any dependencies on it. * - * @see https://www.drupal.org/project/jsonapi/issues/3032787 + * @see https://www.drupal.org/project/drupal/issues/3032787 * @see jsonapi.api.php */ class DefaultExceptionSubscriber extends SerializationDefaultExceptionSubscriber { diff --git a/web/core/modules/jsonapi/src/EventSubscriber/JsonApiRequestValidator.php b/web/core/modules/jsonapi/src/EventSubscriber/JsonApiRequestValidator.php index d030784e83..02e7ac7716 100644 --- a/web/core/modules/jsonapi/src/EventSubscriber/JsonApiRequestValidator.php +++ b/web/core/modules/jsonapi/src/EventSubscriber/JsonApiRequestValidator.php @@ -16,7 +16,7 @@ * @internal JSON:API maintains no PHP API. The API is the HTTP API. This class * may change at any time and could break any dependencies on it. * - * @see https://www.drupal.org/project/jsonapi/issues/3032787 + * @see https://www.drupal.org/project/drupal/issues/3032787 * @see jsonapi.api.php */ class JsonApiRequestValidator implements EventSubscriberInterface { diff --git a/web/core/modules/jsonapi/src/EventSubscriber/ResourceResponseSubscriber.php b/web/core/modules/jsonapi/src/EventSubscriber/ResourceResponseSubscriber.php index 9bf6aaa43a..d04cb211d6 100644 --- a/web/core/modules/jsonapi/src/EventSubscriber/ResourceResponseSubscriber.php +++ b/web/core/modules/jsonapi/src/EventSubscriber/ResourceResponseSubscriber.php @@ -19,7 +19,7 @@ * @internal JSON:API maintains no PHP API. The API is the HTTP API. This class * may change at any time and could break any dependencies on it. * - * @see https://www.drupal.org/project/jsonapi/issues/3032787 + * @see https://www.drupal.org/project/drupal/issues/3032787 * @see jsonapi.api.php * * This is 99% identical to: diff --git a/web/core/modules/jsonapi/src/EventSubscriber/ResourceResponseValidator.php b/web/core/modules/jsonapi/src/EventSubscriber/ResourceResponseValidator.php index 1502a21910..9db86dbc98 100644 --- a/web/core/modules/jsonapi/src/EventSubscriber/ResourceResponseValidator.php +++ b/web/core/modules/jsonapi/src/EventSubscriber/ResourceResponseValidator.php @@ -20,7 +20,7 @@ * @internal JSON:API maintains no PHP API. The API is the HTTP API. This class * may change at any time and could break any dependencies on it. * - * @see https://www.drupal.org/project/jsonapi/issues/3032787 + * @see https://www.drupal.org/project/drupal/issues/3032787 * @see jsonapi.api.php * * @see \Drupal\rest\EventSubscriber\ResourceResponseSubscriber diff --git a/web/core/modules/jsonapi/src/Exception/EntityAccessDeniedHttpException.php b/web/core/modules/jsonapi/src/Exception/EntityAccessDeniedHttpException.php index 3365326aac..74ab245e51 100644 --- a/web/core/modules/jsonapi/src/Exception/EntityAccessDeniedHttpException.php +++ b/web/core/modules/jsonapi/src/Exception/EntityAccessDeniedHttpException.php @@ -18,7 +18,7 @@ * @internal JSON:API maintains no PHP API. The API is the HTTP API. This class * may change at any time and could break any dependencies on it. * - * @see https://www.drupal.org/project/jsonapi/issues/3032787 + * @see https://www.drupal.org/project/drupal/issues/3032787 * @see jsonapi.api.php */ class EntityAccessDeniedHttpException extends CacheableAccessDeniedHttpException implements ResourceIdentifierInterface { @@ -71,7 +71,7 @@ public function __construct($entity, AccessResultInterface $entity_access, $poin $error['reason'] = $entity_access->getReason(); } $this->error = $error; - // @todo: remove this ternary operation in https://www.drupal.org/project/jsonapi/issues/2997594. + // @todo: remove this ternary operation in https://www.drupal.org/project/drupal/issues/2997594. $this->resourceIdentifier = $entity ? ResourceIdentifier::fromEntity($entity) : NULL; } diff --git a/web/core/modules/jsonapi/src/Exception/UnprocessableHttpEntityException.php b/web/core/modules/jsonapi/src/Exception/UnprocessableHttpEntityException.php index 95e496779e..b9d5a6f583 100644 --- a/web/core/modules/jsonapi/src/Exception/UnprocessableHttpEntityException.php +++ b/web/core/modules/jsonapi/src/Exception/UnprocessableHttpEntityException.php @@ -18,7 +18,7 @@ * @internal JSON:API maintains no PHP API. The API is the HTTP API. This class * may change at any time and could break any dependencies on it. * - * @see https://www.drupal.org/project/jsonapi/issues/3032787 + * @see https://www.drupal.org/project/drupal/issues/3032787 * @see jsonapi.api.php */ class UnprocessableHttpEntityException extends HttpException { diff --git a/web/core/modules/jsonapi/src/IncludeResolver.php b/web/core/modules/jsonapi/src/IncludeResolver.php index d8a283df0d..ad0e36ca40 100644 --- a/web/core/modules/jsonapi/src/IncludeResolver.php +++ b/web/core/modules/jsonapi/src/IncludeResolver.php @@ -24,7 +24,7 @@ * @internal JSON:API maintains no PHP API since its API is the HTTP API. This * class may change at any time and this will break any dependencies on it. * - * @see https://www.drupal.org/project/jsonapi/issues/3032787 + * @see https://www.drupal.org/project/drupal/issues/3032787 * @see jsonapi.api.php */ class IncludeResolver { diff --git a/web/core/modules/jsonapi/src/JsonApiResource/Data.php b/web/core/modules/jsonapi/src/JsonApiResource/Data.php index 57dd0ad675..61cf72ca40 100644 --- a/web/core/modules/jsonapi/src/JsonApiResource/Data.php +++ b/web/core/modules/jsonapi/src/JsonApiResource/Data.php @@ -11,7 +11,7 @@ * @internal JSON:API maintains no PHP API. The API is the HTTP API. This class * may change at any time and could break any dependencies on it. * - * @see https://www.drupal.org/project/jsonapi/issues/3032787 + * @see https://www.drupal.org/project/drupal/issues/3032787 * @see jsonapi.api.php */ abstract class Data implements \IteratorAggregate, \Countable { diff --git a/web/core/modules/jsonapi/src/JsonApiResource/ErrorCollection.php b/web/core/modules/jsonapi/src/JsonApiResource/ErrorCollection.php index 2396641abd..d43febdd6e 100644 --- a/web/core/modules/jsonapi/src/JsonApiResource/ErrorCollection.php +++ b/web/core/modules/jsonapi/src/JsonApiResource/ErrorCollection.php @@ -11,7 +11,7 @@ * @internal JSON:API maintains no PHP API. The API is the HTTP API. This class * may change at any time and could break any dependencies on it. * - * @see https://www.drupal.org/project/jsonapi/issues/3032787 + * @see https://www.drupal.org/project/drupal/issues/3032787 * @see jsonapi.api.php * * (The spec says the top-level `data` and `errors` members MUST NOT coexist.) diff --git a/web/core/modules/jsonapi/src/JsonApiResource/IncludedData.php b/web/core/modules/jsonapi/src/JsonApiResource/IncludedData.php index a1566641a6..e0938a1f9a 100644 --- a/web/core/modules/jsonapi/src/JsonApiResource/IncludedData.php +++ b/web/core/modules/jsonapi/src/JsonApiResource/IncludedData.php @@ -11,7 +11,7 @@ * @internal JSON:API maintains no PHP API. The API is the HTTP API. This class * may change at any time and could break any dependencies on it. * - * @see https://www.drupal.org/project/jsonapi/issues/3032787 + * @see https://www.drupal.org/project/drupal/issues/3032787 * @see jsonapi.api.php */ class IncludedData extends ResourceObjectData { diff --git a/web/core/modules/jsonapi/src/JsonApiResource/JsonApiDocumentTopLevel.php b/web/core/modules/jsonapi/src/JsonApiResource/JsonApiDocumentTopLevel.php index 5fc7291f96..df58c32c50 100644 --- a/web/core/modules/jsonapi/src/JsonApiResource/JsonApiDocumentTopLevel.php +++ b/web/core/modules/jsonapi/src/JsonApiResource/JsonApiDocumentTopLevel.php @@ -8,7 +8,7 @@ * @internal JSON:API maintains no PHP API. The API is the HTTP API. This class * may change at any time and could break any dependencies on it. * - * @see https://www.drupal.org/project/jsonapi/issues/3032787 + * @see https://www.drupal.org/project/drupal/issues/3032787 * @see jsonapi.api.php * * @see http://jsonapi.org/format/#document-top-level diff --git a/web/core/modules/jsonapi/src/JsonApiResource/LabelOnlyResourceObject.php b/web/core/modules/jsonapi/src/JsonApiResource/LabelOnlyResourceObject.php index 157b9de1f2..1beaa23056 100644 --- a/web/core/modules/jsonapi/src/JsonApiResource/LabelOnlyResourceObject.php +++ b/web/core/modules/jsonapi/src/JsonApiResource/LabelOnlyResourceObject.php @@ -12,7 +12,7 @@ * @internal JSON:API maintains no PHP API. The API is the HTTP API. This class * may change at any time and could break any dependencies on it. * - * @see https://www.drupal.org/project/jsonapi/issues/3032787 + * @see https://www.drupal.org/project/drupal/issues/3032787 * @see jsonapi.api.php */ final class LabelOnlyResourceObject extends ResourceObject { diff --git a/web/core/modules/jsonapi/src/JsonApiResource/Link.php b/web/core/modules/jsonapi/src/JsonApiResource/Link.php index f098572a65..4f82215719 100644 --- a/web/core/modules/jsonapi/src/JsonApiResource/Link.php +++ b/web/core/modules/jsonapi/src/JsonApiResource/Link.php @@ -15,7 +15,7 @@ * @internal JSON:API maintains no PHP API. The API is the HTTP API. This class * may change at any time and could break any dependencies on it. * - * @see https://www.drupal.org/project/jsonapi/issues/3032787 + * @see https://www.drupal.org/project/drupal/issues/3032787 * @see jsonapi.api.php * * @see https://tools.ietf.org/html/rfc8288 diff --git a/web/core/modules/jsonapi/src/JsonApiResource/LinkCollection.php b/web/core/modules/jsonapi/src/JsonApiResource/LinkCollection.php index 098f580b71..3215888693 100644 --- a/web/core/modules/jsonapi/src/JsonApiResource/LinkCollection.php +++ b/web/core/modules/jsonapi/src/JsonApiResource/LinkCollection.php @@ -10,7 +10,7 @@ * @internal JSON:API maintains no PHP API. The API is the HTTP API. This class * may change at any time and could break any dependencies on it. * - * @see https://www.drupal.org/project/jsonapi/issues/3032787 + * @see https://www.drupal.org/project/drupal/issues/3032787 * @see jsonapi.api.php */ final class LinkCollection implements \IteratorAggregate { diff --git a/web/core/modules/jsonapi/src/JsonApiResource/NullIncludedData.php b/web/core/modules/jsonapi/src/JsonApiResource/NullIncludedData.php index 46b4e6ab5b..6d5da0c1c6 100644 --- a/web/core/modules/jsonapi/src/JsonApiResource/NullIncludedData.php +++ b/web/core/modules/jsonapi/src/JsonApiResource/NullIncludedData.php @@ -8,7 +8,7 @@ * @internal JSON:API maintains no PHP API. The API is the HTTP API. This class * may change at any time and could break any dependencies on it. * - * @see https://www.drupal.org/project/jsonapi/issues/3032787 + * @see https://www.drupal.org/project/drupal/issues/3032787 * @see jsonapi.api.php */ class NullIncludedData extends IncludedData { diff --git a/web/core/modules/jsonapi/src/JsonApiResource/OmittedData.php b/web/core/modules/jsonapi/src/JsonApiResource/OmittedData.php index 1e57348e0e..77fd81ce9e 100644 --- a/web/core/modules/jsonapi/src/JsonApiResource/OmittedData.php +++ b/web/core/modules/jsonapi/src/JsonApiResource/OmittedData.php @@ -11,7 +11,7 @@ * @internal JSON:API maintains no PHP API. The API is the HTTP API. This class * may change at any time and could break any dependencies on it. * - * @see https://www.drupal.org/project/jsonapi/issues/3032787 + * @see https://www.drupal.org/project/drupal/issues/3032787 * @see jsonapi.api.php */ class OmittedData extends ResourceObjectData { diff --git a/web/core/modules/jsonapi/src/JsonApiResource/Relationship.php b/web/core/modules/jsonapi/src/JsonApiResource/Relationship.php index 6e89907a98..b5a383ea89 100644 --- a/web/core/modules/jsonapi/src/JsonApiResource/Relationship.php +++ b/web/core/modules/jsonapi/src/JsonApiResource/Relationship.php @@ -16,7 +16,7 @@ * @internal JSON:API maintains no PHP API since its API is the HTTP API. This * class may change at any time and this will break any dependencies on it. * - * @see https://www.drupal.org/project/jsonapi/issues/3032787 + * @see https://www.drupal.org/project/drupal/issues/3032787 * @see jsonapi.api.php */ class Relationship implements TopLevelDataInterface { diff --git a/web/core/modules/jsonapi/src/JsonApiResource/RelationshipData.php b/web/core/modules/jsonapi/src/JsonApiResource/RelationshipData.php index e4bfa8a2c3..2c2aec5078 100644 --- a/web/core/modules/jsonapi/src/JsonApiResource/RelationshipData.php +++ b/web/core/modules/jsonapi/src/JsonApiResource/RelationshipData.php @@ -10,7 +10,7 @@ * @internal JSON:API maintains no PHP API. The API is the HTTP API. This class * may change at any time and could break any dependencies on it. * - * @see https://www.drupal.org/project/jsonapi/issues/3032787 + * @see https://www.drupal.org/project/drupal/issues/3032787 * @see jsonapi.api.php */ class RelationshipData extends Data { diff --git a/web/core/modules/jsonapi/src/JsonApiResource/ResourceIdentifier.php b/web/core/modules/jsonapi/src/JsonApiResource/ResourceIdentifier.php index b6bca7e3b4..20ca39a856 100644 --- a/web/core/modules/jsonapi/src/JsonApiResource/ResourceIdentifier.php +++ b/web/core/modules/jsonapi/src/JsonApiResource/ResourceIdentifier.php @@ -28,12 +28,12 @@ * @internal JSON:API maintains no PHP API. The API is the HTTP API. This class * may change at any time and could break any dependencies on it. * - * @see https://www.drupal.org/project/jsonapi/issues/3032787 + * @see https://www.drupal.org/project/drupal/issues/3032787 * @see jsonapi.api.php * * @see http://jsonapi.org/format/#document-resource-object-relationships * @see https://github.com/json-api/json-api/pull/1156#issuecomment-325377995 - * @see https://www.drupal.org/project/jsonapi/issues/2864680 + * @see https://www.drupal.org/project/drupal/issues/2864680 */ class ResourceIdentifier implements ResourceIdentifierInterface { diff --git a/web/core/modules/jsonapi/src/JsonApiResource/ResourceIdentifierInterface.php b/web/core/modules/jsonapi/src/JsonApiResource/ResourceIdentifierInterface.php index 872da7dc06..f2e5e6c42d 100644 --- a/web/core/modules/jsonapi/src/JsonApiResource/ResourceIdentifierInterface.php +++ b/web/core/modules/jsonapi/src/JsonApiResource/ResourceIdentifierInterface.php @@ -13,7 +13,7 @@ * @internal JSON:API maintains no PHP API. The API is the HTTP API. This class * may change at any time and could break any dependencies on it. * - * @see https://www.drupal.org/project/jsonapi/issues/3032787 + * @see https://www.drupal.org/project/drupal/issues/3032787 * @see jsonapi.api.php */ interface ResourceIdentifierInterface { diff --git a/web/core/modules/jsonapi/src/JsonApiResource/ResourceIdentifierTrait.php b/web/core/modules/jsonapi/src/JsonApiResource/ResourceIdentifierTrait.php index e4942cfb8f..b7b65586e5 100644 --- a/web/core/modules/jsonapi/src/JsonApiResource/ResourceIdentifierTrait.php +++ b/web/core/modules/jsonapi/src/JsonApiResource/ResourceIdentifierTrait.php @@ -8,7 +8,7 @@ * @internal JSON:API maintains no PHP API. The API is the HTTP API. This class * may change at any time and could break any dependencies on it. * - * @see https://www.drupal.org/project/jsonapi/issues/3032787 + * @see https://www.drupal.org/project/drupal/issues/3032787 * @see jsonapi.api.php * * @see \Drupal\jsonapi\JsonApiResource\ResourceIdentifierInterface diff --git a/web/core/modules/jsonapi/src/JsonApiResource/ResourceObject.php b/web/core/modules/jsonapi/src/JsonApiResource/ResourceObject.php index cce7d45a31..34f64ef839 100644 --- a/web/core/modules/jsonapi/src/JsonApiResource/ResourceObject.php +++ b/web/core/modules/jsonapi/src/JsonApiResource/ResourceObject.php @@ -27,7 +27,7 @@ * @internal JSON:API maintains no PHP API. The API is the HTTP API. This class * may change at any time and could break any dependencies on it. * - * @see https://www.drupal.org/project/jsonapi/issues/3032787 + * @see https://www.drupal.org/project/drupal/issues/3032787 * @see jsonapi.api.php */ class ResourceObject implements CacheableDependencyInterface, ResourceIdentifierInterface { diff --git a/web/core/modules/jsonapi/src/JsonApiResource/ResourceObjectData.php b/web/core/modules/jsonapi/src/JsonApiResource/ResourceObjectData.php index 5fadfb0356..be630e96f8 100644 --- a/web/core/modules/jsonapi/src/JsonApiResource/ResourceObjectData.php +++ b/web/core/modules/jsonapi/src/JsonApiResource/ResourceObjectData.php @@ -11,7 +11,7 @@ * @internal JSON:API maintains no PHP API. The API is the HTTP API. This class * may change at any time and could break any dependencies on it. * - * @see https://www.drupal.org/project/jsonapi/issues/3032787 + * @see https://www.drupal.org/project/drupal/issues/3032787 * @see jsonapi.api.php */ class ResourceObjectData extends Data implements TopLevelDataInterface { diff --git a/web/core/modules/jsonapi/src/JsonApiResource/TopLevelDataInterface.php b/web/core/modules/jsonapi/src/JsonApiResource/TopLevelDataInterface.php index a01da15682..558548f3ca 100644 --- a/web/core/modules/jsonapi/src/JsonApiResource/TopLevelDataInterface.php +++ b/web/core/modules/jsonapi/src/JsonApiResource/TopLevelDataInterface.php @@ -8,7 +8,7 @@ * @internal JSON:API maintains no PHP API since its API is the HTTP API. This * class may change at any time and this will break any dependencies on it. * - * @see https://www.drupal.org/project/jsonapi/issues/3032787 + * @see https://www.drupal.org/project/drupal/issues/3032787 * @see jsonapi.api.php */ interface TopLevelDataInterface { diff --git a/web/core/modules/jsonapi/src/JsonApiSpec.php b/web/core/modules/jsonapi/src/JsonApiSpec.php index a6c8ffa321..c59286fcf5 100644 --- a/web/core/modules/jsonapi/src/JsonApiSpec.php +++ b/web/core/modules/jsonapi/src/JsonApiSpec.php @@ -8,7 +8,7 @@ * @internal JSON:API maintains no PHP API since its API is the HTTP API. This * class may change at any time and this will break any dependencies on it. * - * @see https://www.drupal.org/project/jsonapi/issues/3032787 + * @see https://www.drupal.org/project/drupal/issues/3032787 * @see jsonapi.api.php * * @see http://jsonapi.org/format diff --git a/web/core/modules/jsonapi/src/JsonapiServiceProvider.php b/web/core/modules/jsonapi/src/JsonapiServiceProvider.php index 4696ed567f..e3b0f6d0cc 100644 --- a/web/core/modules/jsonapi/src/JsonapiServiceProvider.php +++ b/web/core/modules/jsonapi/src/JsonapiServiceProvider.php @@ -14,7 +14,7 @@ * @internal JSON:API maintains no PHP API since its API is the HTTP API. This * class may change at any time and this will break any dependencies on it. * - * @see https://www.drupal.org/project/jsonapi/issues/3032787 + * @see https://www.drupal.org/project/drupal/issues/3032787 * @see jsonapi.api.php */ class JsonapiServiceProvider implements ServiceModifierInterface, ServiceProviderInterface { diff --git a/web/core/modules/jsonapi/src/Normalizer/ConfigEntityDenormalizer.php b/web/core/modules/jsonapi/src/Normalizer/ConfigEntityDenormalizer.php index 39288abac9..de74db67aa 100644 --- a/web/core/modules/jsonapi/src/Normalizer/ConfigEntityDenormalizer.php +++ b/web/core/modules/jsonapi/src/Normalizer/ConfigEntityDenormalizer.php @@ -11,7 +11,7 @@ * @internal JSON:API maintains no PHP API since its API is the HTTP API. This * class may change at any time and this will break any dependencies on it. * - * @see https://www.drupal.org/project/jsonapi/issues/3032787 + * @see https://www.drupal.org/project/drupal/issues/3032787 * @see jsonapi.api.php */ final class ConfigEntityDenormalizer extends EntityDenormalizerBase { diff --git a/web/core/modules/jsonapi/src/Normalizer/ContentEntityDenormalizer.php b/web/core/modules/jsonapi/src/Normalizer/ContentEntityDenormalizer.php index 287f2cb140..aa56f8ab9c 100644 --- a/web/core/modules/jsonapi/src/Normalizer/ContentEntityDenormalizer.php +++ b/web/core/modules/jsonapi/src/Normalizer/ContentEntityDenormalizer.php @@ -12,7 +12,7 @@ * @internal JSON:API maintains no PHP API since its API is the HTTP API. This * class may change at any time and this will break any dependencies on it. * - * @see https://www.drupal.org/project/jsonapi/issues/3032787 + * @see https://www.drupal.org/project/drupal/issues/3032787 * @see jsonapi.api.php */ final class ContentEntityDenormalizer extends EntityDenormalizerBase { diff --git a/web/core/modules/jsonapi/src/Normalizer/EntityAccessDeniedHttpExceptionNormalizer.php b/web/core/modules/jsonapi/src/Normalizer/EntityAccessDeniedHttpExceptionNormalizer.php index 0d18dcdea0..5dd2b6e988 100644 --- a/web/core/modules/jsonapi/src/Normalizer/EntityAccessDeniedHttpExceptionNormalizer.php +++ b/web/core/modules/jsonapi/src/Normalizer/EntityAccessDeniedHttpExceptionNormalizer.php @@ -16,7 +16,7 @@ * @internal JSON:API maintains no PHP API since its API is the HTTP API. This * class may change at any time and this will break any dependencies on it. * - * @see https://www.drupal.org/project/jsonapi/issues/3032787 + * @see https://www.drupal.org/project/drupal/issues/3032787 * @see jsonapi.api.php * * @see http://jsonapi.org/format/#error-objects diff --git a/web/core/modules/jsonapi/src/Normalizer/EntityDenormalizerBase.php b/web/core/modules/jsonapi/src/Normalizer/EntityDenormalizerBase.php index 65f25995bf..edfeaa19fd 100644 --- a/web/core/modules/jsonapi/src/Normalizer/EntityDenormalizerBase.php +++ b/web/core/modules/jsonapi/src/Normalizer/EntityDenormalizerBase.php @@ -15,7 +15,7 @@ * @internal JSON:API maintains no PHP API since its API is the HTTP API. This * class may change at any time and this will break any dependencies on it. * - * @see https://www.drupal.org/project/jsonapi/issues/3032787 + * @see https://www.drupal.org/project/drupal/issues/3032787 * @see jsonapi.api.php */ abstract class EntityDenormalizerBase extends NormalizerBase implements DenormalizerInterface { diff --git a/web/core/modules/jsonapi/src/Normalizer/EntityReferenceFieldNormalizer.php b/web/core/modules/jsonapi/src/Normalizer/EntityReferenceFieldNormalizer.php index c79d56ae1a..de46d4d369 100644 --- a/web/core/modules/jsonapi/src/Normalizer/EntityReferenceFieldNormalizer.php +++ b/web/core/modules/jsonapi/src/Normalizer/EntityReferenceFieldNormalizer.php @@ -19,7 +19,7 @@ * @internal JSON:API maintains no PHP API since its API is the HTTP API. This * class may change at any time and this will break any dependencies on it. * - * @see https://www.drupal.org/project/jsonapi/issues/3032787 + * @see https://www.drupal.org/project/drupal/issues/3032787 * @see jsonapi.api.php */ class EntityReferenceFieldNormalizer extends FieldNormalizer { diff --git a/web/core/modules/jsonapi/src/Normalizer/FieldItemNormalizer.php b/web/core/modules/jsonapi/src/Normalizer/FieldItemNormalizer.php index 183fac0730..f3afb42992 100644 --- a/web/core/modules/jsonapi/src/Normalizer/FieldItemNormalizer.php +++ b/web/core/modules/jsonapi/src/Normalizer/FieldItemNormalizer.php @@ -20,7 +20,7 @@ * @internal JSON:API maintains no PHP API since its API is the HTTP API. This * class may change at any time and this will break any dependencies on it. * - * @see https://www.drupal.org/project/jsonapi/issues/3032787 + * @see https://www.drupal.org/project/drupal/issues/3032787 * @see jsonapi.api.php */ class FieldItemNormalizer extends NormalizerBase implements DenormalizerInterface { diff --git a/web/core/modules/jsonapi/src/Normalizer/FieldNormalizer.php b/web/core/modules/jsonapi/src/Normalizer/FieldNormalizer.php index b33677c178..74b78db50e 100644 --- a/web/core/modules/jsonapi/src/Normalizer/FieldNormalizer.php +++ b/web/core/modules/jsonapi/src/Normalizer/FieldNormalizer.php @@ -15,7 +15,7 @@ * @internal JSON:API maintains no PHP API since its API is the HTTP API. This * class may change at any time and this will break any dependencies on it. * - * @see https://www.drupal.org/project/jsonapi/issues/3032787 + * @see https://www.drupal.org/project/drupal/issues/3032787 * @see jsonapi.api.php */ class FieldNormalizer extends NormalizerBase implements DenormalizerInterface { diff --git a/web/core/modules/jsonapi/src/Normalizer/HttpExceptionNormalizer.php b/web/core/modules/jsonapi/src/Normalizer/HttpExceptionNormalizer.php index 4613815815..0b91b4d92f 100644 --- a/web/core/modules/jsonapi/src/Normalizer/HttpExceptionNormalizer.php +++ b/web/core/modules/jsonapi/src/Normalizer/HttpExceptionNormalizer.php @@ -14,7 +14,7 @@ * @internal JSON:API maintains no PHP API since its API is the HTTP API. This * class may change at any time and this will break any dependencies on it. * - * @see https://www.drupal.org/project/jsonapi/issues/3032787 + * @see https://www.drupal.org/project/drupal/issues/3032787 * @see jsonapi.api.php * * @see http://jsonapi.org/format/#error-objects @@ -112,7 +112,7 @@ protected function buildErrorObjects(HttpException $exception) { * URL pointing to the specific RFC-2616 section. Or NULL if it is an HTTP * status code that is defined in another RFC. * - * @see https://www.drupal.org/project/jsonapi/issues/2832211#comment-11826234 + * @see https://www.drupal.org/project/drupal/issues/2832211#comment-11826234 * * @internal */ diff --git a/web/core/modules/jsonapi/src/Normalizer/JsonApiDocumentTopLevelNormalizer.php b/web/core/modules/jsonapi/src/Normalizer/JsonApiDocumentTopLevelNormalizer.php index b6abaf7eaa..ae5cbe0dc3 100644 --- a/web/core/modules/jsonapi/src/Normalizer/JsonApiDocumentTopLevelNormalizer.php +++ b/web/core/modules/jsonapi/src/Normalizer/JsonApiDocumentTopLevelNormalizer.php @@ -28,7 +28,7 @@ * @internal JSON:API maintains no PHP API since its API is the HTTP API. This * class may change at any time and this will break any dependencies on it. * - * @see https://www.drupal.org/project/jsonapi/issues/3032787 + * @see https://www.drupal.org/project/drupal/issues/3032787 * @see jsonapi.api.php * * @see \Drupal\jsonapi\JsonApiResource\JsonApiDocumentTopLevel @@ -217,7 +217,7 @@ public function normalize($object, $format = NULL, array $context = []) { * @return \Drupal\jsonapi\Normalizer\Value\CacheableNormalization * The normalized document. * - * @todo: refactor this to use CacheableNormalization::aggregate in https://www.drupal.org/project/jsonapi/issues/3036284. + * @todo: refactor this to use CacheableNormalization::aggregate in https://www.drupal.org/project/drupal/issues/3036284. */ protected function normalizeErrorDocument(JsonApiDocumentTopLevel $document, $format, array $context = []) { $normalized_values = array_map(function (HttpExceptionInterface $exception) use ($format, $context) { @@ -245,7 +245,7 @@ protected function normalizeErrorDocument(JsonApiDocumentTopLevel $document, $fo * @return \Drupal\jsonapi\Normalizer\Value\CacheableNormalization|\Drupal\jsonapi\Normalizer\Value\CacheableOmission * The normalized omissions. * - * @todo: refactor this to use link collections in https://www.drupal.org/project/jsonapi/issues/3036279. + * @todo: refactor this to use link collections in https://www.drupal.org/project/drupal/issues/3036279. */ protected function normalizeOmissionsLinks(OmittedData $omissions, $format, array $context = []) { $normalized_omissions = array_map(function (HttpExceptionInterface $exception) use ($format, $context) { diff --git a/web/core/modules/jsonapi/src/Normalizer/LinkCollectionNormalizer.php b/web/core/modules/jsonapi/src/Normalizer/LinkCollectionNormalizer.php index a883389d39..2c3f5b71de 100644 --- a/web/core/modules/jsonapi/src/Normalizer/LinkCollectionNormalizer.php +++ b/web/core/modules/jsonapi/src/Normalizer/LinkCollectionNormalizer.php @@ -24,7 +24,7 @@ * @internal JSON:API maintains no PHP API since its API is the HTTP API. This * class may change at any time and this will break any dependencies on it. * - * @see https://www.drupal.org/project/jsonapi/issues/3032787 + * @see https://www.drupal.org/project/drupal/issues/3032787 * @see jsonapi.api.php */ class LinkCollectionNormalizer extends NormalizerBase { diff --git a/web/core/modules/jsonapi/src/Normalizer/NormalizerBase.php b/web/core/modules/jsonapi/src/Normalizer/NormalizerBase.php index 241feac691..37f639bdb7 100644 --- a/web/core/modules/jsonapi/src/Normalizer/NormalizerBase.php +++ b/web/core/modules/jsonapi/src/Normalizer/NormalizerBase.php @@ -11,7 +11,7 @@ * @internal JSON:API maintains no PHP API since its API is the HTTP API. This * class may change at any time and this will break any dependencies on it. * - * @see https://www.drupal.org/project/jsonapi/issues/3032787 + * @see https://www.drupal.org/project/drupal/issues/3032787 * @see jsonapi.api.php */ abstract class NormalizerBase extends SerializationNormalizerBase { diff --git a/web/core/modules/jsonapi/src/Normalizer/ResourceIdentifierNormalizer.php b/web/core/modules/jsonapi/src/Normalizer/ResourceIdentifierNormalizer.php index c1327bdda1..b2ee9cac9a 100644 --- a/web/core/modules/jsonapi/src/Normalizer/ResourceIdentifierNormalizer.php +++ b/web/core/modules/jsonapi/src/Normalizer/ResourceIdentifierNormalizer.php @@ -18,7 +18,7 @@ * @internal JSON:API maintains no PHP API since its API is the HTTP API. This * class may change at any time and this will break any dependencies on it. * - * @see https://www.drupal.org/project/jsonapi/issues/3032787 + * @see https://www.drupal.org/project/drupal/issues/3032787 * @see jsonapi.api.php */ class ResourceIdentifierNormalizer extends NormalizerBase implements DenormalizerInterface { diff --git a/web/core/modules/jsonapi/src/Normalizer/ResourceObjectNormalizer.php b/web/core/modules/jsonapi/src/Normalizer/ResourceObjectNormalizer.php index 10a5e4cca5..8a21f42020 100644 --- a/web/core/modules/jsonapi/src/Normalizer/ResourceObjectNormalizer.php +++ b/web/core/modules/jsonapi/src/Normalizer/ResourceObjectNormalizer.php @@ -17,7 +17,7 @@ * @internal JSON:API maintains no PHP API since its API is the HTTP API. This * class may change at any time and this will break any dependencies on it. * - * @see https://www.drupal.org/project/jsonapi/issues/3032787 + * @see https://www.drupal.org/project/drupal/issues/3032787 * @see jsonapi.api.php */ class ResourceObjectNormalizer extends NormalizerBase { diff --git a/web/core/modules/jsonapi/src/Normalizer/UnprocessableHttpEntityExceptionNormalizer.php b/web/core/modules/jsonapi/src/Normalizer/UnprocessableHttpEntityExceptionNormalizer.php index 35834dd789..aca1088623 100644 --- a/web/core/modules/jsonapi/src/Normalizer/UnprocessableHttpEntityExceptionNormalizer.php +++ b/web/core/modules/jsonapi/src/Normalizer/UnprocessableHttpEntityExceptionNormalizer.php @@ -16,7 +16,7 @@ * @internal JSON:API maintains no PHP API since its API is the HTTP API. This * class may change at any time and this will break any dependencies on it. * - * @see https://www.drupal.org/project/jsonapi/issues/3032787 + * @see https://www.drupal.org/project/drupal/issues/3032787 * @see jsonapi.api.php * * @see http://jsonapi.org/format/#error-objects diff --git a/web/core/modules/jsonapi/src/Normalizer/Value/CacheableNormalization.php b/web/core/modules/jsonapi/src/Normalizer/Value/CacheableNormalization.php index 538422284e..fbc77e89b1 100644 --- a/web/core/modules/jsonapi/src/Normalizer/Value/CacheableNormalization.php +++ b/web/core/modules/jsonapi/src/Normalizer/Value/CacheableNormalization.php @@ -13,7 +13,7 @@ * @internal JSON:API maintains no PHP API since its API is the HTTP API. This * class may change at any time and this will break any dependencies on it. * - * @see https://www.drupal.org/project/jsonapi/issues/3032787 + * @see https://www.drupal.org/project/drupal/issues/3032787 * @see jsonapi.api.php */ class CacheableNormalization implements CacheableDependencyInterface { diff --git a/web/core/modules/jsonapi/src/Normalizer/Value/CacheableOmission.php b/web/core/modules/jsonapi/src/Normalizer/Value/CacheableOmission.php index 9a8310dc44..e3a290723a 100644 --- a/web/core/modules/jsonapi/src/Normalizer/Value/CacheableOmission.php +++ b/web/core/modules/jsonapi/src/Normalizer/Value/CacheableOmission.php @@ -10,7 +10,7 @@ * @internal JSON:API maintains no PHP API since its API is the HTTP API. This * class may change at any time and this will break any dependencies on it. * - * @see https://www.drupal.org/project/jsonapi/issues/3032787 + * @see https://www.drupal.org/project/drupal/issues/3032787 * @see jsonapi.api.php */ final class CacheableOmission extends CacheableNormalization { diff --git a/web/core/modules/jsonapi/src/Normalizer/Value/HttpExceptionNormalizerValue.php b/web/core/modules/jsonapi/src/Normalizer/Value/HttpExceptionNormalizerValue.php index 83cf3beb02..67a61bfd80 100644 --- a/web/core/modules/jsonapi/src/Normalizer/Value/HttpExceptionNormalizerValue.php +++ b/web/core/modules/jsonapi/src/Normalizer/Value/HttpExceptionNormalizerValue.php @@ -8,7 +8,7 @@ * @internal JSON:API maintains no PHP API since its API is the HTTP API. This * class may change at any time and this will break any dependencies on it. * - * @see https://www.drupal.org/project/jsonapi/issues/3032787 + * @see https://www.drupal.org/project/drupal/issues/3032787 * @see jsonapi.api.php */ class HttpExceptionNormalizerValue extends CacheableNormalization {} diff --git a/web/core/modules/jsonapi/src/ParamConverter/EntityUuidConverter.php b/web/core/modules/jsonapi/src/ParamConverter/EntityUuidConverter.php index 75f7181796..f853c15e40 100644 --- a/web/core/modules/jsonapi/src/ParamConverter/EntityUuidConverter.php +++ b/web/core/modules/jsonapi/src/ParamConverter/EntityUuidConverter.php @@ -17,7 +17,7 @@ * @internal JSON:API maintains no PHP API since its API is the HTTP API. This * class may change at any time and this will break any dependencies on it. * - * @see https://www.drupal.org/project/jsonapi/issues/3032787 + * @see https://www.drupal.org/project/drupal/issues/3032787 * @see jsonapi.api.php * * @see \Drupal\Core\ParamConverter\EntityConverter diff --git a/web/core/modules/jsonapi/src/ParamConverter/ResourceTypeConverter.php b/web/core/modules/jsonapi/src/ParamConverter/ResourceTypeConverter.php index ab4569b9d5..d0dba4dd1f 100644 --- a/web/core/modules/jsonapi/src/ParamConverter/ResourceTypeConverter.php +++ b/web/core/modules/jsonapi/src/ParamConverter/ResourceTypeConverter.php @@ -12,7 +12,7 @@ * @internal JSON:API maintains no PHP API since its API is the HTTP API. This * class may change at any time and this will break any dependencies on it. * - * @see https://www.drupal.org/project/jsonapi/issues/3032787 + * @see https://www.drupal.org/project/drupal/issues/3032787 * @see jsonapi.api.php */ class ResourceTypeConverter implements ParamConverterInterface { diff --git a/web/core/modules/jsonapi/src/Query/EntityCondition.php b/web/core/modules/jsonapi/src/Query/EntityCondition.php index 3e2d460b2c..dea06c132d 100644 --- a/web/core/modules/jsonapi/src/Query/EntityCondition.php +++ b/web/core/modules/jsonapi/src/Query/EntityCondition.php @@ -11,7 +11,7 @@ * @internal JSON:API maintains no PHP API since its API is the HTTP API. This * class may change at any time and this will break any dependencies on it. * - * @see https://www.drupal.org/project/jsonapi/issues/3032787 + * @see https://www.drupal.org/project/drupal/issues/3032787 * @see jsonapi.api.php */ class EntityCondition { diff --git a/web/core/modules/jsonapi/src/Query/EntityConditionGroup.php b/web/core/modules/jsonapi/src/Query/EntityConditionGroup.php index fcefe2a278..8a529bf312 100644 --- a/web/core/modules/jsonapi/src/Query/EntityConditionGroup.php +++ b/web/core/modules/jsonapi/src/Query/EntityConditionGroup.php @@ -8,7 +8,7 @@ * @internal JSON:API maintains no PHP API since its API is the HTTP API. This * class may change at any time and this will break any dependencies on it. * - * @see https://www.drupal.org/project/jsonapi/issues/3032787 + * @see https://www.drupal.org/project/drupal/issues/3032787 * @see jsonapi.api.php */ class EntityConditionGroup { diff --git a/web/core/modules/jsonapi/src/Query/Filter.php b/web/core/modules/jsonapi/src/Query/Filter.php index e87f0081a4..ab134317c4 100644 --- a/web/core/modules/jsonapi/src/Query/Filter.php +++ b/web/core/modules/jsonapi/src/Query/Filter.php @@ -12,7 +12,7 @@ * @internal JSON:API maintains no PHP API since its API is the HTTP API. This * class may change at any time and this will break any dependencies on it. * - * @see https://www.drupal.org/project/jsonapi/issues/3032787 + * @see https://www.drupal.org/project/drupal/issues/3032787 * @see jsonapi.api.php */ class Filter { @@ -157,7 +157,8 @@ public static function createFromQueryParameter($parameter, ResourceType $resour foreach ($expanded as &$filter_item) { if (isset($filter_item[static::CONDITION_KEY][EntityCondition::PATH_KEY])) { $unresolved = $filter_item[static::CONDITION_KEY][EntityCondition::PATH_KEY]; - $filter_item[static::CONDITION_KEY][EntityCondition::PATH_KEY] = $field_resolver->resolveInternalEntityQueryPath($resource_type, $unresolved); + $operator = $filter_item[static::CONDITION_KEY][EntityCondition::OPERATOR_KEY]; + $filter_item[static::CONDITION_KEY][EntityCondition::PATH_KEY] = $field_resolver->resolveInternalEntityQueryPath($resource_type, $unresolved, $operator); } } return new static(static::buildEntityConditionGroup($expanded)); diff --git a/web/core/modules/jsonapi/src/Query/OffsetPage.php b/web/core/modules/jsonapi/src/Query/OffsetPage.php index 70a752ef2c..988cc69a50 100644 --- a/web/core/modules/jsonapi/src/Query/OffsetPage.php +++ b/web/core/modules/jsonapi/src/Query/OffsetPage.php @@ -11,7 +11,7 @@ * @internal JSON:API maintains no PHP API since its API is the HTTP API. This * class may change at any time and this will break any dependencies on it. * - * @see https://www.drupal.org/project/jsonapi/issues/3032787 + * @see https://www.drupal.org/project/drupal/issues/3032787 * @see jsonapi.api.php */ class OffsetPage { diff --git a/web/core/modules/jsonapi/src/Query/Sort.php b/web/core/modules/jsonapi/src/Query/Sort.php index c127a9230a..3f01638e91 100644 --- a/web/core/modules/jsonapi/src/Query/Sort.php +++ b/web/core/modules/jsonapi/src/Query/Sort.php @@ -11,7 +11,7 @@ * @internal JSON:API maintains no PHP API since its API is the HTTP API. This * class may change at any time and this will break any dependencies on it. * - * @see https://www.drupal.org/project/jsonapi/issues/3032787 + * @see https://www.drupal.org/project/drupal/issues/3032787 * @see jsonapi.api.php */ class Sort { diff --git a/web/core/modules/jsonapi/src/ResourceResponse.php b/web/core/modules/jsonapi/src/ResourceResponse.php index b73165d170..cf6ddac7a9 100644 --- a/web/core/modules/jsonapi/src/ResourceResponse.php +++ b/web/core/modules/jsonapi/src/ResourceResponse.php @@ -17,7 +17,7 @@ * @internal JSON:API maintains no PHP API since its API is the HTTP API. This * class may change at any time and this will break any dependencies on it. * - * @see https://www.drupal.org/project/jsonapi/issues/3032787 + * @see https://www.drupal.org/project/drupal/issues/3032787 * @see jsonapi.api.php * * @see \Drupal\rest\ModifiedResourceResponse diff --git a/web/core/modules/jsonapi/src/ResourceType/ResourceType.php b/web/core/modules/jsonapi/src/ResourceType/ResourceType.php index 10e2c0fb65..07d92c7387 100644 --- a/web/core/modules/jsonapi/src/ResourceType/ResourceType.php +++ b/web/core/modules/jsonapi/src/ResourceType/ResourceType.php @@ -15,7 +15,7 @@ * @internal JSON:API maintains no PHP API since its API is the HTTP API. This * class may change at any time and this will break any dependencies on it. * - * @see https://www.drupal.org/project/jsonapi/issues/3032787 + * @see https://www.drupal.org/project/drupal/issues/3032787 * @see jsonapi.api.php * * @see \Drupal\jsonapi\ResourceType\ResourceTypeRepository diff --git a/web/core/modules/jsonapi/src/ResourceType/ResourceTypeAttribute.php b/web/core/modules/jsonapi/src/ResourceType/ResourceTypeAttribute.php index 19f71c192f..f606516c9c 100644 --- a/web/core/modules/jsonapi/src/ResourceType/ResourceTypeAttribute.php +++ b/web/core/modules/jsonapi/src/ResourceType/ResourceTypeAttribute.php @@ -8,7 +8,7 @@ * @internal JSON:API maintains no PHP API since its API is the HTTP API. This * class may change at any time and this will break any dependencies on it. * - * @see https://www.drupal.org/project/jsonapi/issues/3032787 + * @see https://www.drupal.org/project/drupal/issues/3032787 * @see jsonapi.api.php * * @see \Drupal\jsonapi\ResourceType\ResourceTypeRepository diff --git a/web/core/modules/jsonapi/src/ResourceType/ResourceTypeField.php b/web/core/modules/jsonapi/src/ResourceType/ResourceTypeField.php index 987f496384..c6a1922f8e 100644 --- a/web/core/modules/jsonapi/src/ResourceType/ResourceTypeField.php +++ b/web/core/modules/jsonapi/src/ResourceType/ResourceTypeField.php @@ -8,7 +8,7 @@ * @internal JSON:API maintains no PHP API since its API is the HTTP API. This * class may change at any time and this will break any dependencies on it. * - * @see https://www.drupal.org/project/jsonapi/issues/3032787 + * @see https://www.drupal.org/project/drupal/issues/3032787 * @see jsonapi.api.php * * @see \Drupal\jsonapi\ResourceType\ResourceTypeRepository diff --git a/web/core/modules/jsonapi/src/ResourceType/ResourceTypeRelationship.php b/web/core/modules/jsonapi/src/ResourceType/ResourceTypeRelationship.php index 8e782a527c..2ae37bd698 100644 --- a/web/core/modules/jsonapi/src/ResourceType/ResourceTypeRelationship.php +++ b/web/core/modules/jsonapi/src/ResourceType/ResourceTypeRelationship.php @@ -8,7 +8,7 @@ * @internal JSON:API maintains no PHP API since its API is the HTTP API. This * class may change at any time and this will break any dependencies on it. * - * @see https://www.drupal.org/project/jsonapi/issues/3032787 + * @see https://www.drupal.org/project/drupal/issues/3032787 * @see jsonapi.api.php * * @see \Drupal\jsonapi\ResourceType\ResourceTypeRepository diff --git a/web/core/modules/jsonapi/src/ResourceType/ResourceTypeRepository.php b/web/core/modules/jsonapi/src/ResourceType/ResourceTypeRepository.php index 724264732f..226c6703d8 100644 --- a/web/core/modules/jsonapi/src/ResourceType/ResourceTypeRepository.php +++ b/web/core/modules/jsonapi/src/ResourceType/ResourceTypeRepository.php @@ -33,7 +33,7 @@ * @internal JSON:API maintains no PHP API since its API is the HTTP API. This * class may change at any time and this will break any dependencies on it. * - * @see https://www.drupal.org/project/jsonapi/issues/3032787 + * @see https://www.drupal.org/project/drupal/issues/3032787 * @see jsonapi.api.php * * @see \Drupal\jsonapi\ResourceType\ResourceType diff --git a/web/core/modules/jsonapi/src/ResourceType/ResourceTypeRepositoryInterface.php b/web/core/modules/jsonapi/src/ResourceType/ResourceTypeRepositoryInterface.php index 6468aaff06..8a66abf5a5 100644 --- a/web/core/modules/jsonapi/src/ResourceType/ResourceTypeRepositoryInterface.php +++ b/web/core/modules/jsonapi/src/ResourceType/ResourceTypeRepositoryInterface.php @@ -8,7 +8,7 @@ * @internal JSON:API maintains no PHP API since its API is the HTTP API. This * class may change at any time and this will break any dependencies on it. * - * @see https://www.drupal.org/project/jsonapi/issues/3032787 + * @see https://www.drupal.org/project/drupal/issues/3032787 * @see jsonapi.api.php */ interface ResourceTypeRepositoryInterface { diff --git a/web/core/modules/jsonapi/src/Revisions/InvalidVersionIdentifierException.php b/web/core/modules/jsonapi/src/Revisions/InvalidVersionIdentifierException.php index d30f4a8596..f56a3aa8d5 100644 --- a/web/core/modules/jsonapi/src/Revisions/InvalidVersionIdentifierException.php +++ b/web/core/modules/jsonapi/src/Revisions/InvalidVersionIdentifierException.php @@ -8,7 +8,7 @@ * @internal JSON:API maintains no PHP API since its API is the HTTP API. This * class may change at any time and this will break any dependencies on it. * - * @see https://www.drupal.org/project/jsonapi/issues/3032787 + * @see https://www.drupal.org/project/drupal/issues/3032787 * @see jsonapi.api.php */ class InvalidVersionIdentifierException extends \InvalidArgumentException {} diff --git a/web/core/modules/jsonapi/src/Revisions/NegotiatorBase.php b/web/core/modules/jsonapi/src/Revisions/NegotiatorBase.php index 0adc78afba..2253090353 100644 --- a/web/core/modules/jsonapi/src/Revisions/NegotiatorBase.php +++ b/web/core/modules/jsonapi/src/Revisions/NegotiatorBase.php @@ -11,7 +11,7 @@ * @internal JSON:API maintains no PHP API since its API is the HTTP API. This * class may change at any time and this will break any dependencies on it. * - * @see https://www.drupal.org/project/jsonapi/issues/3032787 + * @see https://www.drupal.org/project/drupal/issues/3032787 * @see jsonapi.api.php */ abstract class NegotiatorBase implements VersionNegotiatorInterface { diff --git a/web/core/modules/jsonapi/src/Revisions/ResourceVersionRouteEnhancer.php b/web/core/modules/jsonapi/src/Revisions/ResourceVersionRouteEnhancer.php index 50cb8b8c5d..853261346c 100644 --- a/web/core/modules/jsonapi/src/Revisions/ResourceVersionRouteEnhancer.php +++ b/web/core/modules/jsonapi/src/Revisions/ResourceVersionRouteEnhancer.php @@ -18,7 +18,7 @@ * @internal JSON:API maintains no PHP API since its API is the HTTP API. This * class may change at any time and this will break any dependencies on it. * - * @see https://www.drupal.org/project/jsonapi/issues/3032787 + * @see https://www.drupal.org/project/drupal/issues/3032787 * @see jsonapi.api.php */ final class ResourceVersionRouteEnhancer implements EnhancerInterface { @@ -103,7 +103,7 @@ public function enhance(array $defaults, Request $request) { /* Uncomment the next line and remove the following one when https://www.drupal.org/project/drupal/issues/3002352 lands in core. */ /* throw new CacheableHttpException($cacheability, 501, 'Resource versioning is not yet supported for this resource type.'); */ $message = 'JSON:API does not yet support resource versioning for this resource type.'; - $message .= ' For context, see https://www.drupal.org/project/jsonapi/issues/2992833#comment-12818258.'; + $message .= ' For context, see https://www.drupal.org/project/drupal/issues/2992833#comment-12818258.'; $message .= ' To contribute, see https://www.drupal.org/project/drupal/issues/2350939 and https://www.drupal.org/project/drupal/issues/2809177.'; throw new CacheableHttpException($cacheability, 501, $message, NULL, []); } diff --git a/web/core/modules/jsonapi/src/Revisions/VersionById.php b/web/core/modules/jsonapi/src/Revisions/VersionById.php index 4337d37528..36c9825d3a 100644 --- a/web/core/modules/jsonapi/src/Revisions/VersionById.php +++ b/web/core/modules/jsonapi/src/Revisions/VersionById.php @@ -10,7 +10,7 @@ * @internal JSON:API maintains no PHP API since its API is the HTTP API. This * class may change at any time and this will break any dependencies on it. * - * @see https://www.drupal.org/project/jsonapi/issues/3032787 + * @see https://www.drupal.org/project/drupal/issues/3032787 * @see jsonapi.api.php */ class VersionById extends NegotiatorBase implements VersionNegotiatorInterface { diff --git a/web/core/modules/jsonapi/src/Revisions/VersionByRel.php b/web/core/modules/jsonapi/src/Revisions/VersionByRel.php index f825b6533f..0033c1429a 100644 --- a/web/core/modules/jsonapi/src/Revisions/VersionByRel.php +++ b/web/core/modules/jsonapi/src/Revisions/VersionByRel.php @@ -11,7 +11,7 @@ * @internal JSON:API maintains no PHP API since its API is the HTTP API. This * class may change at any time and this will break any dependencies on it. * - * @see https://www.drupal.org/project/jsonapi/issues/3032787 + * @see https://www.drupal.org/project/drupal/issues/3032787 * @see jsonapi.api.php */ class VersionByRel extends NegotiatorBase { diff --git a/web/core/modules/jsonapi/src/Revisions/VersionNegotiator.php b/web/core/modules/jsonapi/src/Revisions/VersionNegotiator.php index 157efa529f..76bd43f0f1 100644 --- a/web/core/modules/jsonapi/src/Revisions/VersionNegotiator.php +++ b/web/core/modules/jsonapi/src/Revisions/VersionNegotiator.php @@ -13,7 +13,7 @@ * @internal JSON:API maintains no PHP API since its API is the HTTP API. This * class may change at any time and this will break any dependencies on it. * - * @see https://www.drupal.org/project/jsonapi/issues/3032787 + * @see https://www.drupal.org/project/drupal/issues/3032787 * @see jsonapi.api.php * * @see \Drupal\jsonapi\Revisions\VersionNegotiatorInterface diff --git a/web/core/modules/jsonapi/src/Revisions/VersionNegotiatorInterface.php b/web/core/modules/jsonapi/src/Revisions/VersionNegotiatorInterface.php index 03a9d8023d..a796468615 100644 --- a/web/core/modules/jsonapi/src/Revisions/VersionNegotiatorInterface.php +++ b/web/core/modules/jsonapi/src/Revisions/VersionNegotiatorInterface.php @@ -10,7 +10,7 @@ * @internal JSON:API maintains no PHP API since its API is the HTTP API. This * class may change at any time and this will break any dependencies on it. * - * @see https://www.drupal.org/project/jsonapi/issues/3032787 + * @see https://www.drupal.org/project/drupal/issues/3032787 * @see jsonapi.api.php * * @see \Drupal\jsonapi\Revisions\VersionNegotiator diff --git a/web/core/modules/jsonapi/src/Revisions/VersionNotFoundException.php b/web/core/modules/jsonapi/src/Revisions/VersionNotFoundException.php index cd6fb4b60e..72d0e38346 100644 --- a/web/core/modules/jsonapi/src/Revisions/VersionNotFoundException.php +++ b/web/core/modules/jsonapi/src/Revisions/VersionNotFoundException.php @@ -8,7 +8,7 @@ * @internal JSON:API maintains no PHP API since its API is the HTTP API. This * class may change at any time and this will break any dependencies on it. * - * @see https://www.drupal.org/project/jsonapi/issues/3032787 + * @see https://www.drupal.org/project/drupal/issues/3032787 * @see jsonapi.api.php */ class VersionNotFoundException extends \InvalidArgumentException { diff --git a/web/core/modules/jsonapi/src/Routing/RouteEnhancer.php b/web/core/modules/jsonapi/src/Routing/RouteEnhancer.php index 0c3b1b477e..1a663fa31b 100644 --- a/web/core/modules/jsonapi/src/Routing/RouteEnhancer.php +++ b/web/core/modules/jsonapi/src/Routing/RouteEnhancer.php @@ -12,7 +12,7 @@ * @internal JSON:API maintains no PHP API since its API is the HTTP API. This * class may change at any time and this will break any dependencies on it. * - * @see https://www.drupal.org/project/jsonapi/issues/3032787 + * @see https://www.drupal.org/project/drupal/issues/3032787 * @see jsonapi.api.php */ class RouteEnhancer implements EnhancerInterface { diff --git a/web/core/modules/jsonapi/src/Routing/Routes.php b/web/core/modules/jsonapi/src/Routing/Routes.php index e592f007ae..6910ae7008 100644 --- a/web/core/modules/jsonapi/src/Routing/Routes.php +++ b/web/core/modules/jsonapi/src/Routing/Routes.php @@ -19,7 +19,7 @@ * @internal JSON:API maintains no PHP API since its API is the HTTP API. This * class may change at any time and this will break any dependencies on it. * - * @see https://www.drupal.org/project/jsonapi/issues/3032787 + * @see https://www.drupal.org/project/drupal/issues/3032787 * @see jsonapi.api.php */ class Routes implements ContainerInjectionInterface { diff --git a/web/core/modules/jsonapi/src/Serializer/Serializer.php b/web/core/modules/jsonapi/src/Serializer/Serializer.php index 67c07c473e..709cf77094 100644 --- a/web/core/modules/jsonapi/src/Serializer/Serializer.php +++ b/web/core/modules/jsonapi/src/Serializer/Serializer.php @@ -12,12 +12,12 @@ * Backwards compatibility is in no way guaranteed and will almost certainly be * broken in the future. * - * @link https://www.drupal.org/project/jsonapi/issues/2923779#comment-12407443 + * @link https://www.drupal.org/project/drupal/issues/2923779#comment-12407443 * * @internal JSON:API maintains no PHP API since its API is the HTTP API. This * class may change at any time and this will break any dependencies on it. * - * @see https://www.drupal.org/project/jsonapi/issues/3032787 + * @see https://www.drupal.org/project/drupal/issues/3032787 * @see jsonapi.api.php */ final class Serializer extends SymfonySerializer { diff --git a/web/core/modules/jsonapi/tests/src/Functional/BlockContentTest.php b/web/core/modules/jsonapi/tests/src/Functional/BlockContentTest.php index d5e51e7a8d..41ac26024e 100644 --- a/web/core/modules/jsonapi/tests/src/Functional/BlockContentTest.php +++ b/web/core/modules/jsonapi/tests/src/Functional/BlockContentTest.php @@ -200,7 +200,7 @@ protected function getExpectedCacheContexts(array $sparse_fieldset = NULL) { * {@inheritdoc} */ public function testRelated() { - $this->markTestSkipped('Remove this in https://www.drupal.org/project/jsonapi/issues/2940339'); + $this->markTestSkipped('Remove this in https://www.drupal.org/project/drupal/issues/2940339'); } /** diff --git a/web/core/modules/jsonapi/tests/src/Functional/CommentTest.php b/web/core/modules/jsonapi/tests/src/Functional/CommentTest.php index 4fd1bb786e..6d5efc59fe 100644 --- a/web/core/modules/jsonapi/tests/src/Functional/CommentTest.php +++ b/web/core/modules/jsonapi/tests/src/Functional/CommentTest.php @@ -392,7 +392,7 @@ protected static function entityAccess(EntityInterface $entity, $operation, Acco * {@inheritdoc} */ public function testRelated() { - $this->markTestSkipped('Remove this in https://www.drupal.org/project/jsonapi/issues/2940339'); + $this->markTestSkipped('Remove this in https://www.drupal.org/project/drupal/issues/2940339'); } /** diff --git a/web/core/modules/jsonapi/tests/src/Functional/ConfigurableLanguageTest.php b/web/core/modules/jsonapi/tests/src/Functional/ConfigurableLanguageTest.php index fd03d53349..5f9b68cd6f 100644 --- a/web/core/modules/jsonapi/tests/src/Functional/ConfigurableLanguageTest.php +++ b/web/core/modules/jsonapi/tests/src/Functional/ConfigurableLanguageTest.php @@ -117,10 +117,10 @@ protected function getExpectedCacheContexts(array $sparse_fieldset = NULL) { /** * Test a GET request for a default config entity, which has a _core key. * - * @see https://www.drupal.org/project/jsonapi/issues/2915539 + * @see https://www.drupal.org/project/drupal/issues/2915539 */ public function testGetIndividualDefaultConfig() { - // @todo Remove line below in favor of commented line in https://www.drupal.org/project/jsonapi/issues/2878463. + // @todo Remove line below in favor of commented line in https://www.drupal.org/project/drupal/issues/2878463. $url = Url::fromRoute('jsonapi.configurable_language--configurable_language.individual', ['entity' => ConfigurableLanguage::load('en')->uuid()]); /* $url = ConfigurableLanguage::load('en')->toUrl('jsonapi'); */ diff --git a/web/core/modules/jsonapi/tests/src/Functional/ExternalNormalizersTest.php b/web/core/modules/jsonapi/tests/src/Functional/ExternalNormalizersTest.php index 33f6aab0de..117a108b3c 100644 --- a/web/core/modules/jsonapi/tests/src/Functional/ExternalNormalizersTest.php +++ b/web/core/modules/jsonapi/tests/src/Functional/ExternalNormalizersTest.php @@ -145,7 +145,7 @@ public function testFormatAgnosticNormalizers($test_module, $expected_value_json $this->assertSame(static::VALUE_ORIGINAL, $denormalized_entity->field_test->value); // Asserts the expected JSON:API normalization. - // @todo Remove line below in favor of commented line in https://www.drupal.org/project/jsonapi/issues/2878463. + // @todo Remove line below in favor of commented line in https://www.drupal.org/project/drupal/issues/2878463. $url = Url::fromRoute('jsonapi.entity_test--entity_test.individual', ['entity' => $this->entity->uuid()]); // $url = $this->entity->toUrl('jsonapi'); $client = $this->getSession()->getDriver()->getClient()->getClient(); diff --git a/web/core/modules/jsonapi/tests/src/Functional/JsonApiRegressionTest.php b/web/core/modules/jsonapi/tests/src/Functional/JsonApiRegressionTest.php index f2da5ad366..01069960e5 100644 --- a/web/core/modules/jsonapi/tests/src/Functional/JsonApiRegressionTest.php +++ b/web/core/modules/jsonapi/tests/src/Functional/JsonApiRegressionTest.php @@ -51,7 +51,7 @@ class JsonApiRegressionTest extends JsonApiFunctionalTestBase { /** * Ensure filtering on relationships works with bundle-specific target types. * - * @see https://www.drupal.org/project/jsonapi/issues/2953207 + * @see https://www.drupal.org/project/drupal/issues/2953207 */ public function testBundleSpecificTargetEntityTypeFromIssue2953207() { // Set up data model. @@ -87,7 +87,7 @@ public function testBundleSpecificTargetEntityTypeFromIssue2953207() { /** * Ensure deep nested include works on multi target entity type field. * - * @see https://www.drupal.org/project/jsonapi/issues/2973681 + * @see https://www.drupal.org/project/drupal/issues/2973681 */ public function testDeepNestedIncludeMultiTargetEntityTypeFieldFromIssue2973681() { // Set up data model. @@ -151,7 +151,7 @@ public function testDeepNestedIncludeMultiTargetEntityTypeFieldFromIssue2973681( /** * Ensure POST and PATCH works for bundle-less relationship routes. * - * @see https://www.drupal.org/project/jsonapi/issues/2976371 + * @see https://www.drupal.org/project/drupal/issues/2976371 */ public function testBundlelessRelationshipMutationFromIssue2973681() { $this->config('jsonapi.settings')->set('read_only', FALSE)->save(TRUE); @@ -202,7 +202,7 @@ public function testBundlelessRelationshipMutationFromIssue2973681() { /** * Ensures GETting terms works when multiple vocabularies exist. * - * @see https://www.drupal.org/project/jsonapi/issues/2977879 + * @see https://www.drupal.org/project/drupal/issues/2977879 */ public function testGetTermWhenMultipleVocabulariesExistFromIssue2977879() { // Set up data model. @@ -238,7 +238,7 @@ public function testGetTermWhenMultipleVocabulariesExistFromIssue2977879() { /** * Cannot PATCH an entity with dangling references in an ER field. * - * @see https://www.drupal.org/project/jsonapi/issues/2968972 + * @see https://www.drupal.org/project/drupal/issues/2968972 */ public function testDanglingReferencesInAnEntityReferenceFieldFromIssue2968972() { $this->config('jsonapi.settings')->set('read_only', FALSE)->save(TRUE); @@ -309,7 +309,7 @@ public function testDanglingReferencesInAnEntityReferenceFieldFromIssue2968972() /** * Ensures GETting node collection + hook_node_grants() implementations works. * - * @see https://www.drupal.org/project/jsonapi/issues/2984964 + * @see https://www.drupal.org/project/drupal/issues/2984964 */ public function testGetNodeCollectionWithHookNodeGrantsImplementationsFromIssue2984964() { // Set up data model. @@ -340,7 +340,7 @@ public function testGetNodeCollectionWithHookNodeGrantsImplementationsFromIssue2 /** * Cannot GET an entity with dangling references in an ER field. * - * @see https://www.drupal.org/project/jsonapi/issues/2984647 + * @see https://www.drupal.org/project/drupal/issues/2984647 */ public function testDanglingReferencesInAnEntityReferenceFieldFromIssue2984647() { // Set up data model. @@ -470,7 +470,7 @@ public function testDanglingReferencesInAnEntityReferenceFieldFromIssue2984647() * Adding a new relationship field should cause new routes to be immediately * regenerated. The site builder should not need to manually rebuild caches. * - * @see https://www.drupal.org/project/jsonapi/issues/2984886 + * @see https://www.drupal.org/project/drupal/issues/2984886 */ public function testThatRoutesAreRebuiltAfterDataModelChangesFromIssue2984886() { $user = $this->drupalCreateUser(['access content']); @@ -526,7 +526,7 @@ public function testThatRoutesAreRebuiltAfterDataModelChangesFromIssue2984886() /** * Ensures denormalizing relationships with aliased field names works. * - * @see https://www.drupal.org/project/jsonapi/issues/3007113 + * @see https://www.drupal.org/project/drupal/issues/3007113 * @see https://www.drupal.org/project/jsonapi_extras/issues/3004582#comment-12817261 */ public function testDenormalizeAliasedRelationshipFromIssue2953207() { @@ -584,7 +584,7 @@ public function testDenormalizeAliasedRelationshipFromIssue2953207() { /** * Ensures that Drupal's page cache is effective. * - * @see https://www.drupal.org/project/jsonapi/issues/3009596 + * @see https://www.drupal.org/project/drupal/issues/3009596 */ public function testPageCacheFromIssue3009596() { $anonymous_role = Role::load(RoleInterface::ANONYMOUS_ID); @@ -619,7 +619,7 @@ public function testPageCacheFromIssue3009596() { /** * Ensures that filtering by a sequential internal ID named 'id' is possible. * - * @see https://www.drupal.org/project/jsonapi/issues/3015759 + * @see https://www.drupal.org/project/drupal/issues/3015759 */ public function testFilterByIdFromIssue3015759() { // Set up data model. @@ -659,7 +659,7 @@ public function testFilterByIdFromIssue3015759() { /** * Ensures datetime fields are normalized using the correct timezone. * - * @see https://www.drupal.org/project/jsonapi/issues/2999438 + * @see https://www.drupal.org/project/drupal/issues/2999438 */ public function testPatchingDateTimeNormalizedWrongTimeZoneIssue3021194() { // Set up data model. @@ -708,7 +708,7 @@ public function testPatchingDateTimeNormalizedWrongTimeZoneIssue3021194() { /** * Ensures PATCHing datetime (both date-only & date+time) fields is possible. * - * @see https://www.drupal.org/project/jsonapi/issues/3021194 + * @see https://www.drupal.org/project/drupal/issues/3021194 */ public function testPatchingDateTimeFieldsFromIssue3021194() { $this->config('jsonapi.settings')->set('read_only', FALSE)->save(TRUE); @@ -791,7 +791,7 @@ public function testPatchingDateTimeFieldsFromIssue3021194() { /** * Ensure includes are respected even when POSTing. * - * @see https://www.drupal.org/project/jsonapi/issues/3026030 + * @see https://www.drupal.org/project/drupal/issues/3026030 */ public function testPostToIncludeUrlDoesNotReturnIncludeFromIssue3026030() { $this->config('jsonapi.settings')->set('read_only', FALSE)->save(TRUE); @@ -828,7 +828,7 @@ public function testPostToIncludeUrlDoesNotReturnIncludeFromIssue3026030() { /** * Ensure includes are respected even when PATCHing. * - * @see https://www.drupal.org/project/jsonapi/issues/3026030 + * @see https://www.drupal.org/project/drupal/issues/3026030 */ public function testPatchToIncludeUrlDoesNotReturnIncludeFromIssue3026030() { $this->config('jsonapi.settings')->set('read_only', FALSE)->save(TRUE); @@ -874,7 +874,7 @@ public function testPatchToIncludeUrlDoesNotReturnIncludeFromIssue3026030() { /** * Ensure `@FieldType=map` fields are normalized correctly. * - * @see https://www.drupal.org/project/jsonapi/issues/3040590 + * @see https://www.drupal.org/project/drupal/issues/3040590 */ public function testMapFieldTypeNormalizationFromIssue3040590() { $this->assertTrue($this->container->get('module_installer')->install(['entity_test'], TRUE), 'Installed modules.'); @@ -918,6 +918,62 @@ public function testMapFieldTypeNormalizationFromIssue3040590() { $this->assertSame(['foo' => 'bar'], $data['data'][0]['attributes']['data']); } + /** + * Ensure filtering for entities with empty entity reference fields works. + * + * @see https://www.drupal.org/project/drupal/issues/3025372 + */ + public function testEmptyRelationshipFilteringFromIssue3025372() { + // Set up data model. + $this->drupalCreateContentType(['type' => 'folder']); + $this->createEntityReferenceField( + 'node', + 'folder', + 'field_parent_folder', + NULL, + 'node', + 'default', + [ + 'target_bundles' => ['folder'], + ], + FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED + ); + $this->rebuildAll(); + + // Create data. + $node = Node::create([ + 'title' => 'root folder', + 'type' => 'folder', + ]); + $node->save(); + + // Test. + $user = $this->drupalCreateUser(['access content']); + $url = Url::fromRoute('jsonapi.node--folder.collection'); + $request_options = [ + RequestOptions::HEADERS => [ + 'Content-Type' => 'application/vnd.api+json', + 'Accept' => 'application/vnd.api+json', + ], + RequestOptions::AUTH => [$user->getAccountName(), $user->pass_raw], + ]; + $response = $this->request('GET', $url, $request_options); + $this->assertSame(200, $response->getStatusCode(), (string) $response->getBody()); + $this->assertSame($node->uuid(), Json::decode((string) $response->getBody())['data'][0]['id']); + $response = $this->request('GET', $url->setOption('query', [ + 'filter[test][condition][path]' => 'field_parent_folder', + 'filter[test][condition][operator]' => 'IS NULL', + ]), $request_options); + $this->assertSame(200, $response->getStatusCode(), (string) $response->getBody()); + $this->assertSame($node->uuid(), Json::decode((string) $response->getBody())['data'][0]['id']); + $response = $this->request('GET', $url->setOption('query', [ + 'filter[test][condition][path]' => 'field_parent_folder', + 'filter[test][condition][operator]' => 'IS NOT NULL', + ]), $request_options); + $this->assertSame(200, $response->getStatusCode(), (string) $response->getBody()); + $this->assertEmpty(Json::decode((string) $response->getBody())['data']); + } + /** * Tests that the response still has meaningful error messages. */ @@ -1198,8 +1254,8 @@ public function testLeakCacheMetadataInOmitted() { /** * Tests that "virtual/missing" resources can exist for renamed fields. * - * @see https://www.drupal.org/project/jsonapi/issues/3034786 - * @see https://www.drupal.org/project/jsonapi_extras/issues/3035544 + * @see https://www.drupal.org/project/drupal/issues/3034786 + * @see https://www.drupal.org/project/drupal/issues/3035544 */ public function testAliasedFieldsWithVirtualRelationships() { // Set up the data model. diff --git a/web/core/modules/jsonapi/tests/src/Functional/MediaTest.php b/web/core/modules/jsonapi/tests/src/Functional/MediaTest.php index f604ca6092..62ac530711 100644 --- a/web/core/modules/jsonapi/tests/src/Functional/MediaTest.php +++ b/web/core/modules/jsonapi/tests/src/Functional/MediaTest.php @@ -348,7 +348,7 @@ protected function getExpectedUnauthorizedAccessCacheability() { */ public function testPostIndividual() { // @todo Mimic \Drupal\Tests\rest\Functional\EntityResource\Media\MediaResourceTestBase::testPost() - // @todo Later, use https://www.drupal.org/project/jsonapi/issues/2958554 to upload files rather than the REST module. + // @todo Later, use https://www.drupal.org/project/drupal/issues/2958554 to upload files rather than the REST module. parent::testPostIndividual(); } // @codingStandardsIgnoreEnd diff --git a/web/core/modules/jsonapi/tests/src/Functional/MenuLinkContentTest.php b/web/core/modules/jsonapi/tests/src/Functional/MenuLinkContentTest.php index fdb07f71dd..cf3ce8de31 100644 --- a/web/core/modules/jsonapi/tests/src/Functional/MenuLinkContentTest.php +++ b/web/core/modules/jsonapi/tests/src/Functional/MenuLinkContentTest.php @@ -176,7 +176,7 @@ protected function getExpectedUnauthorizedAccessMessage($method) { * {@inheritdoc} */ public function testRelated() { - $this->markTestSkipped('Remove this in https://www.drupal.org/project/jsonapi/issues/2940339'); + $this->markTestSkipped('Remove this in https://www.drupal.org/project/drupal/issues/2940339'); } /** diff --git a/web/core/modules/jsonapi/tests/src/Functional/NodeTest.php b/web/core/modules/jsonapi/tests/src/Functional/NodeTest.php index 266e220023..76c198a0ad 100644 --- a/web/core/modules/jsonapi/tests/src/Functional/NodeTest.php +++ b/web/core/modules/jsonapi/tests/src/Functional/NodeTest.php @@ -271,7 +271,7 @@ public function testPatchPath() { $this->setUpAuthorization('PATCH'); $this->config('jsonapi.settings')->set('read_only', FALSE)->save(TRUE); - // @todo Remove line below in favor of commented line in https://www.drupal.org/project/jsonapi/issues/2878463. + // @todo Remove line below in favor of commented line in https://www.drupal.org/project/drupal/issues/2878463. $url = Url::fromRoute(sprintf('jsonapi.%s.individual', static::$resourceTypeName), ['entity' => $this->entity->uuid()]); // $url = $this->entity->toUrl('jsonapi'); @@ -311,14 +311,14 @@ public function testGetIndividual() { // Unpublish node. $this->entity->setUnpublished()->save(); - // @todo Remove line below in favor of commented line in https://www.drupal.org/project/jsonapi/issues/2878463. + // @todo Remove line below in favor of commented line in https://www.drupal.org/project/drupal/issues/2878463. $url = Url::fromRoute(sprintf('jsonapi.%s.individual', static::$resourceTypeName), ['entity' => $this->entity->uuid()]); // $url = $this->entity->toUrl('jsonapi'); $request_options = $this->getAuthenticationRequestOptions(); // 403 when accessing own unpublished node. $response = $this->request('GET', $url, $request_options); - // @todo Remove $expected + assertResourceResponse() in favor of the commented line below once https://www.drupal.org/project/jsonapi/issues/2943176 lands. + // @todo Remove $expected + assertResourceResponse() in favor of the commented line below once https://www.drupal.org/project/drupal/issues/2943176 lands. $expected_document = [ 'jsonapi' => static::$jsonApiMember, 'errors' => [ @@ -374,7 +374,7 @@ protected function assertCacheableNormalizations() { ]); // After saving the entity the normalization should not be cached. $this->assertFalse($cache); - // @todo Remove line below in favor of commented line in https://www.drupal.org/project/jsonapi/issues/2878463. + // @todo Remove line below in favor of commented line in https://www.drupal.org/project/drupal/issues/2878463. $url = Url::fromRoute(sprintf('jsonapi.%s.individual', static::$resourceTypeName), ['entity' => $uuid]); // $url = $this->entity->toUrl('jsonapi'); $request_options = $this->getAuthenticationRequestOptions(); diff --git a/web/core/modules/jsonapi/tests/src/Functional/ResourceTestBase.php b/web/core/modules/jsonapi/tests/src/Functional/ResourceTestBase.php index c38211d813..1a01ff22a1 100644 --- a/web/core/modules/jsonapi/tests/src/Functional/ResourceTestBase.php +++ b/web/core/modules/jsonapi/tests/src/Functional/ResourceTestBase.php @@ -906,7 +906,7 @@ public function testGetIndividual() { // - to first test all mistakes a developer might make, and assert that the // error responses provide a good DX // - to eventually result in a well-formed request that succeeds. - // @todo Remove line below in favor of commented line in https://www.drupal.org/project/jsonapi/issues/2878463. + // @todo Remove line below in favor of commented line in https://www.drupal.org/project/drupal/issues/2878463. $url = Url::fromRoute(sprintf('jsonapi.%s.individual', static::$resourceTypeName), ['entity' => $this->entity->uuid()]); // $url = $this->entity->toUrl('jsonapi'); $request_options = []; @@ -975,9 +975,10 @@ public function testGetIndividual() { // contain a flattened response. Otherwise performance suffers. // @see \Drupal\jsonapi\EventSubscriber\ResourceResponseSubscriber::flattenResponse() $cache_items = $this->container->get('database') - ->query("SELECT cid, data FROM {cache_dynamic_page_cache} WHERE cid LIKE :pattern", [ - ':pattern' => '%[route]=jsonapi.%', - ]) + ->select('cache_dynamic_page_cache', 'cdp') + ->fields('cdp', ['cid', 'data']) + ->condition('cid', '%[route]=jsonapi.%', 'LIKE') + ->execute() ->fetchAllAssoc('cid'); $this->assertTrue(count($cache_items) >= 2); $found_cache_redirect = FALSE; @@ -1985,7 +1986,7 @@ public function testPostIndividual() { if (get_class($this->entityStorage) !== ContentEntityNullStorage::class) { $created_entity = $this->entityLoadUnchanged(static::$firstCreatedEntityId); $uuid = $created_entity->uuid(); - // @todo Remove line below in favor of commented line in https://www.drupal.org/project/jsonapi/issues/2878463. + // @todo Remove line below in favor of commented line in https://www.drupal.org/project/drupal/issues/2878463. $location = Url::fromRoute(sprintf('jsonapi.%s.individual', static::$resourceTypeName), ['entity' => $uuid]); if (static::$resourceTypeIsVersionable) { assert($created_entity instanceof RevisionableInterface); @@ -2037,7 +2038,7 @@ public function testPostIndividual() { if ($this->entity->getEntityType()->getStorageClass() !== ContentEntityNullStorage::class && $this->entity->getEntityType()->hasKey('uuid')) { $second_created_entity = $this->entityStorage->load(static::$secondCreatedEntityId); $uuid = $second_created_entity->uuid(); - // @todo Remove line below in favor of commented line in https://www.drupal.org/project/jsonapi/issues/2878463. + // @todo Remove line below in favor of commented line in https://www.drupal.org/project/drupal/issues/2878463. $location = Url::fromRoute(sprintf('jsonapi.%s.individual', static::$resourceTypeName), ['entity' => $uuid]); /* $location = $this->entityStorage->load(static::$secondCreatedEntityId)->toUrl('jsonapi')->setAbsolute(TRUE)->toString(); */ if (static::$resourceTypeIsVersionable) { @@ -2117,7 +2118,7 @@ public function testPatchIndividual() { // - to first test all mistakes a developer might make, and assert that the // error responses provide a good DX // - to eventually result in a well-formed request that succeeds. - // @todo Remove line below in favor of commented line in https://www.drupal.org/project/jsonapi/issues/2878463. + // @todo Remove line below in favor of commented line in https://www.drupal.org/project/drupal/issues/2878463. $url = Url::fromRoute(sprintf('jsonapi.%s.individual', static::$resourceTypeName), ['entity' => $this->entity->uuid()]); // $url = $this->entity->toUrl('jsonapi'); $request_options = []; @@ -2370,7 +2371,7 @@ public function testPatchIndividual() { $updated_entity->setNewRevision(); $updated_entity->save(); $actual_response = $this->request('PATCH', $url, $request_options); - $this->assertResourceErrorResponse(400, 'Updating a resource object that has a working copy is not yet supported. See https://www.drupal.org/project/jsonapi/issues/2795279.', $url, $actual_response); + $this->assertResourceErrorResponse(400, 'Updating a resource object that has a working copy is not yet supported. See https://www.drupal.org/project/drupal/issues/2795279.', $url, $actual_response); // Allow PATCHing an unpublished default revision. $updated_entity->set('moderation_state', 'archived'); @@ -2411,7 +2412,7 @@ public function testDeleteIndividual() { // - to first test all mistakes a developer might make, and assert that the // error responses provide a good DX // - to eventually result in a well-formed request that succeeds. - // @todo Remove line below in favor of commented line in https://www.drupal.org/project/jsonapi/issues/2878463. + // @todo Remove line below in favor of commented line in https://www.drupal.org/project/drupal/issues/2878463. $url = Url::fromRoute(sprintf('jsonapi.%s.individual', static::$resourceTypeName), ['entity' => $this->entity->uuid()]); // $url = $this->entity->toUrl('jsonapi'); $request_options = []; @@ -2694,7 +2695,7 @@ public function testRevisions() { $request_options = NestedArray::mergeDeep($request_options, $this->getAuthenticationRequestOptions()); $response = $this->request('GET', $url, $request_options); $detail = 'JSON:API does not yet support resource versioning for this resource type.'; - $detail .= ' For context, see https://www.drupal.org/project/jsonapi/issues/2992833#comment-12818258.'; + $detail .= ' For context, see https://www.drupal.org/project/drupal/issues/2992833#comment-12818258.'; $detail .= ' To contribute, see https://www.drupal.org/project/drupal/issues/2350939 and https://www.drupal.org/project/drupal/issues/2809177.'; $expected_cache_contexts = [ 'url.path', @@ -2731,7 +2732,7 @@ public function testRevisions() { $entity->save(); $latest_revision_id = (int) $entity->getRevisionId(); - // @todo Remove line below in favor of commented line in https://www.drupal.org/project/jsonapi/issues/2878463. + // @todo Remove line below in favor of commented line in https://www.drupal.org/project/drupal/issues/2878463. $url = Url::fromRoute(sprintf('jsonapi.%s.individual', static::$resourceTypeName), ['entity' => $this->entity->uuid()])->setAbsolute(); // $url = $this->entity->toUrl('jsonapi'); $collection_url = Url::fromRoute(sprintf('jsonapi.%s.collection', static::$resourceTypeName))->setAbsolute(); diff --git a/web/core/modules/jsonapi/tests/src/Functional/TermTest.php b/web/core/modules/jsonapi/tests/src/Functional/TermTest.php index f5f20aeec2..94805ec51c 100644 --- a/web/core/modules/jsonapi/tests/src/Functional/TermTest.php +++ b/web/core/modules/jsonapi/tests/src/Functional/TermTest.php @@ -372,7 +372,7 @@ public function testPatchPath() { $this->setUpAuthorization('PATCH'); $this->config('jsonapi.settings')->set('read_only', FALSE)->save(TRUE); - // @todo Remove line below in favor of commented line in https://www.drupal.org/project/jsonapi/issues/2878463. + // @todo Remove line below in favor of commented line in https://www.drupal.org/project/drupal/issues/2878463. $url = Url::fromRoute(sprintf('jsonapi.%s.individual', static::$resourceTypeName), ['entity' => $this->entity->uuid()]); // $url = $this->entity->toUrl('jsonapi'); $request_options = []; @@ -438,7 +438,7 @@ public function testGetIndividualTermWithParent(array $parent_term_ids) { // Modify the entity under test to use the provided parent terms. $this->entity->set('parent', $parent_term_ids)->save(); - // @todo Remove line below in favor of commented line in https://www.drupal.org/project/jsonapi/issues/2878463. + // @todo Remove line below in favor of commented line in https://www.drupal.org/project/drupal/issues/2878463. $url = Url::fromRoute(sprintf('jsonapi.%s.individual', static::$resourceTypeName), ['entity' => $this->entity->uuid()]); // $url = $this->entity->toUrl('jsonapi'); $request_options = []; @@ -473,7 +473,7 @@ public function providerTestGetIndividualTermWithParent() { * {@inheritdoc} */ public function testRelated() { - $this->markTestSkipped('Remove this in https://www.drupal.org/project/jsonapi/issues/2940339'); + $this->markTestSkipped('Remove this in https://www.drupal.org/project/drupal/issues/2940339'); } /** diff --git a/web/core/modules/jsonapi/tests/src/Functional/Update/ReadOnlyModeUpdateTest.php b/web/core/modules/jsonapi/tests/src/Functional/Update/ReadOnlyModeUpdateTest.php index dabc0df37e..c48dd28d4b 100644 --- a/web/core/modules/jsonapi/tests/src/Functional/Update/ReadOnlyModeUpdateTest.php +++ b/web/core/modules/jsonapi/tests/src/Functional/Update/ReadOnlyModeUpdateTest.php @@ -8,7 +8,7 @@ * Tests that existing sites have the new read-only mode to "off". * * @see jsonapi_update_8701() - * @see https://www.drupal.org/project/jsonapi/issues/3039568 + * @see https://www.drupal.org/project/drupal/issues/3039568 * * @group jsonapi * @group Update diff --git a/web/core/modules/jsonapi/tests/src/Functional/UserTest.php b/web/core/modules/jsonapi/tests/src/Functional/UserTest.php index f4ce93f2aa..98a1815588 100644 --- a/web/core/modules/jsonapi/tests/src/Functional/UserTest.php +++ b/web/core/modules/jsonapi/tests/src/Functional/UserTest.php @@ -203,7 +203,7 @@ protected function getExpectedUnauthorizedAccessMessage($method) { * Tests PATCHing security-sensitive base fields of the logged in account. */ public function testPatchDxForSecuritySensitiveBaseFields() { - // @todo Remove line below in favor of commented line in https://www.drupal.org/project/jsonapi/issues/2878463. + // @todo Remove line below in favor of commented line in https://www.drupal.org/project/drupal/issues/2878463. $url = Url::fromRoute(sprintf('jsonapi.user--user.individual'), ['entity' => $this->account->uuid()]); /* $url = $this->account->toUrl('jsonapi'); */ @@ -321,7 +321,7 @@ protected function assertRpcLogin($username, $password) { * Tests PATCHing security-sensitive base fields to change other users. */ public function testPatchSecurityOtherUser() { - // @todo Remove line below in favor of commented line in https://www.drupal.org/project/jsonapi/issues/2878463. + // @todo Remove line below in favor of commented line in https://www.drupal.org/project/drupal/issues/2878463. $url = Url::fromRoute(sprintf('jsonapi.user--user.individual'), ['entity' => $this->account->uuid()]); /* $url = $this->account->toUrl('jsonapi'); */ @@ -379,7 +379,7 @@ public function testGetMailFieldOnlyVisibleToOwner() { $this->grantPermissionsToTestedRole(['access user profiles']); $collection_url = Url::fromRoute('jsonapi.user--user.collection', [], ['query' => ['sort' => 'drupal_internal__uid']]); - // @todo Remove line below in favor of commented line in https://www.drupal.org/project/jsonapi/issues/2878463. + // @todo Remove line below in favor of commented line in https://www.drupal.org/project/drupal/issues/2878463. $user_a_url = Url::fromRoute(sprintf('jsonapi.user--user.individual'), ['entity' => $user_a->uuid()]); /* $user_a_url = $user_a->toUrl('jsonapi'); */ $request_options = []; diff --git a/web/core/modules/jsonapi/tests/src/Kernel/Normalizer/JsonApiDocumentTopLevelNormalizerTest.php b/web/core/modules/jsonapi/tests/src/Kernel/Normalizer/JsonApiDocumentTopLevelNormalizerTest.php index 0d2f093f01..6c97b71683 100644 --- a/web/core/modules/jsonapi/tests/src/Kernel/Normalizer/JsonApiDocumentTopLevelNormalizerTest.php +++ b/web/core/modules/jsonapi/tests/src/Kernel/Normalizer/JsonApiDocumentTopLevelNormalizerTest.php @@ -302,7 +302,7 @@ public function testNormalize() { * @covers ::normalize */ public function testNormalizeRelated() { - $this->markTestIncomplete('This fails and should be fixed by https://www.drupal.org/project/jsonapi/issues/2922121'); + $this->markTestIncomplete('This fails and should be fixed by https://www.drupal.org/project/drupal/issues/2922121'); list($request, $resource_type) = $this->generateProphecies('node', 'article', 'uid'); $request->query = new ParameterBag([ diff --git a/web/core/modules/jsonapi/tests/src/Kernel/Query/FilterTest.php b/web/core/modules/jsonapi/tests/src/Kernel/Query/FilterTest.php index f8ecc22355..afe8ee6a69 100644 --- a/web/core/modules/jsonapi/tests/src/Kernel/Query/FilterTest.php +++ b/web/core/modules/jsonapi/tests/src/Kernel/Query/FilterTest.php @@ -413,7 +413,7 @@ public function testCreateFromQueryParameterNested() { */ protected function getFieldResolverMock(ResourceType $resource_type) { $field_resolver = $this->prophesize(FieldResolver::class); - $field_resolver->resolveInternalEntityQueryPath($resource_type, Argument::any())->willReturnArgument(1); + $field_resolver->resolveInternalEntityQueryPath($resource_type, Argument::any(), Argument::any())->willReturnArgument(1); return $field_resolver->reveal(); } diff --git a/web/core/modules/locale/tests/src/Functional/LocaleImportFunctionalTest.php b/web/core/modules/locale/tests/src/Functional/LocaleImportFunctionalTest.php index 526db97c0a..5575cad6d5 100644 --- a/web/core/modules/locale/tests/src/Functional/LocaleImportFunctionalTest.php +++ b/web/core/modules/locale/tests/src/Functional/LocaleImportFunctionalTest.php @@ -202,7 +202,11 @@ public function testStandalonePoFile() { // The database should now contain 6 customized strings (two imported // strings are not translated). - $count = Database::getConnection()->query('SELECT COUNT(*) FROM {locales_target} WHERE customized = :custom', [':custom' => 1])->fetchField(); + $count = Database::getConnection()->select('locales_target') + ->condition('customized', 1) + ->countQuery() + ->execute() + ->fetchField(); $this->assertEqual($count, 6, 'Customized translations successfully imported.'); // Try importing a .po file with overriding strings, and ensure existing diff --git a/web/core/modules/locale/tests/src/Functional/LocalePluralFormatTest.php b/web/core/modules/locale/tests/src/Functional/LocalePluralFormatTest.php index 552273cfa7..54b442b8ec 100644 --- a/web/core/modules/locale/tests/src/Functional/LocalePluralFormatTest.php +++ b/web/core/modules/locale/tests/src/Functional/LocalePluralFormatTest.php @@ -197,7 +197,12 @@ public function testPluralEditDateFormatter() { // not save our source string for performance optimization if we do not ask // specifically for a language. \Drupal::translation()->formatPlural(1, '1 second', '@count seconds', [], ['langcode' => 'fr'])->render(); - $lid = Database::getConnection()->query("SELECT lid FROM {locales_source} WHERE source = :source AND context = ''", [':source' => "1 second" . PoItem::DELIMITER . "@count seconds"])->fetchField(); + $lid = Database::getConnection()->select('locales_source', 'ls') + ->fields('ls', ['lid']) + ->condition('source', "1 second" . PoItem::DELIMITER . "@count seconds") + ->condition('context', '') + ->execute() + ->fetchField(); // Look up editing page for this plural string and check fields. $search = [ 'string' => '1 second', @@ -282,7 +287,12 @@ public function testPluralEditExport() { $connection = Database::getConnection(); // Edit langcode hr translations and see if that took effect. - $lid = $connection->query("SELECT lid FROM {locales_source} WHERE source = :source AND context = ''", [':source' => "1 hour" . PoItem::DELIMITER . "@count hours"])->fetchField(); + $lid = $connection->select('locales_source', 'ls') + ->fields('ls', ['lid']) + ->condition('source', "1 hour" . PoItem::DELIMITER . "@count hours") + ->condition('context', '') + ->execute() + ->fetchField(); $edit = [ "strings[$lid][translations][1]" => '@count sata edited', ]; @@ -308,7 +318,12 @@ public function testPluralEditExport() { // not save our source string for performance optimization if we do not ask // specifically for a language. \Drupal::translation()->formatPlural(1, '1 day', '@count days', [], ['langcode' => 'fr'])->render(); - $lid = $connection->query("SELECT lid FROM {locales_source} WHERE source = :source AND context = ''", [':source' => "1 day" . PoItem::DELIMITER . "@count days"])->fetchField(); + $lid = $connection->select('locales_source', 'ls') + ->fields('ls', ['lid']) + ->condition('source', "1 day" . PoItem::DELIMITER . "@count days") + ->condition('context', '') + ->execute() + ->fetchField(); // Look up editing page for this plural string and check fields. $search = [ 'string' => '1 day', diff --git a/web/core/modules/locale/tests/src/Functional/LocaleUpdateBase.php b/web/core/modules/locale/tests/src/Functional/LocaleUpdateBase.php index 2e2d82b633..5a42977975 100644 --- a/web/core/modules/locale/tests/src/Functional/LocaleUpdateBase.php +++ b/web/core/modules/locale/tests/src/Functional/LocaleUpdateBase.php @@ -301,7 +301,13 @@ protected function setCurrentTranslations() { * (optional) A message to display with the assertion. */ protected function assertTranslation($source, $translation, $langcode, $message = '') { - $db_translation = Database::getConnection()->query('SELECT translation FROM {locales_target} lt INNER JOIN {locales_source} ls ON ls.lid = lt.lid WHERE ls.source = :source AND lt.language = :langcode', [':source' => $source, ':langcode' => $langcode])->fetchField(); + $query = Database::getConnection()->select('locales_target', 'lt'); + $query->innerJoin('locales_source', 'ls', 'ls.lid = lt.lid'); + $db_translation = $query->fields('lt', ['translation']) + ->condition('ls.source', $source) + ->condition('lt.language', $langcode) + ->execute() + ->fetchField(); $db_translation = $db_translation == FALSE ? '' : $db_translation; $this->assertEqual($translation, $db_translation, $message ? $message : new FormattableMarkup('Correct translation of %source (%language)', ['%source' => $source, '%language' => $langcode])); } diff --git a/web/core/modules/locale/tests/src/Functional/LocaleUpdateTest.php b/web/core/modules/locale/tests/src/Functional/LocaleUpdateTest.php index d1b12c17f4..366667a6cc 100644 --- a/web/core/modules/locale/tests/src/Functional/LocaleUpdateTest.php +++ b/web/core/modules/locale/tests/src/Functional/LocaleUpdateTest.php @@ -359,14 +359,22 @@ public function testEnableLanguage() { // Check if the language data is added to the database. $connection = Database::getConnection(); - $result = $connection->query("SELECT project FROM {locale_file} WHERE langcode='nl'")->fetchField(); + $result = $connection->select('locale_file', 'lf') + ->fields('lf', ['project']) + ->condition('langcode', 'nl') + ->execute() + ->fetchField(); $this->assertNotEmpty($result, 'Files added to file history'); // Remove a language. $this->drupalPostForm('admin/config/regional/language/delete/nl', [], t('Delete')); // Check if the language data is removed from the database. - $result = $connection->query("SELECT project FROM {locale_file} WHERE langcode='nl'")->fetchField(); + $result = $connection->select('locale_file', 'lf') + ->fields('lf', ['project']) + ->condition('langcode', 'nl') + ->execute() + ->fetchField(); $this->assertFalse($result, 'Files removed from file history'); // Check that the Dutch translation is gone. diff --git a/web/core/modules/migrate_drupal/tests/fixtures/drupal6.php b/web/core/modules/migrate_drupal/tests/fixtures/drupal6.php index a6e4ab7610..28a47bfa2c 100644 --- a/web/core/modules/migrate_drupal/tests/fixtures/drupal6.php +++ b/web/core/modules/migrate_drupal/tests/fixtures/drupal6.php @@ -2274,6 +2274,20 @@ 'field_image_list' => '1', 'field_image_data' => 'a:2:{s:3:"alt";s:0:"";s:5:"title";s:0:"";}', )) +->values(array( + 'vid' => '5', + 'nid' => '1', + 'field_image_fid' => '2', + 'field_image_list' => '1', + 'field_image_data' => 'a:2:{s:3:"alt";s:0:"";s:5:"title";s:0:"";}', +)) +->values(array( + 'vid' => '2001', + 'nid' => '1', + 'field_image_fid' => '2', + 'field_image_list' => '1', + 'field_image_data' => 'a:2:{s:3:"alt";s:0:"";s:5:"title";s:0:"";}', +)) ->execute(); $connection->schema()->createTable('content_field_multivalue', array( 'fields' => array( @@ -2389,12 +2403,6 @@ 'field_test_value' => 'This is a shared text field', 'field_test_format' => '1', )) -->values(array( - 'vid' => '2', - 'nid' => '1', - 'field_test_value' => 'This is a shared text field', - 'field_test_format' => '1', -)) ->values(array( 'vid' => '3', 'nid' => '2', @@ -2403,9 +2411,9 @@ )) ->values(array( 'vid' => '5', - 'nid' => '2', - 'field_test_value' => NULL, - 'field_test_format' => NULL, + 'nid' => '1', + 'field_test_value' => 'This is a shared text field', + 'field_test_format' => '1', )) ->values(array( 'vid' => '12', @@ -2413,6 +2421,12 @@ 'field_test_value' => 'text for default value', 'field_test_format' => '1', )) +->values(array( + 'vid' => '2001', + 'nid' => '1', + 'field_test_value' => 'This is a shared text field', + 'field_test_format' => '1', +)) ->execute(); $connection->schema()->createTable('content_field_test_text_single_checkbox', array( 'fields' => array( @@ -2470,14 +2484,19 @@ )) ->values(array( 'vid' => '5', - 'nid' => '2', - 'field_test_text_single_checkbox_value' => NULL, + 'nid' => '1', + 'field_test_text_single_checkbox_value' => '0', )) ->values(array( 'vid' => '12', 'nid' => '9', 'field_test_text_single_checkbox_value' => '0', )) +->values(array( + 'vid' => '2001', + 'nid' => '1', + 'field_test_text_single_checkbox_value' => '0', +)) ->execute(); $connection->schema()->createTable('content_field_test_two', array( 'fields' => array( @@ -2534,10 +2553,10 @@ 'field_test_two_value' => '10', )) ->values(array( - 'vid' => '2', + 'vid' => '1', 'nid' => '1', - 'delta' => '0', - 'field_test_two_value' => NULL, + 'delta' => '1', + 'field_test_two_value' => '20', )) ->values(array( 'vid' => '3', @@ -2547,9 +2566,15 @@ )) ->values(array( 'vid' => '5', - 'nid' => '2', + 'nid' => '1', 'delta' => '0', - 'field_test_two_value' => NULL, + 'field_test_two_value' => '10', +)) +->values(array( + 'vid' => '5', + 'nid' => '1', + 'delta' => '1', + 'field_test_two_value' => '20', )) ->values(array( 'vid' => '12', @@ -2558,7 +2583,13 @@ 'field_test_two_value' => NULL, )) ->values(array( - 'vid' => '1', + 'vid' => '2001', + 'nid' => '1', + 'delta' => '0', + 'field_test_two_value' => '10', +)) +->values(array( + 'vid' => '2001', 'nid' => '1', 'delta' => '1', 'field_test_two_value' => '20', @@ -3939,38 +3970,6 @@ 'field_test_datetime_value2' => NULL, 'field_test_string_selectlist_value' => NULL, )) -->values(array( - 'nid' => '1', - 'vid' => '2', - 'uid' => '1', - 'field_test_three_value' => '42.42', - 'field_test_identical1_value' => '1', - 'field_test_identical2_value' => '1', - 'field_test_link_url' => 'https://www.drupal.org/project/drupal', - 'field_test_link_title' => 'Drupal project page', - 'field_test_link_attributes' => 's:32:"a:1:{s:6:"target";s:6:"_blank";}";', - 'field_test_date_value' => '2013-01-02T04:05:00', - 'field_test_datestamp_value' => '1391357160', - 'field_test_datetime_value' => '2015-03-04 06:07:00', - 'field_test_email_email' => 'PrincessRuwenne@example.com', - 'field_test_filefield_fid' => NULL, - 'field_test_filefield_list' => NULL, - 'field_test_filefield_data' => NULL, - 'field_test_four_value' => NULL, - 'field_test_integer_selectlist_value' => NULL, - 'field_test_float_single_checkbox_value' => NULL, - 'field_test_decimal_radio_buttons_value' => NULL, - 'field_test_phone_value' => NULL, - 'field_test_exclude_unset_value' => NULL, - 'field_test_exclude_unset_format' => NULL, - 'field_test_imagefield_fid' => NULL, - 'field_test_imagefield_list' => NULL, - 'field_test_imagefield_data' => NULL, - 'field_test_text_single_checkbox2_value' => NULL, - 'field_test_datestamp_value2' => NULL, - 'field_test_datetime_value2' => NULL, - 'field_test_string_selectlist_value' => NULL, -)) ->values(array( 'nid' => '2', 'vid' => '3', @@ -4004,33 +4003,33 @@ 'field_test_string_selectlist_value' => NULL, )) ->values(array( - 'nid' => '2', + 'nid' => '1', 'vid' => '5', 'uid' => '1', - 'field_test_three_value' => '23.20', + 'field_test_three_value' => '42.42', 'field_test_identical1_value' => '1', 'field_test_identical2_value' => '1', - 'field_test_link_url' => 'http://groups.drupal.org/', - 'field_test_link_title' => 'Drupal Groups', - 'field_test_link_attributes' => 's:6:"a:0:{}";', - 'field_test_date_value' => NULL, - 'field_test_datestamp_value' => NULL, - 'field_test_datetime_value' => NULL, - 'field_test_email_email' => NULL, - 'field_test_filefield_fid' => NULL, - 'field_test_filefield_list' => NULL, - 'field_test_filefield_data' => NULL, + 'field_test_link_url' => 'https://www.drupal.org/project/drupal', + 'field_test_link_title' => 'Drupal project page', + 'field_test_link_attributes' => 's:32:"a:1:{s:6:"target";s:6:"_blank";}";', + 'field_test_date_value' => '2013-01-02T04:05:00', + 'field_test_datestamp_value' => '1391357160', + 'field_test_datetime_value' => '2015-03-04 06:07:00', + 'field_test_email_email' => 'PrincessRuwenne@example.com', + 'field_test_filefield_fid' => '5', + 'field_test_filefield_list' => '1', + 'field_test_filefield_data' => 'a:1:{s:11:"description";s:4:"desc";}', 'field_test_four_value' => NULL, - 'field_test_integer_selectlist_value' => NULL, - 'field_test_float_single_checkbox_value' => NULL, + 'field_test_integer_selectlist_value' => '3412', + 'field_test_float_single_checkbox_value' => '3', 'field_test_decimal_radio_buttons_value' => NULL, 'field_test_phone_value' => NULL, - 'field_test_exclude_unset_value' => NULL, - 'field_test_exclude_unset_format' => NULL, + 'field_test_exclude_unset_value' => 'This is a field with exclude unset.', + 'field_test_exclude_unset_format' => '1', 'field_test_imagefield_fid' => NULL, 'field_test_imagefield_list' => NULL, 'field_test_imagefield_data' => NULL, - 'field_test_text_single_checkbox2_value' => NULL, + 'field_test_text_single_checkbox2_value' => 'Hello', 'field_test_datestamp_value2' => NULL, 'field_test_datetime_value2' => NULL, 'field_test_string_selectlist_value' => NULL, @@ -4067,6 +4066,38 @@ 'field_test_datetime_value2' => '2015-03-04 06:07:00', 'field_test_string_selectlist_value' => NULL, )) +->values(array( + 'nid' => '1', + 'vid' => '2001', + 'uid' => '1', + 'field_test_three_value' => '42.42', + 'field_test_identical1_value' => '1', + 'field_test_identical2_value' => '1', + 'field_test_link_url' => 'https://www.drupal.org/project/drupal', + 'field_test_link_title' => 'Drupal project page', + 'field_test_link_attributes' => 's:32:"a:1:{s:6:"target";s:6:"_blank";}";', + 'field_test_date_value' => '2013-01-02T04:05:00', + 'field_test_datestamp_value' => '1391357160', + 'field_test_datetime_value' => '2015-03-04 06:07:00', + 'field_test_email_email' => 'PrincessRuwenne@example.com', + 'field_test_filefield_fid' => '5', + 'field_test_filefield_list' => '1', + 'field_test_filefield_data' => 'a:1:{s:11:"description";s:4:"desc";}', + 'field_test_four_value' => NULL, + 'field_test_integer_selectlist_value' => '3412', + 'field_test_float_single_checkbox_value' => '3', + 'field_test_decimal_radio_buttons_value' => NULL, + 'field_test_phone_value' => NULL, + 'field_test_exclude_unset_value' => 'This is a field with exclude unset.', + 'field_test_exclude_unset_format' => '1', + 'field_test_imagefield_fid' => NULL, + 'field_test_imagefield_list' => NULL, + 'field_test_imagefield_data' => NULL, + 'field_test_text_single_checkbox2_value' => 'Hello', + 'field_test_datestamp_value2' => NULL, + 'field_test_datetime_value2' => NULL, + 'field_test_string_selectlist_value' => NULL, +)) ->execute(); $connection->schema()->createTable('content_type_test_page', array( 'fields' => array( @@ -44470,7 +44501,7 @@ )) ->values(array( 'nid' => '1', - 'vid' => '1', + 'vid' => '2001', 'type' => 'story', 'language' => '', 'title' => 'Test title rev 3', @@ -48083,6 +48114,16 @@ 'vid' => '3', 'tid' => '3', )) +->values(array( + 'nid' => '1', + 'vid' => '2001', + 'tid' => '1', +)) +->values(array( + 'nid' => '1', + 'vid' => '2001', + 'tid' => '2', +)) ->values(array( 'nid' => '1', 'vid' => '2001', @@ -48283,6 +48324,14 @@ 'list' => '0', 'weight' => '1', )) +->values(array( + 'fid' => '1', + 'nid' => '1', + 'vid' => '5', + 'description' => 'file 1-1-1', + 'list' => '0', + 'weight' => '-1', +)) ->values(array( 'fid' => '3', 'nid' => '12', @@ -48291,6 +48340,14 @@ 'list' => '0', 'weight' => '0', )) +->values(array( + 'fid' => '1', + 'nid' => '1', + 'vid' => '2001', + 'description' => 'file 1-1-1', + 'list' => '0', + 'weight' => '-1', +)) ->execute(); $connection->schema()->createTable('url_alias', array( 'fields' => array( diff --git a/web/core/modules/node/tests/src/Functional/NodeCreationTest.php b/web/core/modules/node/tests/src/Functional/NodeCreationTest.php index faef2af13b..161e8df6ef 100644 --- a/web/core/modules/node/tests/src/Functional/NodeCreationTest.php +++ b/web/core/modules/node/tests/src/Functional/NodeCreationTest.php @@ -294,7 +294,9 @@ protected static function getWatchdogIdsForTestExceptionRollback() { // PostgreSQL doesn't support bytea LIKE queries, so we need to unserialize // first to check for the rollback exception message. $matches = []; - $query = Database::getConnection()->query("SELECT wid, variables FROM {watchdog}"); + $query = Database::getConnection()->select('watchdog', 'w') + ->fields('w', ['wid', 'variables']) + ->execute(); foreach ($query as $row) { $variables = (array) unserialize($row->variables); if (isset($variables['@message']) && $variables['@message'] === 'Test exception for rollback.') { diff --git a/web/core/modules/node/tests/src/Kernel/Migrate/d6/MigrateNodeTest.php b/web/core/modules/node/tests/src/Kernel/Migrate/d6/MigrateNodeTest.php index 1e951d0e47..5f64bf6e90 100644 --- a/web/core/modules/node/tests/src/Kernel/Migrate/d6/MigrateNodeTest.php +++ b/web/core/modules/node/tests/src/Kernel/Migrate/d6/MigrateNodeTest.php @@ -52,24 +52,24 @@ public function testNode() { $node = Node::load(1); $this->assertIdentical('1', $node->id(), 'Node 1 loaded.'); $this->assertIdentical('und', $node->langcode->value); - $this->assertIdentical('test', $node->body->value); - $this->assertIdentical('test', $node->body->summary); + $this->assertIdentical('body test rev 3', $node->body->value); + $this->assertIdentical('teaser test rev 3', $node->body->summary); $this->assertIdentical('filtered_html', $node->body->format); $this->assertIdentical('story', $node->getType(), 'Node has the correct bundle.'); - $this->assertIdentical('Test title', $node->getTitle(), 'Node has the correct title.'); + $this->assertIdentical('Test title rev 3', $node->getTitle(), 'Node has the correct title.'); $this->assertIdentical('1390095702', $node->getCreatedTime(), 'Node has the correct created time.'); $this->assertIdentical(FALSE, $node->isSticky()); $this->assertIdentical('1', $node->getOwnerId()); - $this->assertIdentical('1390095702', $node->getRevisionCreationTime()); + $this->assertIdentical('1420861423', $node->getRevisionCreationTime()); /** @var \Drupal\node\NodeInterface $node_revision */ - $node_revision = \Drupal::entityTypeManager()->getStorage('node')->loadRevision(1); - $this->assertIdentical('Test title', $node_revision->getTitle()); - $this->assertIdentical('1', $node_revision->getRevisionUser()->id(), 'Node revision has the correct user'); + $node_revision = \Drupal::entityTypeManager()->getStorage('node')->loadRevision(2001); + $this->assertIdentical('Test title rev 3', $node_revision->getTitle()); + $this->assertIdentical('2', $node_revision->getRevisionUser()->id(), 'Node revision has the correct user'); $this->assertSame('1', $node_revision->id(), 'Node 1 loaded.'); - $this->assertSame('1', $node_revision->getRevisionId(), 'Node 1 revision 1 loaded.'); + $this->assertSame('2001', $node_revision->getRevisionId(), 'Node 1 revision 2001 loaded.'); // This is empty on the first revision. - $this->assertIdentical(NULL, $node_revision->revision_log->value); + $this->assertIdentical('modified rev 3', $node_revision->revision_log->value); $this->assertIdentical('This is a shared text field', $node->field_test->value); $this->assertIdentical('filtered_html', $node->field_test->format); $this->assertIdentical('10', $node->field_test_two->value); diff --git a/web/core/modules/node/tests/src/Kernel/NodeAccessRecordsTest.php b/web/core/modules/node/tests/src/Kernel/NodeAccessRecordsTest.php index a5a5d6ae53..bc36ae92ec 100644 --- a/web/core/modules/node/tests/src/Kernel/NodeAccessRecordsTest.php +++ b/web/core/modules/node/tests/src/Kernel/NodeAccessRecordsTest.php @@ -30,7 +30,11 @@ public function testNodeAccessRecords() { // Check to see if grants added by node_test_node_access_records made it in. $connection = Database::getConnection(); - $records = $connection->query('SELECT realm, gid FROM {node_access} WHERE nid = :nid', [':nid' => $node1->id()])->fetchAll(); + $records = $connection->select('node_access', 'na') + ->fields('na', ['realm', 'gid']) + ->condition('nid', $node1->id()) + ->execute() + ->fetchAll(); $this->assertCount(1, $records, 'Returned the correct number of rows.'); $this->assertEqual($records[0]->realm, 'test_article_realm', 'Grant with article_realm acquired for node without alteration.'); $this->assertEqual($records[0]->gid, 1, 'Grant with gid = 1 acquired for node without alteration.'); @@ -40,7 +44,11 @@ public function testNodeAccessRecords() { $this->assertNotEmpty(Node::load($node2->id()), 'Unpromoted basic page node created.'); // Check to see if grants added by node_test_node_access_records made it in. - $records = $connection->query('SELECT realm, gid FROM {node_access} WHERE nid = :nid', [':nid' => $node2->id()])->fetchAll(); + $records = $connection->select('node_access', 'na') + ->fields('na', ['realm', 'gid']) + ->condition('nid', $node2->id()) + ->execute() + ->fetchAll(); $this->assertCount(1, $records, 'Returned the correct number of rows.'); $this->assertEqual($records[0]->realm, 'test_page_realm', 'Grant with page_realm acquired for node without alteration.'); $this->assertEqual($records[0]->gid, 1, 'Grant with gid = 1 acquired for node without alteration.'); @@ -50,7 +58,11 @@ public function testNodeAccessRecords() { $this->assertNotEmpty(Node::load($node3->id()), 'Unpromoted, unpublished basic page node created.'); // Check to see if grants added by node_test_node_access_records made it in. - $records = $connection->query('SELECT realm, gid FROM {node_access} WHERE nid = :nid', [':nid' => $node3->id()])->fetchAll(); + $records = $connection->select('node_access', 'na') + ->fields('na', ['realm', 'gid']) + ->condition('nid', $node3->id()) + ->execute() + ->fetchAll(); $this->assertCount(1, $records, 'Returned the correct number of rows.'); $this->assertEqual($records[0]->realm, 'test_page_realm', 'Grant with page_realm acquired for node without alteration.'); $this->assertEqual($records[0]->gid, 1, 'Grant with gid = 1 acquired for node without alteration.'); @@ -61,7 +73,11 @@ public function testNodeAccessRecords() { // Check to see if grant added by node_test_node_access_records was altered // by node_test_node_access_records_alter. - $records = $connection->query('SELECT realm, gid FROM {node_access} WHERE nid = :nid', [':nid' => $node4->id()])->fetchAll(); + $records = $connection->select('node_access', 'na') + ->fields('na', ['realm', 'gid']) + ->condition('nid', $node4->id()) + ->execute() + ->fetchAll(); $this->assertCount(1, $records, 'Returned the correct number of rows.'); $this->assertEqual($records[0]->realm, 'test_alter_realm', 'Altered grant with alter_realm acquired for node.'); $this->assertEqual($records[0]->gid, 2, 'Altered grant with gid = 2 acquired for node.'); @@ -80,7 +96,11 @@ public function testNodeAccessRecords() { // Check that core does not grant access to an unpublished node when an // empty $grants array is returned. $node6 = $this->drupalCreateNode(['status' => 0, 'disable_node_access' => TRUE]); - $records = $connection->query('SELECT realm, gid FROM {node_access} WHERE nid = :nid', [':nid' => $node6->id()])->fetchAll(); + $records = $connection->select('node_access', 'na') + ->fields('na', ['realm', 'gid']) + ->condition('nid', $node6->id()) + ->execute() + ->fetchAll(); $this->assertCount(0, $records, 'Returned no records for unpublished node.'); } diff --git a/web/core/modules/rdf/rdf.module b/web/core/modules/rdf/rdf.module index 92cc337fc1..cbd696e05d 100644 --- a/web/core/modules/rdf/rdf.module +++ b/web/core/modules/rdf/rdf.module @@ -237,12 +237,13 @@ function rdf_comment_storage_load($comments) { ->getPreparedFieldMapping('created'); /** @var \Drupal\comment\CommentInterface $comment*/ $comment->rdf_data['date'] = rdf_rdfa_attributes($created_mapping, $comment->get('created')->first()->toArray()); - $entity = $comment->getCommentedEntity(); - // The current function is a storage level hook, so avoid to bubble - // bubbleable metadata, because it can be outside of a render context. - $comment->rdf_data['entity_uri'] = $entity->toUrl()->toString(TRUE)->getGeneratedUrl(); - if ($comment->hasParentComment()) { - $comment->rdf_data['pid_uri'] = $comment->getParentComment()->toUrl()->toString(TRUE)->getGeneratedUrl(); + if ($entity = $comment->getCommentedEntity()) { + // The current function is a storage level hook, so avoid to bubble + // bubbleable metadata, because it can be outside of a render context. + $comment->rdf_data['entity_uri'] = $entity->toUrl()->toString(TRUE)->getGeneratedUrl(); + } + if ($parent = $comment->getParentComment()) { + $comment->rdf_data['pid_uri'] = $parent->toUrl()->toString(TRUE)->getGeneratedUrl(); } } } diff --git a/web/core/modules/rdf/tests/src/Functional/CommentAttributesTest.php b/web/core/modules/rdf/tests/src/Functional/CommentAttributesTest.php index 129e348ae9..2cf2366628 100644 --- a/web/core/modules/rdf/tests/src/Functional/CommentAttributesTest.php +++ b/web/core/modules/rdf/tests/src/Functional/CommentAttributesTest.php @@ -7,6 +7,7 @@ use Drupal\comment\CommentManagerInterface; use Drupal\Tests\comment\Functional\CommentTestBase; use Drupal\Tests\rdf\Traits\RdfParsingTrait; +use Drupal\user\Entity\User; use Drupal\user\RoleInterface; use Drupal\comment\Entity\Comment; @@ -24,7 +25,7 @@ class CommentAttributesTest extends CommentTestBase { * * @var array */ - public static $modules = ['views', 'node', 'comment', 'rdf']; + public static $modules = ['views', 'node', 'comment', 'rdf', 'user_hooks_test']; /** * {@inheritdoc} @@ -148,6 +149,9 @@ public function testNumberOfCommentsRdfaMarkup() { * Tests comment author link markup has not been broken by RDF. */ public function testCommentRdfAuthorMarkup() { + // Set to test the altered display name. + \Drupal::state()->set('user_hooks_test_user_format_name_alter', TRUE); + // Post a comment as a registered user. $this->saveComment($this->node->id(), $this->webUser->id()); @@ -158,7 +162,7 @@ public function testCommentRdfAuthorMarkup() { // Ensure that the author link still works properly after the author output // is modified by the RDF module. $this->drupalGet('node/' . $this->node->id()); - $this->assertSession()->linkExists($this->webUser->getAccountName()); + $this->assertSession()->linkExistsExact($this->webUser->getDisplayName()); $this->assertLinkByHref('user/' . $this->webUser->id()); } @@ -169,6 +173,9 @@ public function testCommentRdfAuthorMarkup() { * on comments from registered and anonymous users. */ public function testCommentRdfaMarkup() { + // Set to test the altered display name. + \Drupal::state()->set('user_hooks_test_user_format_name_alter', TRUE); + // Posts comment #1 on behalf of registered user. $comment1 = $this->saveComment($this->node->id(), $this->webUser->id()); @@ -187,12 +194,13 @@ public function testCommentRdfaMarkup() { $anonymous_user['homepage'] = 'http://example.org/'; $comment2 = $this->saveComment($this->node->id(), 0, $anonymous_user); + $anonymous = User::load(0); // Tests comment #2 as anonymous user. - $this->_testBasicCommentRdfaMarkup($comment2, $anonymous_user); + $this->_testBasicCommentRdfaMarkup($comment2, $anonymous); // Tests comment #2 as logged in user. $this->drupalLogin($this->webUser); - $this->_testBasicCommentRdfaMarkup($comment2, $anonymous_user); + $this->_testBasicCommentRdfaMarkup($comment2, $anonymous); } /** @@ -240,7 +248,7 @@ public function testCommentReplyOfRdfaMarkup() { * @param $account * An array containing information about an anonymous user. */ - public function _testBasicCommentRdfaMarkup(CommentInterface $comment, $account = []) { + public function _testBasicCommentRdfaMarkup(CommentInterface $comment, $account = NULL) { $this->drupalGet($this->node->toUrl()); $comment_uri = $comment->toUrl('canonical', ['absolute' => TRUE])->toString(); @@ -303,7 +311,7 @@ public function _testBasicCommentRdfaMarkup(CommentInterface $comment, $account } // Author name. - $name = empty($account["name"]) ? $this->webUser->getAccountName() : $account["name"] . " (not verified)"; + $name = $account ? $account->getDisplayName() . " (not verified)" : $this->webUser->getDisplayName(); $expected_value = [ 'type' => 'literal', 'value' => $name, diff --git a/web/core/modules/rdf/tests/src/Functional/UserAttributesTest.php b/web/core/modules/rdf/tests/src/Functional/UserAttributesTest.php index ee5102aecb..abece849eb 100644 --- a/web/core/modules/rdf/tests/src/Functional/UserAttributesTest.php +++ b/web/core/modules/rdf/tests/src/Functional/UserAttributesTest.php @@ -20,7 +20,7 @@ class UserAttributesTest extends BrowserTestBase { * * @var array */ - public static $modules = ['rdf', 'node']; + public static $modules = ['rdf', 'node', 'user_hooks_test']; /** * {@inheritdoc} @@ -47,6 +47,9 @@ protected function setUp() { // Prepares commonly used URIs. $this->baseUri = Url::fromRoute('<front>', [], ['absolute' => TRUE])->toString(); + + // Set to test the altered display name. + \Drupal::state()->set('user_hooks_test_user_format_name_alter', TRUE); } /** @@ -87,7 +90,7 @@ public function testUserAttributesInMarkup() { // User name. $expected_value = [ 'type' => 'literal', - 'value' => $author->getAccountName(), + 'value' => $author->getDisplayName(), ]; $this->assertTrue($this->hasRdfProperty($this->getSession()->getPage()->getContent(), $this->baseUri, $account_uri, 'http://xmlns.com/foaf/0.1/name', $expected_value), 'User name found in RDF output (foaf:name).'); @@ -108,7 +111,7 @@ public function testUserAttributesInMarkup() { // User name. $expected_value = [ 'type' => 'literal', - 'value' => $author->getAccountName(), + 'value' => $author->getDisplayName(), ]; $this->assertTrue($this->hasRdfProperty($this->getSession()->getPage()->getContent(), $this->baseUri, $account_uri, 'http://xmlns.com/foaf/0.1/name', $expected_value), 'User name found in RDF output (foaf:name).'); } diff --git a/web/core/modules/rdf/tests/src/Kernel/RdfCommentStorageLoadTest.php b/web/core/modules/rdf/tests/src/Kernel/RdfCommentStorageLoadTest.php new file mode 100644 index 0000000000..5ace1bcc64 --- /dev/null +++ b/web/core/modules/rdf/tests/src/Kernel/RdfCommentStorageLoadTest.php @@ -0,0 +1,46 @@ +<?php + +namespace Drupal\Tests\rdf\Kernel; + +use Drupal\Core\Field\FieldItemList; +use Drupal\Core\Field\Plugin\Field\FieldType\CreatedItem; +use Drupal\KernelTests\Core\Entity\EntityKernelTestBase; +use Drupal\comment\Entity\Comment; + +/** + * Tests rdf_comment_storage_load. + * + * @group rdf + */ +class RdfCommentStorageLoadTest extends EntityKernelTestBase { + + /** + * {@inheritdoc} + */ + public static $modules = ['comment', 'rdf']; + + /** + * Tests rdf_comment_storage_load. + */ + public function testRdfCommentStorageLoad() { + $field_created_item = $this->prophesize(CreatedItem::class); + $field_created_item->setValue([time()]); + + $field_list = $this->prophesize(FieldItemList::class); + $field_list->reveal(); + $field_list->first()->willReturn($field_created_item->reveal()); + + $comment = $this->prophesize(Comment::class); + $comment->bundle()->willReturn('page'); + $comment->get('created')->willReturn($field_list); + $comment->getFieldDefinitions()->willReturn(NULL); + // Set commented entity and parent entity to NULL. + $comment->getCommentedEntity()->willReturn(NULL); + $comment->getParentComment()->willReturn(NULL); + + /** @var \Drupal\Core\Extension\ModuleHandler $module_handler */ + $module_handler = \Drupal::service('module_handler'); + $module_handler->invoke('rdf', 'comment_storage_load', [[$comment->reveal()]]); + } + +} diff --git a/web/core/modules/search/tests/src/Functional/SearchNodeUpdateAndDeletionTest.php b/web/core/modules/search/tests/src/Functional/SearchNodeUpdateAndDeletionTest.php index 4e984037d3..77df01e279 100644 --- a/web/core/modules/search/tests/src/Functional/SearchNodeUpdateAndDeletionTest.php +++ b/web/core/modules/search/tests/src/Functional/SearchNodeUpdateAndDeletionTest.php @@ -100,7 +100,11 @@ public function testSearchIndexUpdateOnNodeDeletion() { // Get the node info from the search index tables. $connection = Database::getConnection(); - $search_index_dataset = $connection->query("SELECT sid FROM {search_index} WHERE type = 'node_search' AND word = :word", [':word' => 'dragons']) + $search_index_dataset = $connection->select('search_index', 'si') + ->fields('si', ['sid']) + ->condition('type', 'node_search') + ->condition('word', 'dragons') + ->execute() ->fetchField(); $this->assertNotEqual($search_index_dataset, FALSE, t('Node info found on the search_index')); @@ -108,7 +112,11 @@ public function testSearchIndexUpdateOnNodeDeletion() { $node->delete(); // Check if the node info is gone from the search table. - $search_index_dataset = $connection->query("SELECT sid FROM {search_index} WHERE type = 'node_search' AND word = :word", [':word' => 'dragons']) + $search_index_dataset = $connection->select('search_index', 'si') + ->fields('si', ['sid']) + ->condition('type', 'node_search') + ->condition('word', 'dragons') + ->execute() ->fetchField(); $this->assertFalse($search_index_dataset, t('Node info successfully removed from search_index')); diff --git a/web/core/modules/system/tests/modules/error_test/src/Controller/ErrorTestController.php b/web/core/modules/system/tests/modules/error_test/src/Controller/ErrorTestController.php index c64da6dc23..2960b2151e 100644 --- a/web/core/modules/system/tests/modules/error_test/src/Controller/ErrorTestController.php +++ b/web/core/modules/system/tests/modules/error_test/src/Controller/ErrorTestController.php @@ -76,7 +76,9 @@ public function triggerException() { */ public function triggerPDOException() { define('SIMPLETEST_COLLECT_ERRORS', FALSE); - $this->database->query('SELECT * FROM bananas_are_awesome'); + $this->database->select('bananas_are_awesome', 'b') + ->fields('b') + ->execute(); } /** diff --git a/web/core/modules/system/tests/src/Functional/Database/SelectPagerDefaultTest.php b/web/core/modules/system/tests/src/Functional/Database/SelectPagerDefaultTest.php index 2ba40a043a..4a37ecd4b6 100644 --- a/web/core/modules/system/tests/src/Functional/Database/SelectPagerDefaultTest.php +++ b/web/core/modules/system/tests/src/Functional/Database/SelectPagerDefaultTest.php @@ -30,7 +30,7 @@ public function testEvenPagerQuery() { // information forward to the actual query on the other side of the // HTTP request. $limit = 2; - $count = Database::getConnection()->query('SELECT COUNT(*) FROM {test}')->fetchField(); + $count = Database::getConnection()->select('test')->countQuery()->execute()->fetchField(); $correct_number = $limit; $num_pages = floor($count / $limit); @@ -64,7 +64,7 @@ public function testOddPagerQuery() { // information forward to the actual query on the other side of the // HTTP request. $limit = 2; - $count = Database::getConnection()->query('SELECT COUNT(*) FROM {test_task}')->fetchField(); + $count = Database::getConnection()->select('test_task')->countQuery()->execute()->fetchField(); $correct_number = $limit; $num_pages = floor($count / $limit); diff --git a/web/core/modules/system/tests/src/Functional/Form/StorageTest.php b/web/core/modules/system/tests/src/Functional/Form/StorageTest.php index d503ba6a38..02ce119834 100644 --- a/web/core/modules/system/tests/src/Functional/Form/StorageTest.php +++ b/web/core/modules/system/tests/src/Functional/Form/StorageTest.php @@ -189,7 +189,12 @@ public function testImmutableFormLegacyProtection() { // Assert that a watchdog message was logged by // \Drupal::formBuilder()->setCache(). - $status = (bool) Database::getConnection()->queryRange('SELECT 1 FROM {watchdog} WHERE message = :message', 0, 1, [':message' => 'Form build-id mismatch detected while attempting to store a form in the cache.']); + $status = (bool) Database::getConnection()->select('watchdog') + ->condition('message', 'Form build-id mismatch detected while attempting to store a form in the cache.') + ->range(0, 1) + ->countQuery() + ->execute() + ->fetchField(); $this->assertTrue($status, 'A watchdog message was logged by \Drupal::formBuilder()->setCache'); // Ensure that the form state was not poisoned by the preceding call. diff --git a/web/core/modules/system/tests/src/Functional/Module/InstallTest.php b/web/core/modules/system/tests/src/Functional/Module/InstallTest.php index 1fb619ff26..0041d3a4f5 100644 --- a/web/core/modules/system/tests/src/Functional/Module/InstallTest.php +++ b/web/core/modules/system/tests/src/Functional/Module/InstallTest.php @@ -31,7 +31,7 @@ class InstallTest extends BrowserTestBase { */ public function testGetSchemaAtInstallTime() { // @see module_test_install() - $value = Database::getConnection()->query("SELECT data FROM {module_test}")->fetchField(); + $value = Database::getConnection()->select('module_test', 'mt')->fields('mt', ['data'])->execute()->fetchField(); $this->assertIdentical($value, 'varchar'); } diff --git a/web/core/modules/system/tests/src/Functional/Session/SessionHttpsTest.php b/web/core/modules/system/tests/src/Functional/Session/SessionHttpsTest.php index 59dc9205de..49223e61ed 100644 --- a/web/core/modules/system/tests/src/Functional/Session/SessionHttpsTest.php +++ b/web/core/modules/system/tests/src/Functional/Session/SessionHttpsTest.php @@ -254,10 +254,7 @@ protected function getPathFromLocationHeader(ResponseInterface $response, $https * has the given insecure and secure session IDs. */ protected function assertSessionIds($sid, $assertion_text) { - $args = [ - ':sid' => Crypt::hashBase64($sid), - ]; - return $this->assertNotEmpty(\Drupal::database()->query('SELECT timestamp FROM {sessions} WHERE sid = :sid', $args)->fetchField(), $assertion_text); + return $this->assertNotEmpty(\Drupal::database()->select('sessions', 's')->fields('s', ['timestamp'])->condition('sid', Crypt::hashBase64($sid))->execute()->fetchField(), $assertion_text); } /** diff --git a/web/core/modules/system/tests/src/Functional/Session/SessionTest.php b/web/core/modules/system/tests/src/Functional/Session/SessionTest.php index aa34664bd1..ab8948d552 100644 --- a/web/core/modules/system/tests/src/Functional/Session/SessionTest.php +++ b/web/core/modules/system/tests/src/Functional/Session/SessionTest.php @@ -233,8 +233,12 @@ public function testSessionWrite() { $this->drupalLogin($user); $connection = Database::getConnection(); - $sql = 'SELECT u.access, s.timestamp FROM {users_field_data} u INNER JOIN {sessions} s ON u.uid = s.uid WHERE u.uid = :uid'; - $times1 = $connection->query($sql, [':uid' => $user->id()])->fetchObject(); + $query = $connection->select('users_field_data', 'u'); + $query->innerJoin('sessions', 's', 'u.uid = s.uid'); + $query->fields('u', ['access']) + ->fields('s', ['timestamp']) + ->condition('u.uid', $user->id()); + $times1 = $query->execute()->fetchObject(); // Before every request we sleep one second to make sure that if the session // is saved, its timestamp will change. @@ -242,21 +246,21 @@ public function testSessionWrite() { // Modify the session. sleep(1); $this->drupalGet('session-test/set/foo'); - $times2 = $connection->query($sql, [':uid' => $user->id()])->fetchObject(); + $times2 = $query->execute()->fetchObject(); $this->assertEqual($times2->access, $times1->access, 'Users table was not updated.'); $this->assertNotEqual($times2->timestamp, $times1->timestamp, 'Sessions table was updated.'); // Write the same value again, i.e. do not modify the session. sleep(1); $this->drupalGet('session-test/set/foo'); - $times3 = $connection->query($sql, [':uid' => $user->id()])->fetchObject(); + $times3 = $query->execute()->fetchObject(); $this->assertEqual($times3->access, $times1->access, 'Users table was not updated.'); $this->assertEqual($times3->timestamp, $times2->timestamp, 'Sessions table was not updated.'); // Do not change the session. sleep(1); $this->drupalGet(''); - $times4 = $connection->query($sql, [':uid' => $user->id()])->fetchObject(); + $times4 = $query->execute()->fetchObject(); $this->assertEqual($times4->access, $times3->access, 'Users table was not updated.'); $this->assertEqual($times4->timestamp, $times3->timestamp, 'Sessions table was not updated.'); @@ -267,7 +271,7 @@ public function testSessionWrite() { ]; $this->writeSettings($settings); $this->drupalGet(''); - $times5 = $connection->query($sql, [':uid' => $user->id()])->fetchObject(); + $times5 = $query->execute()->fetchObject(); $this->assertNotEqual($times5->access, $times4->access, 'Users table was updated.'); $this->assertNotEqual($times5->timestamp, $times4->timestamp, 'Sessions table was updated.'); } @@ -283,7 +287,12 @@ public function testEmptySessionID() { // Reset the sid in {sessions} to a blank string. This may exist in the // wild in some cases, although we normally prevent it from happening. - Database::getConnection()->query("UPDATE {sessions} SET sid = '' WHERE uid = :uid", [':uid' => $user->id()]); + Database::getConnection()->update('sessions') + ->fields([ + 'sid' => '', + ]) + ->condition('uid', $user->id()) + ->execute(); // Send a blank sid in the session cookie, and the session should no longer // be valid. Closing the curl handler will stop the previous session ID // from persisting. diff --git a/web/core/modules/system/tests/src/Functional/System/ErrorHandlerTest.php b/web/core/modules/system/tests/src/Functional/System/ErrorHandlerTest.php index 7e03031c10..a8f52f2750 100644 --- a/web/core/modules/system/tests/src/Functional/System/ErrorHandlerTest.php +++ b/web/core/modules/system/tests/src/Functional/System/ErrorHandlerTest.php @@ -105,7 +105,7 @@ public function testExceptionHandler() { ]; $error_pdo_exception = [ '%type' => 'DatabaseExceptionWrapper', - '@message' => 'SELECT * FROM bananas_are_awesome', + '@message' => 'SELECT b.* FROM {bananas_are_awesome} b', '%function' => 'Drupal\error_test\Controller\ErrorTestController->triggerPDOException()', '%line' => 64, '%file' => drupal_get_path('module', 'error_test') . '/error_test.module', @@ -127,7 +127,9 @@ public function testExceptionHandler() { // We cannot use assertErrorMessage() since the exact error reported // varies from database to database. Check that the SQL string is displayed. $this->assertText($error_pdo_exception['%type'], new FormattableMarkup('Found %type in error page.', $error_pdo_exception)); - $this->assertText($error_pdo_exception['@message'], new FormattableMarkup('Found @message in error page.', $error_pdo_exception)); + // Assert statement improved since static queries adds table alias in the + // error message. + $this->assertSession()->pageTextContains($error_pdo_exception['@message']); $error_details = new FormattableMarkup('in %function (line ', $error_pdo_exception); $this->assertRaw($error_details, new FormattableMarkup("Found '@message' in error page.", ['@message' => $error_details])); diff --git a/web/core/modules/taxonomy/src/Plugin/views/filter/TaxonomyIndexTid.php b/web/core/modules/taxonomy/src/Plugin/views/filter/TaxonomyIndexTid.php index 5829681767..24352de93b 100644 --- a/web/core/modules/taxonomy/src/Plugin/views/filter/TaxonomyIndexTid.php +++ b/web/core/modules/taxonomy/src/Plugin/views/filter/TaxonomyIndexTid.php @@ -4,6 +4,7 @@ use Drupal\Core\Entity\Element\EntityAutocomplete; use Drupal\Core\Form\FormStateInterface; +use Drupal\Core\Session\AccountInterface; use Drupal\taxonomy\Entity\Term; use Drupal\taxonomy\TermStorageInterface; use Drupal\taxonomy\VocabularyStorageInterface; @@ -38,6 +39,13 @@ class TaxonomyIndexTid extends ManyToOne { */ protected $termStorage; + /** + * The current user. + * + * @var \Drupal\Core\Session\AccountInterface + */ + protected $currentUser; + /** * Constructs a TaxonomyIndexTid object. * @@ -51,11 +59,18 @@ class TaxonomyIndexTid extends ManyToOne { * The vocabulary storage. * @param \Drupal\taxonomy\TermStorageInterface $term_storage * The term storage. + * @param \Drupal\Core\Session\AccountInterface $current_user + * The current user. */ - public function __construct(array $configuration, $plugin_id, $plugin_definition, VocabularyStorageInterface $vocabulary_storage, TermStorageInterface $term_storage) { + public function __construct(array $configuration, $plugin_id, $plugin_definition, VocabularyStorageInterface $vocabulary_storage, TermStorageInterface $term_storage, AccountInterface $current_user = NULL) { parent::__construct($configuration, $plugin_id, $plugin_definition); $this->vocabularyStorage = $vocabulary_storage; $this->termStorage = $term_storage; + if (!$current_user) { + @trigger_error('The current_user service must be passed to ' . __NAMESPACE__ . '\TaxonomyIndexTid::__construct(). It was added in drupal:8.9.0 and will be required before drupal:10.0.0.', E_USER_DEPRECATED); + $current_user = \Drupal::service('current_user'); + } + $this->currentUser = $current_user; } /** @@ -67,7 +82,8 @@ public static function create(ContainerInterface $container, array $configuratio $plugin_id, $plugin_definition, $container->get('entity_type.manager')->getStorage('taxonomy_vocabulary'), - $container->get('entity_type.manager')->getStorage('taxonomy_term') + $container->get('entity_type.manager')->getStorage('taxonomy_term'), + $container->get('current_user') ); } @@ -181,6 +197,9 @@ protected function valueForm(&$form, FormStateInterface $form_state) { if ($tree) { foreach ($tree as $term) { + if (!$term->isPublished() && !$this->currentUser->hasPermission('administer taxonomy')) { + continue; + } $choice = new \stdClass(); $choice->option = [$term->id() => str_repeat('-', $term->depth) . \Drupal::service('entity.repository')->getTranslationFromContext($term)->label()]; $options[] = $choice; @@ -195,6 +214,9 @@ protected function valueForm(&$form, FormStateInterface $form_state) { ->sort('weight') ->sort('name') ->addTag('taxonomy_term_access'); + if (!$this->currentUser->hasPermission('administer taxonomy')) { + $query->condition('status', 1); + } if ($this->options['limit']) { $query->condition('vid', $vocabulary->id()); } diff --git a/web/core/modules/taxonomy/tests/src/Functional/TermIndexTest.php b/web/core/modules/taxonomy/tests/src/Functional/TermIndexTest.php index f83313d77f..ccf5466922 100644 --- a/web/core/modules/taxonomy/tests/src/Functional/TermIndexTest.php +++ b/web/core/modules/taxonomy/tests/src/Functional/TermIndexTest.php @@ -117,10 +117,12 @@ public function testTaxonomyIndex() { // Check that the term is indexed, and only once. $node = $this->drupalGetNodeByTitle($edit['title[0][value]']); $connection = Database::getConnection(); - $index_count = $connection->query('SELECT COUNT(*) FROM {taxonomy_index} WHERE nid = :nid AND tid = :tid', [ - ':nid' => $node->id(), - ':tid' => $term_1->id(), - ])->fetchField(); + $index_count = $connection->select('taxonomy_index') + ->condition('nid', $node->id()) + ->condition('tid', $term_1->id()) + ->countQuery() + ->execute() + ->fetchField(); $this->assertEqual(1, $index_count, 'Term 1 is indexed once.'); // Update the article to change one term. @@ -128,15 +130,19 @@ public function testTaxonomyIndex() { $this->drupalPostForm('node/' . $node->id() . '/edit', $edit, t('Save')); // Check that both terms are indexed. - $index_count = $connection->query('SELECT COUNT(*) FROM {taxonomy_index} WHERE nid = :nid AND tid = :tid', [ - ':nid' => $node->id(), - ':tid' => $term_1->id(), - ])->fetchField(); + $index_count = $connection->select('taxonomy_index') + ->condition('nid', $node->id()) + ->condition('tid', $term_1->id()) + ->countQuery() + ->execute() + ->fetchField(); $this->assertEqual(1, $index_count, 'Term 1 is indexed.'); - $index_count = $connection->query('SELECT COUNT(*) FROM {taxonomy_index} WHERE nid = :nid AND tid = :tid', [ - ':nid' => $node->id(), - ':tid' => $term_2->id(), - ])->fetchField(); + $index_count = $connection->select('taxonomy_index') + ->condition('nid', $node->id()) + ->condition('tid', $term_2->id()) + ->countQuery() + ->execute() + ->fetchField(); $this->assertEqual(1, $index_count, 'Term 2 is indexed.'); // Update the article to change another term. @@ -144,15 +150,19 @@ public function testTaxonomyIndex() { $this->drupalPostForm('node/' . $node->id() . '/edit', $edit, t('Save')); // Check that only one term is indexed. - $index_count = $connection->query('SELECT COUNT(*) FROM {taxonomy_index} WHERE nid = :nid AND tid = :tid', [ - ':nid' => $node->id(), - ':tid' => $term_1->id(), - ])->fetchField(); + $index_count = $connection->select('taxonomy_index') + ->condition('nid', $node->id()) + ->condition('tid', $term_1->id()) + ->countQuery() + ->execute() + ->fetchField(); $this->assertEqual(0, $index_count, 'Term 1 is not indexed.'); - $index_count = $connection->query('SELECT COUNT(*) FROM {taxonomy_index} WHERE nid = :nid AND tid = :tid', [ - ':nid' => $node->id(), - ':tid' => $term_2->id(), - ])->fetchField(); + $index_count = $connection->select('taxonomy_index') + ->condition('nid', $node->id()) + ->condition('tid', $term_2->id()) + ->countQuery() + ->execute() + ->fetchField(); $this->assertEqual(1, $index_count, 'Term 2 is indexed once.'); // Redo the above tests without interface. @@ -164,15 +174,19 @@ public function testTaxonomyIndex() { $node->save(); // Check that the index was not changed. - $index_count = $connection->query('SELECT COUNT(*) FROM {taxonomy_index} WHERE nid = :nid AND tid = :tid', [ - ':nid' => $node->id(), - ':tid' => $term_1->id(), - ])->fetchField(); + $index_count = $connection->select('taxonomy_index') + ->condition('nid', $node->id()) + ->condition('tid', $term_1->id()) + ->countQuery() + ->execute() + ->fetchField(); $this->assertEqual(0, $index_count, 'Term 1 is not indexed.'); - $index_count = $connection->query('SELECT COUNT(*) FROM {taxonomy_index} WHERE nid = :nid AND tid = :tid', [ - ':nid' => $node->id(), - ':tid' => $term_2->id(), - ])->fetchField(); + $index_count = $connection->select('taxonomy_index') + ->condition('nid', $node->id()) + ->condition('tid', $term_2->id()) + ->countQuery() + ->execute() + ->fetchField(); $this->assertEqual(1, $index_count, 'Term 2 is indexed once.'); // Update the article to change one term. @@ -180,15 +194,19 @@ public function testTaxonomyIndex() { $node->save(); // Check that both terms are indexed. - $index_count = $connection->query('SELECT COUNT(*) FROM {taxonomy_index} WHERE nid = :nid AND tid = :tid', [ - ':nid' => $node->id(), - ':tid' => $term_1->id(), - ])->fetchField(); + $index_count = $connection->select('taxonomy_index') + ->condition('nid', $node->id()) + ->condition('tid', $term_1->id()) + ->countQuery() + ->execute() + ->fetchField(); $this->assertEqual(1, $index_count, 'Term 1 is indexed.'); - $index_count = $connection->query('SELECT COUNT(*) FROM {taxonomy_index} WHERE nid = :nid AND tid = :tid', [ - ':nid' => $node->id(), - ':tid' => $term_2->id(), - ])->fetchField(); + $index_count = $connection->select('taxonomy_index') + ->condition('nid', $node->id()) + ->condition('tid', $term_2->id()) + ->countQuery() + ->execute() + ->fetchField(); $this->assertEqual(1, $index_count, 'Term 2 is indexed.'); // Update the article to change another term. @@ -196,15 +214,19 @@ public function testTaxonomyIndex() { $node->save(); // Check that only one term is indexed. - $index_count = $connection->query('SELECT COUNT(*) FROM {taxonomy_index} WHERE nid = :nid AND tid = :tid', [ - ':nid' => $node->id(), - ':tid' => $term_1->id(), - ])->fetchField(); + $index_count = $connection->select('taxonomy_index') + ->condition('nid', $node->id()) + ->condition('tid', $term_1->id()) + ->countQuery() + ->execute() + ->fetchField(); $this->assertEqual(1, $index_count, 'Term 1 is indexed once.'); - $index_count = $connection->query('SELECT COUNT(*) FROM {taxonomy_index} WHERE nid = :nid AND tid = :tid', [ - ':nid' => $node->id(), - ':tid' => $term_2->id(), - ])->fetchField(); + $index_count = $connection->select('taxonomy_index') + ->condition('nid', $node->id()) + ->condition('tid', $term_2->id()) + ->countQuery() + ->execute() + ->fetchField(); $this->assertEqual(0, $index_count, 'Term 2 is not indexed.'); } diff --git a/web/core/modules/taxonomy/tests/src/Functional/Views/TaxonomyIndexTidUiTest.php b/web/core/modules/taxonomy/tests/src/Functional/Views/TaxonomyIndexTidUiTest.php index eb0774abb3..22845acd79 100644 --- a/web/core/modules/taxonomy/tests/src/Functional/Views/TaxonomyIndexTidUiTest.php +++ b/web/core/modules/taxonomy/tests/src/Functional/Views/TaxonomyIndexTidUiTest.php @@ -231,4 +231,41 @@ public function testExposedFilter() { $this->assertTrue(empty($preview), 'No results.'); } + /** + * Tests that an exposed taxonomy filter doesn't show unpublished terms. + */ + public function testExposedUnpublishedFilterOptions() { + $this->terms[1][0]->setUnpublished()->save(); + // Expose the filter. + $this->drupalPostForm('admin/structure/views/nojs/handler/test_filter_taxonomy_index_tid/default/filter/tid', [], 'Expose filter'); + $edit = ['options[expose_button][checkbox][checkbox]' => TRUE]; + $this->drupalPostForm(NULL, $edit, 'Apply'); + $this->drupalPostForm(NULL, [], 'Save'); + // Make sure the unpublished term is shown to the admin user. + $this->drupalGet('test-filter-taxonomy-index-tid'); + $this->assertNotEmpty($this->cssSelect('option[value="' . $this->terms[0][0]->id() . '"]')); + $this->assertNotEmpty($this->cssSelect('option[value="' . $this->terms[1][0]->id() . '"]')); + $this->drupalLogout(); + $this->drupalGet('test-filter-taxonomy-index-tid'); + // Make sure the unpublished term isn't shown to the anonymous user. + $this->assertNotEmpty($this->cssSelect('option[value="' . $this->terms[0][0]->id() . '"]')); + $this->assertEmpty($this->cssSelect('option[value="' . $this->terms[1][0]->id() . '"]')); + + // Tests that the term also isn't shown when not showing hierarchy. + $this->drupalLogin($this->adminUser); + $edit = [ + 'options[hierarchy]' => FALSE, + ]; + $this->drupalPostForm('admin/structure/views/nojs/handler-extra/test_filter_taxonomy_index_tid/default/filter/tid', $edit, 'Apply'); + $this->drupalPostForm(NULL, [], 'Save'); + $this->drupalGet('test-filter-taxonomy-index-tid'); + $this->assertNotEmpty($this->cssSelect('option[value="' . $this->terms[0][0]->id() . '"]')); + $this->assertNotEmpty($this->cssSelect('option[value="' . $this->terms[1][0]->id() . '"]')); + $this->drupalLogout(); + $this->drupalGet('test-filter-taxonomy-index-tid'); + // Make sure the unpublished term isn't shown to the anonymous user. + $this->assertNotEmpty($this->cssSelect('option[value="' . $this->terms[0][0]->id() . '"]')); + $this->assertEmpty($this->cssSelect('option[value="' . $this->terms[1][0]->id() . '"]')); + } + } diff --git a/web/core/modules/user/src/AccountForm.php b/web/core/modules/user/src/AccountForm.php index 8e32dad8b1..893fdd251b 100644 --- a/web/core/modules/user/src/AccountForm.php +++ b/web/core/modules/user/src/AccountForm.php @@ -272,8 +272,11 @@ public function form(array $form, FormStateInterface $form_state) { // separately, assume that the user profile data is in the user's preferred // language. This entity builder provides that synchronization. For // use-cases where this synchronization is not desired, a module can alter - // or remove this item. - $form['#entity_builders']['sync_user_langcode'] = '::syncUserLangcode'; + // or remove this item. Sync user langcode only when a user registers and + // not when a user is updated or translated. + if ($register) { + $form['#entity_builders']['sync_user_langcode'] = '::syncUserLangcode'; + } $system_date_config = \Drupal::config('system.date'); $form['timezone'] = [ diff --git a/web/core/modules/user/src/Plugin/Block/UserLoginBlock.php b/web/core/modules/user/src/Plugin/Block/UserLoginBlock.php index d9971c564d..f55a70d611 100644 --- a/web/core/modules/user/src/Plugin/Block/UserLoginBlock.php +++ b/web/core/modules/user/src/Plugin/Block/UserLoginBlock.php @@ -2,6 +2,7 @@ namespace Drupal\user\Plugin\Block; +use Drupal\Component\Utility\UrlHelper; use Drupal\Core\Access\AccessResult; use Drupal\Core\Plugin\ContainerFactoryPluginInterface; use Drupal\Core\Security\TrustedCallbackInterface; @@ -155,7 +156,7 @@ public function build() { public static function renderPlaceholderFormAction() { return [ '#type' => 'markup', - '#markup' => Url::fromRoute('<current>', [], ['query' => \Drupal::destination()->getAsArray(), 'external' => FALSE])->toString(), + '#markup' => UrlHelper::filterBadProtocol(Url::fromRoute('<current>', [], ['query' => \Drupal::destination()->getAsArray(), 'external' => FALSE])->toString()), '#cache' => ['contexts' => ['url.path', 'url.query_args']], ]; } diff --git a/web/core/modules/user/tests/src/Functional/UserEditTest.php b/web/core/modules/user/tests/src/Functional/UserEditTest.php index 6a71927a96..d06df78f3a 100644 --- a/web/core/modules/user/tests/src/Functional/UserEditTest.php +++ b/web/core/modules/user/tests/src/Functional/UserEditTest.php @@ -174,4 +174,53 @@ public function testUserWellKnownChangePasswordAnon() { $this->assertSession()->statusCodeEquals(403); } + /** + * Tests that a user is able to change site language. + */ + public function testUserChangeSiteLanguage() { + // Install these modules here as these aren't needed for other test methods. + \Drupal::service('module_installer')->install([ + 'content_translation', + 'language', + ]); + // Create and login as an admin user to add a new language and enable + // translation for user accounts. + $adminUser = $this->drupalCreateUser([ + 'administer account settings', + 'administer languages', + 'administer content translation', + 'administer users', + 'translate any entity', + ]); + $this->drupalLogin($adminUser); + + // Add a new language into the system. + $edit = [ + 'predefined_langcode' => 'fr', + ]; + $this->drupalPostForm('admin/config/regional/language/add', $edit, 'Add language'); + $this->assertSession()->pageTextContains('French'); + + // Enable translation for user accounts. + $edit = [ + 'language[content_translation]' => 1, + ]; + $this->drupalPostForm('admin/config/people/accounts', $edit, 'Save configuration'); + $this->assertSession()->pageTextContains('The configuration options have been saved.'); + + // Create a regular user for whom translation will be enabled. + $webUser = $this->drupalCreateUser(); + + // Create a translation for a regular user account. + $this->drupalPostForm('user/' . $webUser->id() . '/translations/add/en/fr', [], 'Save'); + $this->assertSession()->pageTextContains('The changes have been saved.'); + + // Update the site language of the user account. + $edit = [ + 'preferred_langcode' => 'fr', + ]; + $this->drupalPostForm('user/' . $webUser->id() . '/edit', $edit, 'Save'); + $this->assertSession()->statusCodeEquals(200); + } + } diff --git a/web/core/modules/views/tests/src/Kernel/Plugin/RelationshipJoinInTest.php b/web/core/modules/views/tests/src/Kernel/Plugin/RelationshipJoinInTest.php index 4b7a70d5bf..f6e11a0acc 100644 --- a/web/core/modules/views/tests/src/Kernel/Plugin/RelationshipJoinInTest.php +++ b/web/core/modules/views/tests/src/Kernel/Plugin/RelationshipJoinInTest.php @@ -40,15 +40,30 @@ public function testRelationshipInQuery() { // Update the first two Beatles to be authored by Kristiaan. $account_k = $this->createUser([], 'Kristiaan'); $connection = Database::getConnection(); - $connection->query("UPDATE {views_test_data} SET uid = :uid WHERE id IN (1,2)", [':uid' => $account_k->id()]); + $connection->update('views_test_data') + ->fields([ + 'uid' => $account_k->id(), + ]) + ->condition('id', [1, 2], 'IN') + ->execute(); // Update the other two Beatles to be authored by Django. $account_d = $this->createUser([], 'Django'); - $connection->query("UPDATE {views_test_data} SET uid = :uid WHERE id IN (3,4)", [':uid' => $account_d->id()]); + $connection->update('views_test_data') + ->fields([ + 'uid' => $account_d->id(), + ]) + ->condition('id', [3, 4], 'IN') + ->execute(); // Update Meredith to be authored by Silvie. $account_s = $this->createUser([], 'Silvie'); - $connection->query("UPDATE {views_test_data} SET uid = :uid WHERE id = 5", [':uid' => $account_s->id()]); + $connection->update('views_test_data') + ->fields([ + 'uid' => $account_s->id(), + ]) + ->condition('id', 5) + ->execute(); $view = Views::getView('test_view'); $view->setDisplay(); diff --git a/web/core/modules/views/tests/src/Kernel/Plugin/RelationshipTest.php b/web/core/modules/views/tests/src/Kernel/Plugin/RelationshipTest.php index 421b73643b..86e353bed7 100644 --- a/web/core/modules/views/tests/src/Kernel/Plugin/RelationshipTest.php +++ b/web/core/modules/views/tests/src/Kernel/Plugin/RelationshipTest.php @@ -38,8 +38,18 @@ class RelationshipTest extends RelationshipJoinTestBase { public function testRelationshipQuery() { $connection = Database::getConnection(); // Set the first entry to have the admin as author. - $connection->query("UPDATE {views_test_data} SET uid = 1 WHERE id = 1"); - $connection->query("UPDATE {views_test_data} SET uid = 2 WHERE id <> 1"); + $connection->update('views_test_data') + ->fields([ + 'uid' => 1, + ]) + ->condition('id', 1) + ->execute(); + $connection->update('views_test_data') + ->fields([ + 'uid' => 2, + ]) + ->condition('id', 1, '<>') + ->execute(); $view = Views::getView('test_view'); $view->setDisplay(); @@ -136,11 +146,26 @@ public function testRelationshipQuery() { public function testRelationshipRender() { $connection = Database::getConnection(); $author1 = $this->createUser(); - $connection->query("UPDATE {views_test_data} SET uid = :uid WHERE id = 1", [':uid' => $author1->id()]); + $connection->update('views_test_data') + ->fields([ + 'uid' => $author1->id(), + ]) + ->condition('id', 1) + ->execute(); $author2 = $this->createUser(); - $connection->query("UPDATE {views_test_data} SET uid = :uid WHERE id = 2", [':uid' => $author2->id()]); + $connection->update('views_test_data') + ->fields([ + 'uid' => $author2->id(), + ]) + ->condition('id', 2) + ->execute(); // Set uid to non-existing author uid for row 3. - $connection->query("UPDATE {views_test_data} SET uid = :uid WHERE id = 3", [':uid' => $author2->id() + 123]); + $connection->update('views_test_data') + ->fields([ + 'uid' => $author2->id() + 123, + ]) + ->condition('id', 3) + ->execute(); $view = Views::getView('test_view'); // Add a relationship for authors. diff --git a/web/core/modules/views_ui/src/Controller/ViewsUIController.php b/web/core/modules/views_ui/src/Controller/ViewsUIController.php index 92a258558b..c5ccdf23b3 100644 --- a/web/core/modules/views_ui/src/Controller/ViewsUIController.php +++ b/web/core/modules/views_ui/src/Controller/ViewsUIController.php @@ -2,6 +2,7 @@ namespace Drupal\views_ui\Controller; +use Drupal\Component\Utility\Tags; use Drupal\Core\Controller\ControllerBase; use Drupal\Core\Link; use Drupal\Core\Url; @@ -188,13 +189,15 @@ public function autocompleteTag(Request $request) { // Keep track of previously processed tags so they can be skipped. $tags = []; foreach ($views as $view) { - $tag = $view->get('tag'); - if ($tag && !in_array($tag, $tags)) { - $tags[] = $tag; - if (strpos($tag, $string) === 0) { - $matches[] = ['value' => $tag, 'label' => Html::escape($tag)]; - if (count($matches) >= 10) { - break; + $view_tag = $view->get('tag'); + foreach (Tags::explode($view_tag) as $tag) { + if ($tag && !in_array($tag, $tags, TRUE)) { + $tags[] = $tag; + if (mb_stripos($tag, $string) !== FALSE) { + $matches[] = ['value' => $tag, 'label' => Html::escape($tag)]; + if (count($matches) >= 10) { + break 2; + } } } } diff --git a/web/core/modules/views_ui/tests/src/Kernel/TagTest.php b/web/core/modules/views_ui/tests/src/Kernel/TagTest.php index 6376874b4a..9c7dbeb2ea 100644 --- a/web/core/modules/views_ui/tests/src/Kernel/TagTest.php +++ b/web/core/modules/views_ui/tests/src/Kernel/TagTest.php @@ -22,7 +22,7 @@ class TagTest extends ViewsKernelTestBase { public static $modules = ['views', 'views_ui', 'user']; /** - * Tests the views_ui_autocomplete_tag function. + * Tests the ViewsUIController::autocompleteTag() function. */ public function testViewsUiAutocompleteTag() { \Drupal::moduleHandler()->loadInclude('views_ui', 'inc', 'admin'); @@ -68,4 +68,41 @@ public function testViewsUiAutocompleteTag() { $this->assertCount(0, $matches, "Make sure an invalid tag doesn't return anything."); } + /** + * Tests that comma delimited tags are treated as individual tags. + * + * @dataProvider providerViewsUiAutocompleteIndividualTags + */ + public function testViewsUiAutocompleteIndividualTags($expected_tag, $search_string) { + $controller = ViewsUIController::create($this->container); + $request = $this->container->get('request_stack')->getCurrentRequest(); + $tag = 'comma, 你好, Foo bar'; + View::create(['tag' => $tag, 'id' => $this->randomMachineName()])->save(); + $request->query->set('q', $search_string); + $result = $controller->autocompleteTag($request); + $matches = (array) json_decode($result->getContent()); + $this->assertCount(1, $matches); + $this->assertSame($expected_tag, $matches[0]->value); + } + + /** + * Data provider for testViewsUiAutocompleteIndividualTags(). + * + * @return array[] + * The data set. + */ + public function providerViewsUiAutocompleteIndividualTags() { + return [ + 'tag' => ['comma', 'comma'], + 'case insensitive tag' => ['comma', 'COMMA'], + 'Hello in Chinese (partial 1)' => ['你好', '你'], + 'Hello in Chinese (partial 2)' => ['你好', '好'], + 'Hello in Chinese' => ['你好', '你好'], + 'Starts with partial and case-sensitive' => ['Foo bar', 'Foo'], + 'Starts with partial and case-insensitive' => ['Foo bar', 'fOO'], + 'Ends with partial and case-sensitive' => ['Foo bar', 'bar'], + 'Ends with partial and case-insensitive' => ['Foo bar', 'BAR'], + ]; + } + } diff --git a/web/core/modules/workspaces/src/WorkspaceManager.php b/web/core/modules/workspaces/src/WorkspaceManager.php index 541ca88564..3421d31ec6 100644 --- a/web/core/modules/workspaces/src/WorkspaceManager.php +++ b/web/core/modules/workspaces/src/WorkspaceManager.php @@ -186,7 +186,11 @@ public function getActiveWorkspace() { foreach ($this->negotiatorIds as $negotiator_id) { $negotiator = $this->classResolver->getInstanceFromDefinition($negotiator_id); if ($negotiator->applies($request)) { - if ($active_workspace = $negotiator->getActiveWorkspace($request)) { + // By default, 'view' access is checked when a workspace is activated, + // but it should also be checked when retrieving the currently active + // workspace. + if (($negotiated_workspace = $negotiator->getActiveWorkspace($request)) && $negotiated_workspace->access('view')) { + $active_workspace = $negotiated_workspace; break; } } diff --git a/web/core/modules/workspaces/tests/src/Functional/UpdateSystem/ActiveWorkspaceUpdateTest.php b/web/core/modules/workspaces/tests/src/Functional/UpdateSystem/ActiveWorkspaceUpdateTest.php index 98cc5a3bfe..1c4f9b90ab 100644 --- a/web/core/modules/workspaces/tests/src/Functional/UpdateSystem/ActiveWorkspaceUpdateTest.php +++ b/web/core/modules/workspaces/tests/src/Functional/UpdateSystem/ActiveWorkspaceUpdateTest.php @@ -4,6 +4,7 @@ use Drupal\Tests\BrowserTestBase; use Drupal\Tests\UpdatePathTestTrait; +use Drupal\Tests\user\Traits\UserCreationTrait; /** * Tests that there is no active workspace during database updates. @@ -12,12 +13,14 @@ * @group Update */ class ActiveWorkspaceUpdateTest extends BrowserTestBase { + use UpdatePathTestTrait; + use UserCreationTrait; /** * {@inheritdoc} */ - protected static $modules = ['workspaces', 'workspace_update_test']; + protected static $modules = ['workspaces']; /** * {@inheritdoc} @@ -29,6 +32,11 @@ class ActiveWorkspaceUpdateTest extends BrowserTestBase { */ protected function setUp() { parent::setUp(); + + $this->setUpCurrentUser([], ['view any workspace']); + $this->container->get('module_installer')->install(['workspace_update_test']); + $this->rebuildContainer(); + // Ensure the workspace_update_test_post_update_check_active_workspace() // update runs. $existing_updates = \Drupal::keyValue('post_update')->get('existing_updates', []); diff --git a/web/core/tests/Drupal/Tests/Core/Asset/LibraryDiscoveryParserTest.php b/web/core/tests/Drupal/Tests/Core/Asset/LibraryDiscoveryParserTest.php index 7fc84a4278..52838df335 100644 --- a/web/core/tests/Drupal/Tests/Core/Asset/LibraryDiscoveryParserTest.php +++ b/web/core/tests/Drupal/Tests/Core/Asset/LibraryDiscoveryParserTest.php @@ -644,6 +644,24 @@ public function testNonCoreLibrariesNotFound() { $this->assertEquals('libraries/third_party_library/css/example.css', $library['css'][0]['data']); } + /** + * @covers ::parseLibraryInfo + */ + public function testEmptyLibraryFile() { + $this->moduleHandler->expects($this->atLeastOnce()) + ->method('moduleExists') + ->with('empty') + ->will($this->returnValue(TRUE)); + + $path = __DIR__ . '/library_test_files'; + $path = substr($path, strlen($this->root) + 1); + $this->libraryDiscoveryParser->setPaths('module', 'empty', $path); + + $libraries = $this->libraryDiscoveryParser->buildByExtension('empty'); + + $this->assertEquals([], $libraries); + } + } /** diff --git a/web/core/tests/Drupal/Tests/Core/Asset/library_test_files/empty.libraries.yml b/web/core/tests/Drupal/Tests/Core/Asset/library_test_files/empty.libraries.yml new file mode 100644 index 0000000000..1388b54b2c --- /dev/null +++ b/web/core/tests/Drupal/Tests/Core/Asset/library_test_files/empty.libraries.yml @@ -0,0 +1 @@ +# This file intentionally left empty diff --git a/web/core/themes/claro/css/components/form.css b/web/core/themes/claro/css/components/form.css index 78dc419d1c..ac3f76feab 100644 --- a/web/core/themes/claro/css/components/form.css +++ b/web/core/themes/claro/css/components/form.css @@ -137,16 +137,11 @@ tr .form-item, .form-item__label.form-required::after, .fieldset__label.form-required::after { display: inline-block; - width: 0.4375rem; - height: 0.4375rem; - margin-right: 0.3em; - margin-left: 0.3em; - content: ""; - vertical-align: super; - /* Use a background image to prevent screen readers from announcing the text. */ - background-image: url(../../images/core/ee0000/required.svg); - background-repeat: no-repeat; - background-size: 0.4375rem 0.4375rem; + margin-right: 0.15em; + margin-left: 0.15em; + content: "*"; + color: #d72222; + font-size: 0.875rem; } /** diff --git a/web/core/themes/claro/css/components/form.pcss.css b/web/core/themes/claro/css/components/form.pcss.css index 554df9c9d1..1cf4cb4478 100644 --- a/web/core/themes/claro/css/components/form.pcss.css +++ b/web/core/themes/claro/css/components/form.pcss.css @@ -70,16 +70,11 @@ tr .form-item, .form-item__label.form-required::after, .fieldset__label.form-required::after { display: inline-block; - width: var(--input--required-mark-size); - height: var(--input--required-mark-size); - margin-right: 0.3em; - margin-left: 0.3em; - content: ""; - vertical-align: super; - /* Use a background image to prevent screen readers from announcing the text. */ - background-image: url(../../images/core/ee0000/required.svg); - background-repeat: no-repeat; - background-size: var(--input--required-mark-size) var(--input--required-mark-size); + margin-right: 0.15em; + margin-left: 0.15em; + content: "*"; + color: var(--color-maximumred); + font-size: 0.875rem; } /** diff --git a/web/sites/default/settings.pantheon.php b/web/sites/default/settings.pantheon.php index dfcd419a92..ace23ce1ad 100644 --- a/web/sites/default/settings.pantheon.php +++ b/web/sites/default/settings.pantheon.php @@ -25,7 +25,7 @@ * not to any Drupal files. */ if (!defined("PANTHEON_VERSION")) { - define("PANTHEON_VERSION", "3"); + define("PANTHEON_VERSION", "4"); } /** @@ -146,7 +146,7 @@ * */ if (isset($_ENV['PANTHEON_ENVIRONMENT'])) { - $settings["file_temp_path"] = $_SERVER['HOME'] .'/tmp'; + $settings["file_temp_path"] = sys_get_temp_dir(); } /** -- GitLab