diff --git a/composer.lock b/composer.lock index 3a0904f82a9e21b78f7de86ff90df6e9e7a816ca..9b995db663cf4ade817660a46e01755fbdbb02c8 100644 --- a/composer.lock +++ b/composer.lock @@ -1342,16 +1342,16 @@ }, { "name": "doctrine/annotations", - "version": "1.13.2", + "version": "1.13.3", "source": { "type": "git", "url": "https://github.com/doctrine/annotations.git", - "reference": "5b668aef16090008790395c02c893b1ba13f7e08" + "reference": "648b0343343565c4a056bfc8392201385e8d89f0" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/annotations/zipball/5b668aef16090008790395c02c893b1ba13f7e08", - "reference": "5b668aef16090008790395c02c893b1ba13f7e08", + "url": "https://api.github.com/repos/doctrine/annotations/zipball/648b0343343565c4a056bfc8392201385e8d89f0", + "reference": "648b0343343565c4a056bfc8392201385e8d89f0", "shasum": "" }, "require": { @@ -1363,9 +1363,10 @@ "require-dev": { "doctrine/cache": "^1.11 || ^2.0", "doctrine/coding-standard": "^6.0 || ^8.1", - "phpstan/phpstan": "^0.12.20", + "phpstan/phpstan": "^1.4.10 || ^1.8.0", "phpunit/phpunit": "^7.5 || ^8.0 || ^9.1.5", - "symfony/cache": "^4.4 || ^5.2" + "symfony/cache": "^4.4 || ^5.2", + "vimeo/psalm": "^4.10" }, "type": "library", "autoload": { @@ -1408,9 +1409,9 @@ ], "support": { "issues": "https://github.com/doctrine/annotations/issues", - "source": "https://github.com/doctrine/annotations/tree/1.13.2" + "source": "https://github.com/doctrine/annotations/tree/1.13.3" }, - "time": "2021-08-05T19:00:23+00:00" + "time": "2022-07-02T10:48:51+00:00" }, { "name": "doctrine/collections", @@ -2958,16 +2959,16 @@ }, { "name": "drupal/core", - "version": "9.4.1", + "version": "9.4.3", "source": { "type": "git", "url": "https://github.com/drupal/core.git", - "reference": "81489e8f0d5fdcd5d502b561f0f8cdf5ccdda614" + "reference": "7b1a403c093c7abc89ef3df1a6b05bdb19b3ffad" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/drupal/core/zipball/81489e8f0d5fdcd5d502b561f0f8cdf5ccdda614", - "reference": "81489e8f0d5fdcd5d502b561f0f8cdf5ccdda614", + "url": "https://api.github.com/repos/drupal/core/zipball/7b1a403c093c7abc89ef3df1a6b05bdb19b3ffad", + "reference": "7b1a403c093c7abc89ef3df1a6b05bdb19b3ffad", "shasum": "" }, "require": { @@ -3210,9 +3211,9 @@ ], "description": "Drupal is an open source content management platform powering millions of websites and applications.", "support": { - "source": "https://github.com/drupal/core/tree/9.4.1" + "source": "https://github.com/drupal/core/tree/9.4.3" }, - "time": "2022-06-21T20:53:48+00:00" + "time": "2022-07-20T15:11:38+00:00" }, { "name": "drupal/core-composer-scaffold", @@ -3266,16 +3267,16 @@ }, { "name": "drupal/core-recommended", - "version": "9.4.1", + "version": "9.4.3", "source": { "type": "git", "url": "https://github.com/drupal/core-recommended.git", - "reference": "a3ae54715ba7792fe596c2f6a73dfcef217b0577" + "reference": "ff8662af0a5963a88ea856e9786e17a51f8e640c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/drupal/core-recommended/zipball/a3ae54715ba7792fe596c2f6a73dfcef217b0577", - "reference": "a3ae54715ba7792fe596c2f6a73dfcef217b0577", + "url": "https://api.github.com/repos/drupal/core-recommended/zipball/ff8662af0a5963a88ea856e9786e17a51f8e640c", + "reference": "ff8662af0a5963a88ea856e9786e17a51f8e640c", "shasum": "" }, "require": { @@ -3284,7 +3285,7 @@ "doctrine/annotations": "~1.13.2", "doctrine/lexer": "~1.2.3", "doctrine/reflection": "~1.2.3", - "drupal/core": "9.4.1", + "drupal/core": "9.4.3", "egulias/email-validator": "~3.2", "guzzlehttp/guzzle": "~6.5.8", "guzzlehttp/promises": "~1.5.1", @@ -3346,9 +3347,9 @@ ], "description": "Core and its dependencies with known-compatible minor versions. Require this project INSTEAD OF drupal/core.", "support": { - "source": "https://github.com/drupal/core-recommended/tree/9.4.1" + "source": "https://github.com/drupal/core-recommended/tree/9.4.3" }, - "time": "2022-06-21T20:53:48+00:00" + "time": "2022-07-20T15:11:38+00:00" }, { "name": "drupal/crop", @@ -9154,16 +9155,16 @@ }, { "name": "laminas/laminas-diactoros", - "version": "2.11.0", + "version": "2.11.3", "source": { "type": "git", "url": "https://github.com/laminas/laminas-diactoros.git", - "reference": "d1bc565b23c2040fafde398a8a5db083c47928c0" + "reference": "1f97b0c52eafd108e09c76d6b29d83ef4a855f76" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laminas/laminas-diactoros/zipball/d1bc565b23c2040fafde398a8a5db083c47928c0", - "reference": "d1bc565b23c2040fafde398a8a5db083c47928c0", + "url": "https://api.github.com/repos/laminas/laminas-diactoros/zipball/1f97b0c52eafd108e09c76d6b29d83ef4a855f76", + "reference": "1f97b0c52eafd108e09c76d6b29d83ef4a855f76", "shasum": "" }, "require": { @@ -9249,7 +9250,7 @@ "type": "community_bridge" } ], - "time": "2022-05-17T10:57:52+00:00" + "time": "2022-07-06T09:24:53+00:00" }, { "name": "laminas/laminas-escaper", @@ -12912,7 +12913,7 @@ }, { "name": "symfony/deprecation-contracts", - "version": "v2.5.1", + "version": "v2.5.2", "source": { "type": "git", "url": "https://github.com/symfony/deprecation-contracts.git", @@ -12959,7 +12960,7 @@ "description": "A generic function and convention to trigger deprecation notices", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/deprecation-contracts/tree/v2.5.1" + "source": "https://github.com/symfony/deprecation-contracts/tree/v2.5.2" }, "funding": [ { @@ -13205,7 +13206,7 @@ }, { "name": "symfony/event-dispatcher-contracts", - "version": "v1.1.12", + "version": "v1.1.13", "source": { "type": "git", "url": "https://github.com/symfony/event-dispatcher-contracts.git", @@ -13264,7 +13265,7 @@ "standards" ], "support": { - "source": "https://github.com/symfony/event-dispatcher-contracts/tree/v1.1.12" + "source": "https://github.com/symfony/event-dispatcher-contracts/tree/v1.1.13" }, "funding": [ { @@ -13408,16 +13409,16 @@ }, { "name": "symfony/http-client-contracts", - "version": "v2.5.1", + "version": "v2.5.2", "source": { "type": "git", "url": "https://github.com/symfony/http-client-contracts.git", - "reference": "1a4f708e4e87f335d1b1be6148060739152f0bd5" + "reference": "ba6a9f0e8f3edd190520ee3b9a958596b6ca2e70" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-client-contracts/zipball/1a4f708e4e87f335d1b1be6148060739152f0bd5", - "reference": "1a4f708e4e87f335d1b1be6148060739152f0bd5", + "url": "https://api.github.com/repos/symfony/http-client-contracts/zipball/ba6a9f0e8f3edd190520ee3b9a958596b6ca2e70", + "reference": "ba6a9f0e8f3edd190520ee3b9a958596b6ca2e70", "shasum": "" }, "require": { @@ -13466,7 +13467,7 @@ "standards" ], "support": { - "source": "https://github.com/symfony/http-client-contracts/tree/v2.5.1" + "source": "https://github.com/symfony/http-client-contracts/tree/v2.5.2" }, "funding": [ { @@ -13482,7 +13483,7 @@ "type": "tidelift" } ], - "time": "2022-03-13T20:07:29+00:00" + "time": "2022-04-12T15:48:08+00:00" }, { "name": "symfony/http-foundation", @@ -14810,16 +14811,16 @@ }, { "name": "symfony/service-contracts", - "version": "v2.5.1", + "version": "v2.5.2", "source": { "type": "git", "url": "https://github.com/symfony/service-contracts.git", - "reference": "24d9dc654b83e91aa59f9d167b131bc3b5bea24c" + "reference": "4b426aac47d6427cc1a1d0f7e2ac724627f5966c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/service-contracts/zipball/24d9dc654b83e91aa59f9d167b131bc3b5bea24c", - "reference": "24d9dc654b83e91aa59f9d167b131bc3b5bea24c", + "url": "https://api.github.com/repos/symfony/service-contracts/zipball/4b426aac47d6427cc1a1d0f7e2ac724627f5966c", + "reference": "4b426aac47d6427cc1a1d0f7e2ac724627f5966c", "shasum": "" }, "require": { @@ -14873,7 +14874,7 @@ "standards" ], "support": { - "source": "https://github.com/symfony/service-contracts/tree/v2.5.1" + "source": "https://github.com/symfony/service-contracts/tree/v2.5.2" }, "funding": [ { @@ -14889,7 +14890,7 @@ "type": "tidelift" } ], - "time": "2022-03-13T20:07:29+00:00" + "time": "2022-05-30T19:17:29+00:00" }, { "name": "symfony/translation", @@ -14982,16 +14983,16 @@ }, { "name": "symfony/translation-contracts", - "version": "v2.5.1", + "version": "v2.5.2", "source": { "type": "git", "url": "https://github.com/symfony/translation-contracts.git", - "reference": "1211df0afa701e45a04253110e959d4af4ef0f07" + "reference": "136b19dd05cdf0709db6537d058bcab6dd6e2dbe" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/translation-contracts/zipball/1211df0afa701e45a04253110e959d4af4ef0f07", - "reference": "1211df0afa701e45a04253110e959d4af4ef0f07", + "url": "https://api.github.com/repos/symfony/translation-contracts/zipball/136b19dd05cdf0709db6537d058bcab6dd6e2dbe", + "reference": "136b19dd05cdf0709db6537d058bcab6dd6e2dbe", "shasum": "" }, "require": { @@ -15040,7 +15041,7 @@ "standards" ], "support": { - "source": "https://github.com/symfony/translation-contracts/tree/v2.5.1" + "source": "https://github.com/symfony/translation-contracts/tree/v2.5.2" }, "funding": [ { @@ -15056,7 +15057,7 @@ "type": "tidelift" } ], - "time": "2022-01-02T09:53:40+00:00" + "time": "2022-06-27T16:58:25+00:00" }, { "name": "symfony/validator", diff --git a/vendor/composer/autoload_classmap.php b/vendor/composer/autoload_classmap.php index 55becfd2d22430d610c884c377d66c2ce00bc823..e1198c7a003bd58ba652ac7a04ddb564e11c5669 100644 --- a/vendor/composer/autoload_classmap.php +++ b/vendor/composer/autoload_classmap.php @@ -3274,6 +3274,8 @@ 'Laminas\\Diactoros\\Exception\\DeserializationException' => $vendorDir . '/laminas/laminas-diactoros/src/Exception/DeserializationException.php', 'Laminas\\Diactoros\\Exception\\ExceptionInterface' => $vendorDir . '/laminas/laminas-diactoros/src/Exception/ExceptionInterface.php', 'Laminas\\Diactoros\\Exception\\InvalidArgumentException' => $vendorDir . '/laminas/laminas-diactoros/src/Exception/InvalidArgumentException.php', + 'Laminas\\Diactoros\\Exception\\InvalidForwardedHeaderNameException' => $vendorDir . '/laminas/laminas-diactoros/src/Exception/InvalidForwardedHeaderNameException.php', + 'Laminas\\Diactoros\\Exception\\InvalidProxyAddressException' => $vendorDir . '/laminas/laminas-diactoros/src/Exception/InvalidProxyAddressException.php', 'Laminas\\Diactoros\\Exception\\InvalidStreamPointerPositionException' => $vendorDir . '/laminas/laminas-diactoros/src/Exception/InvalidStreamPointerPositionException.php', 'Laminas\\Diactoros\\Exception\\RuntimeException' => $vendorDir . '/laminas/laminas-diactoros/src/Exception/RuntimeException.php', 'Laminas\\Diactoros\\Exception\\SerializationException' => $vendorDir . '/laminas/laminas-diactoros/src/Exception/SerializationException.php', @@ -3308,6 +3310,10 @@ 'Laminas\\Diactoros\\Response\\XmlResponse' => $vendorDir . '/laminas/laminas-diactoros/src/Response/XmlResponse.php', 'Laminas\\Diactoros\\ServerRequest' => $vendorDir . '/laminas/laminas-diactoros/src/ServerRequest.php', 'Laminas\\Diactoros\\ServerRequestFactory' => $vendorDir . '/laminas/laminas-diactoros/src/ServerRequestFactory.php', + 'Laminas\\Diactoros\\ServerRequestFilter\\DoNotFilter' => $vendorDir . '/laminas/laminas-diactoros/src/ServerRequestFilter/DoNotFilter.php', + 'Laminas\\Diactoros\\ServerRequestFilter\\FilterServerRequestInterface' => $vendorDir . '/laminas/laminas-diactoros/src/ServerRequestFilter/FilterServerRequestInterface.php', + 'Laminas\\Diactoros\\ServerRequestFilter\\FilterUsingXForwardedHeaders' => $vendorDir . '/laminas/laminas-diactoros/src/ServerRequestFilter/FilterUsingXForwardedHeaders.php', + 'Laminas\\Diactoros\\ServerRequestFilter\\IPRange' => $vendorDir . '/laminas/laminas-diactoros/src/ServerRequestFilter/IPRange.php', 'Laminas\\Diactoros\\Stream' => $vendorDir . '/laminas/laminas-diactoros/src/Stream.php', 'Laminas\\Diactoros\\StreamFactory' => $vendorDir . '/laminas/laminas-diactoros/src/StreamFactory.php', 'Laminas\\Diactoros\\UploadedFile' => $vendorDir . '/laminas/laminas-diactoros/src/UploadedFile.php', diff --git a/vendor/composer/autoload_static.php b/vendor/composer/autoload_static.php index bfb31e3b85899a2500a0782e582668cb9cf08638..42fd77cc434f7cfeea9e196f92de959f4ca1029f 100644 --- a/vendor/composer/autoload_static.php +++ b/vendor/composer/autoload_static.php @@ -4060,6 +4060,8 @@ class ComposerStaticInit5c689ffcd54b9e495ed983fdce09b530 'Laminas\\Diactoros\\Exception\\DeserializationException' => __DIR__ . '/..' . '/laminas/laminas-diactoros/src/Exception/DeserializationException.php', 'Laminas\\Diactoros\\Exception\\ExceptionInterface' => __DIR__ . '/..' . '/laminas/laminas-diactoros/src/Exception/ExceptionInterface.php', 'Laminas\\Diactoros\\Exception\\InvalidArgumentException' => __DIR__ . '/..' . '/laminas/laminas-diactoros/src/Exception/InvalidArgumentException.php', + 'Laminas\\Diactoros\\Exception\\InvalidForwardedHeaderNameException' => __DIR__ . '/..' . '/laminas/laminas-diactoros/src/Exception/InvalidForwardedHeaderNameException.php', + 'Laminas\\Diactoros\\Exception\\InvalidProxyAddressException' => __DIR__ . '/..' . '/laminas/laminas-diactoros/src/Exception/InvalidProxyAddressException.php', 'Laminas\\Diactoros\\Exception\\InvalidStreamPointerPositionException' => __DIR__ . '/..' . '/laminas/laminas-diactoros/src/Exception/InvalidStreamPointerPositionException.php', 'Laminas\\Diactoros\\Exception\\RuntimeException' => __DIR__ . '/..' . '/laminas/laminas-diactoros/src/Exception/RuntimeException.php', 'Laminas\\Diactoros\\Exception\\SerializationException' => __DIR__ . '/..' . '/laminas/laminas-diactoros/src/Exception/SerializationException.php', @@ -4094,6 +4096,10 @@ class ComposerStaticInit5c689ffcd54b9e495ed983fdce09b530 'Laminas\\Diactoros\\Response\\XmlResponse' => __DIR__ . '/..' . '/laminas/laminas-diactoros/src/Response/XmlResponse.php', 'Laminas\\Diactoros\\ServerRequest' => __DIR__ . '/..' . '/laminas/laminas-diactoros/src/ServerRequest.php', 'Laminas\\Diactoros\\ServerRequestFactory' => __DIR__ . '/..' . '/laminas/laminas-diactoros/src/ServerRequestFactory.php', + 'Laminas\\Diactoros\\ServerRequestFilter\\DoNotFilter' => __DIR__ . '/..' . '/laminas/laminas-diactoros/src/ServerRequestFilter/DoNotFilter.php', + 'Laminas\\Diactoros\\ServerRequestFilter\\FilterServerRequestInterface' => __DIR__ . '/..' . '/laminas/laminas-diactoros/src/ServerRequestFilter/FilterServerRequestInterface.php', + 'Laminas\\Diactoros\\ServerRequestFilter\\FilterUsingXForwardedHeaders' => __DIR__ . '/..' . '/laminas/laminas-diactoros/src/ServerRequestFilter/FilterUsingXForwardedHeaders.php', + 'Laminas\\Diactoros\\ServerRequestFilter\\IPRange' => __DIR__ . '/..' . '/laminas/laminas-diactoros/src/ServerRequestFilter/IPRange.php', 'Laminas\\Diactoros\\Stream' => __DIR__ . '/..' . '/laminas/laminas-diactoros/src/Stream.php', 'Laminas\\Diactoros\\StreamFactory' => __DIR__ . '/..' . '/laminas/laminas-diactoros/src/StreamFactory.php', 'Laminas\\Diactoros\\UploadedFile' => __DIR__ . '/..' . '/laminas/laminas-diactoros/src/UploadedFile.php', diff --git a/vendor/composer/installed.json b/vendor/composer/installed.json index 8ac11e86cd33024f71d8868e96c504e0d132638b..878dac5a4671d253b87e7ea3a44c00413f7d2bea 100644 --- a/vendor/composer/installed.json +++ b/vendor/composer/installed.json @@ -1365,17 +1365,17 @@ }, { "name": "doctrine/annotations", - "version": "1.13.2", - "version_normalized": "1.13.2.0", + "version": "1.13.3", + "version_normalized": "1.13.3.0", "source": { "type": "git", "url": "https://github.com/doctrine/annotations.git", - "reference": "5b668aef16090008790395c02c893b1ba13f7e08" + "reference": "648b0343343565c4a056bfc8392201385e8d89f0" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/annotations/zipball/5b668aef16090008790395c02c893b1ba13f7e08", - "reference": "5b668aef16090008790395c02c893b1ba13f7e08", + "url": "https://api.github.com/repos/doctrine/annotations/zipball/648b0343343565c4a056bfc8392201385e8d89f0", + "reference": "648b0343343565c4a056bfc8392201385e8d89f0", "shasum": "" }, "require": { @@ -1387,11 +1387,12 @@ "require-dev": { "doctrine/cache": "^1.11 || ^2.0", "doctrine/coding-standard": "^6.0 || ^8.1", - "phpstan/phpstan": "^0.12.20", + "phpstan/phpstan": "^1.4.10 || ^1.8.0", "phpunit/phpunit": "^7.5 || ^8.0 || ^9.1.5", - "symfony/cache": "^4.4 || ^5.2" + "symfony/cache": "^4.4 || ^5.2", + "vimeo/psalm": "^4.10" }, - "time": "2021-08-05T19:00:23+00:00", + "time": "2022-07-02T10:48:51+00:00", "type": "library", "installation-source": "dist", "autoload": { @@ -1434,7 +1435,7 @@ ], "support": { "issues": "https://github.com/doctrine/annotations/issues", - "source": "https://github.com/doctrine/annotations/tree/1.13.2" + "source": "https://github.com/doctrine/annotations/tree/1.13.3" }, "install-path": "../doctrine/annotations" }, @@ -3044,17 +3045,17 @@ }, { "name": "drupal/core", - "version": "9.4.1", - "version_normalized": "9.4.1.0", + "version": "9.4.3", + "version_normalized": "9.4.3.0", "source": { "type": "git", "url": "https://github.com/drupal/core.git", - "reference": "81489e8f0d5fdcd5d502b561f0f8cdf5ccdda614" + "reference": "7b1a403c093c7abc89ef3df1a6b05bdb19b3ffad" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/drupal/core/zipball/81489e8f0d5fdcd5d502b561f0f8cdf5ccdda614", - "reference": "81489e8f0d5fdcd5d502b561f0f8cdf5ccdda614", + "url": "https://api.github.com/repos/drupal/core/zipball/7b1a403c093c7abc89ef3df1a6b05bdb19b3ffad", + "reference": "7b1a403c093c7abc89ef3df1a6b05bdb19b3ffad", "shasum": "" }, "require": { @@ -3225,7 +3226,7 @@ "drupal/workflows": "self.version", "drupal/workspaces": "self.version" }, - "time": "2022-06-21T20:53:48+00:00", + "time": "2022-07-20T15:11:38+00:00", "type": "drupal-core", "extra": { "drupal-scaffold": { @@ -3303,7 +3304,7 @@ ], "description": "Drupal is an open source content management platform powering millions of websites and applications.", "support": { - "source": "https://github.com/drupal/core/tree/9.4.1" + "source": "https://github.com/drupal/core/tree/9.4.3" }, "install-path": "../../web/core" }, @@ -3359,17 +3360,17 @@ }, { "name": "drupal/core-recommended", - "version": "9.4.1", - "version_normalized": "9.4.1.0", + "version": "9.4.3", + "version_normalized": "9.4.3.0", "source": { "type": "git", "url": "https://github.com/drupal/core-recommended.git", - "reference": "a3ae54715ba7792fe596c2f6a73dfcef217b0577" + "reference": "ff8662af0a5963a88ea856e9786e17a51f8e640c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/drupal/core-recommended/zipball/a3ae54715ba7792fe596c2f6a73dfcef217b0577", - "reference": "a3ae54715ba7792fe596c2f6a73dfcef217b0577", + "url": "https://api.github.com/repos/drupal/core-recommended/zipball/ff8662af0a5963a88ea856e9786e17a51f8e640c", + "reference": "ff8662af0a5963a88ea856e9786e17a51f8e640c", "shasum": "" }, "require": { @@ -3378,7 +3379,7 @@ "doctrine/annotations": "~1.13.2", "doctrine/lexer": "~1.2.3", "doctrine/reflection": "~1.2.3", - "drupal/core": "9.4.1", + "drupal/core": "9.4.3", "egulias/email-validator": "~3.2", "guzzlehttp/guzzle": "~6.5.8", "guzzlehttp/promises": "~1.5.1", @@ -3433,7 +3434,7 @@ "conflict": { "webflo/drupal-core-strict": "*" }, - "time": "2022-06-21T20:53:48+00:00", + "time": "2022-07-20T15:11:38+00:00", "type": "metapackage", "notification-url": "https://packagist.org/downloads/", "license": [ @@ -3441,7 +3442,7 @@ ], "description": "Core and its dependencies with known-compatible minor versions. Require this project INSTEAD OF drupal/core.", "support": { - "source": "https://github.com/drupal/core-recommended/tree/9.4.1" + "source": "https://github.com/drupal/core-recommended/tree/9.4.3" }, "install-path": null }, @@ -9494,17 +9495,17 @@ }, { "name": "laminas/laminas-diactoros", - "version": "2.11.0", - "version_normalized": "2.11.0.0", + "version": "2.11.3", + "version_normalized": "2.11.3.0", "source": { "type": "git", "url": "https://github.com/laminas/laminas-diactoros.git", - "reference": "d1bc565b23c2040fafde398a8a5db083c47928c0" + "reference": "1f97b0c52eafd108e09c76d6b29d83ef4a855f76" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laminas/laminas-diactoros/zipball/d1bc565b23c2040fafde398a8a5db083c47928c0", - "reference": "d1bc565b23c2040fafde398a8a5db083c47928c0", + "url": "https://api.github.com/repos/laminas/laminas-diactoros/zipball/1f97b0c52eafd108e09c76d6b29d83ef4a855f76", + "reference": "1f97b0c52eafd108e09c76d6b29d83ef4a855f76", "shasum": "" }, "require": { @@ -9533,7 +9534,7 @@ "psalm/plugin-phpunit": "^0.14.0", "vimeo/psalm": "^4.3" }, - "time": "2022-05-17T10:57:52+00:00", + "time": "2022-07-06T09:24:53+00:00", "type": "library", "extra": { "laminas": { @@ -13282,8 +13283,8 @@ }, { "name": "symfony/deprecation-contracts", - "version": "v2.5.1", - "version_normalized": "2.5.1.0", + "version": "v2.5.2", + "version_normalized": "2.5.2.0", "source": { "type": "git", "url": "https://github.com/symfony/deprecation-contracts.git", @@ -13332,7 +13333,7 @@ "description": "A generic function and convention to trigger deprecation notices", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/deprecation-contracts/tree/v2.5.1" + "source": "https://github.com/symfony/deprecation-contracts/tree/v2.5.2" }, "funding": [ { @@ -13587,8 +13588,8 @@ }, { "name": "symfony/event-dispatcher-contracts", - "version": "v1.1.12", - "version_normalized": "1.1.12.0", + "version": "v1.1.13", + "version_normalized": "1.1.13.0", "source": { "type": "git", "url": "https://github.com/symfony/event-dispatcher-contracts.git", @@ -13649,7 +13650,7 @@ "standards" ], "support": { - "source": "https://github.com/symfony/event-dispatcher-contracts/tree/v1.1.12" + "source": "https://github.com/symfony/event-dispatcher-contracts/tree/v1.1.13" }, "funding": [ { @@ -13799,17 +13800,17 @@ }, { "name": "symfony/http-client-contracts", - "version": "v2.5.1", - "version_normalized": "2.5.1.0", + "version": "v2.5.2", + "version_normalized": "2.5.2.0", "source": { "type": "git", "url": "https://github.com/symfony/http-client-contracts.git", - "reference": "1a4f708e4e87f335d1b1be6148060739152f0bd5" + "reference": "ba6a9f0e8f3edd190520ee3b9a958596b6ca2e70" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-client-contracts/zipball/1a4f708e4e87f335d1b1be6148060739152f0bd5", - "reference": "1a4f708e4e87f335d1b1be6148060739152f0bd5", + "url": "https://api.github.com/repos/symfony/http-client-contracts/zipball/ba6a9f0e8f3edd190520ee3b9a958596b6ca2e70", + "reference": "ba6a9f0e8f3edd190520ee3b9a958596b6ca2e70", "shasum": "" }, "require": { @@ -13818,7 +13819,7 @@ "suggest": { "symfony/http-client-implementation": "" }, - "time": "2022-03-13T20:07:29+00:00", + "time": "2022-04-12T15:48:08+00:00", "type": "library", "extra": { "branch-alias": { @@ -13860,7 +13861,7 @@ "standards" ], "support": { - "source": "https://github.com/symfony/http-client-contracts/tree/v2.5.1" + "source": "https://github.com/symfony/http-client-contracts/tree/v2.5.2" }, "funding": [ { @@ -15252,17 +15253,17 @@ }, { "name": "symfony/service-contracts", - "version": "v2.5.1", - "version_normalized": "2.5.1.0", + "version": "v2.5.2", + "version_normalized": "2.5.2.0", "source": { "type": "git", "url": "https://github.com/symfony/service-contracts.git", - "reference": "24d9dc654b83e91aa59f9d167b131bc3b5bea24c" + "reference": "4b426aac47d6427cc1a1d0f7e2ac724627f5966c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/service-contracts/zipball/24d9dc654b83e91aa59f9d167b131bc3b5bea24c", - "reference": "24d9dc654b83e91aa59f9d167b131bc3b5bea24c", + "url": "https://api.github.com/repos/symfony/service-contracts/zipball/4b426aac47d6427cc1a1d0f7e2ac724627f5966c", + "reference": "4b426aac47d6427cc1a1d0f7e2ac724627f5966c", "shasum": "" }, "require": { @@ -15276,7 +15277,7 @@ "suggest": { "symfony/service-implementation": "" }, - "time": "2022-03-13T20:07:29+00:00", + "time": "2022-05-30T19:17:29+00:00", "type": "library", "extra": { "branch-alias": { @@ -15318,7 +15319,7 @@ "standards" ], "support": { - "source": "https://github.com/symfony/service-contracts/tree/v2.5.1" + "source": "https://github.com/symfony/service-contracts/tree/v2.5.2" }, "funding": [ { @@ -15430,17 +15431,17 @@ }, { "name": "symfony/translation-contracts", - "version": "v2.5.1", - "version_normalized": "2.5.1.0", + "version": "v2.5.2", + "version_normalized": "2.5.2.0", "source": { "type": "git", "url": "https://github.com/symfony/translation-contracts.git", - "reference": "1211df0afa701e45a04253110e959d4af4ef0f07" + "reference": "136b19dd05cdf0709db6537d058bcab6dd6e2dbe" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/translation-contracts/zipball/1211df0afa701e45a04253110e959d4af4ef0f07", - "reference": "1211df0afa701e45a04253110e959d4af4ef0f07", + "url": "https://api.github.com/repos/symfony/translation-contracts/zipball/136b19dd05cdf0709db6537d058bcab6dd6e2dbe", + "reference": "136b19dd05cdf0709db6537d058bcab6dd6e2dbe", "shasum": "" }, "require": { @@ -15449,7 +15450,7 @@ "suggest": { "symfony/translation-implementation": "" }, - "time": "2022-01-02T09:53:40+00:00", + "time": "2022-06-27T16:58:25+00:00", "type": "library", "extra": { "branch-alias": { @@ -15491,7 +15492,7 @@ "standards" ], "support": { - "source": "https://github.com/symfony/translation-contracts/tree/v2.5.1" + "source": "https://github.com/symfony/translation-contracts/tree/v2.5.2" }, "funding": [ { diff --git a/vendor/composer/installed.php b/vendor/composer/installed.php index 1ba378e309d133258d118539d247993070a441ad..36415218a894e2d370db251c755e6aa053bb5ac4 100644 --- a/vendor/composer/installed.php +++ b/vendor/composer/installed.php @@ -3,7 +3,7 @@ 'name' => 'osu-asc-webservices/d8-upstream', 'pretty_version' => 'dev-master', 'version' => 'dev-master', - 'reference' => '07a7c2435c9d4e8234762b2e1e5bea728ccd9e76', + 'reference' => 'f3adbe0a3bfef44fba6e4ed128a583c42dc7445f', 'type' => 'project', 'install_path' => __DIR__ . '/../../', 'aliases' => array(), @@ -233,9 +233,9 @@ 'dev_requirement' => false, ), 'doctrine/annotations' => array( - 'pretty_version' => '1.13.2', - 'version' => '1.13.2.0', - 'reference' => '5b668aef16090008790395c02c893b1ba13f7e08', + 'pretty_version' => '1.13.3', + 'version' => '1.13.3.0', + 'reference' => '648b0343343565c4a056bfc8392201385e8d89f0', 'type' => 'library', 'install_path' => __DIR__ . '/../doctrine/annotations', 'aliases' => array(), @@ -271,7 +271,7 @@ 'drupal/action' => array( 'dev_requirement' => false, 'replaced' => array( - 0 => '9.4.1', + 0 => '9.4.3', ), ), 'drupal/addtocalendar' => array( @@ -304,7 +304,7 @@ 'drupal/aggregator' => array( 'dev_requirement' => false, 'replaced' => array( - 0 => '9.4.1', + 0 => '9.4.3', ), ), 'drupal/allowed_formats' => array( @@ -328,25 +328,25 @@ 'drupal/automated_cron' => array( 'dev_requirement' => false, 'replaced' => array( - 0 => '9.4.1', + 0 => '9.4.3', ), ), 'drupal/ban' => array( 'dev_requirement' => false, 'replaced' => array( - 0 => '9.4.1', + 0 => '9.4.3', ), ), 'drupal/bartik' => array( 'dev_requirement' => false, 'replaced' => array( - 0 => '9.4.1', + 0 => '9.4.3', ), ), 'drupal/basic_auth' => array( 'dev_requirement' => false, 'replaced' => array( - 0 => '9.4.1', + 0 => '9.4.3', ), ), 'drupal/better_exposed_filters' => array( @@ -361,19 +361,19 @@ 'drupal/big_pipe' => array( 'dev_requirement' => false, 'replaced' => array( - 0 => '9.4.1', + 0 => '9.4.3', ), ), 'drupal/block' => array( 'dev_requirement' => false, 'replaced' => array( - 0 => '9.4.1', + 0 => '9.4.3', ), ), 'drupal/block_content' => array( 'dev_requirement' => false, 'replaced' => array( - 0 => '9.4.1', + 0 => '9.4.3', ), ), 'drupal/block_field' => array( @@ -406,7 +406,7 @@ 'drupal/book' => array( 'dev_requirement' => false, 'replaced' => array( - 0 => '9.4.1', + 0 => '9.4.3', ), ), 'drupal/bootstrap' => array( @@ -421,7 +421,7 @@ 'drupal/breakpoint' => array( 'dev_requirement' => false, 'replaced' => array( - 0 => '9.4.1', + 0 => '9.4.3', ), ), 'drupal/cache_control_override' => array( @@ -445,13 +445,13 @@ 'drupal/ckeditor' => array( 'dev_requirement' => false, 'replaced' => array( - 0 => '9.4.1', + 0 => '9.4.3', ), ), 'drupal/ckeditor5' => array( 'dev_requirement' => false, 'replaced' => array( - 0 => '9.4.1', + 0 => '9.4.3', ), ), 'drupal/ckeditor_indentblock' => array( @@ -466,31 +466,31 @@ 'drupal/claro' => array( 'dev_requirement' => false, 'replaced' => array( - 0 => '9.4.1', + 0 => '9.4.3', ), ), 'drupal/classy' => array( 'dev_requirement' => false, 'replaced' => array( - 0 => '9.4.1', + 0 => '9.4.3', ), ), 'drupal/color' => array( 'dev_requirement' => false, 'replaced' => array( - 0 => '9.4.1', + 0 => '9.4.3', ), ), 'drupal/comment' => array( 'dev_requirement' => false, 'replaced' => array( - 0 => '9.4.1', + 0 => '9.4.3', ), ), 'drupal/config' => array( 'dev_requirement' => false, 'replaced' => array( - 0 => '9.4.1', + 0 => '9.4.3', ), ), 'drupal/config_direct_save' => array( @@ -523,7 +523,7 @@ 'drupal/config_translation' => array( 'dev_requirement' => false, 'replaced' => array( - 0 => '9.4.1', + 0 => '9.4.3', ), ), 'drupal/config_update' => array( @@ -574,7 +574,7 @@ 'drupal/contact' => array( 'dev_requirement' => false, 'replaced' => array( - 0 => '9.4.1', + 0 => '9.4.3', ), ), 'drupal/content_access' => array( @@ -589,25 +589,25 @@ 'drupal/content_moderation' => array( 'dev_requirement' => false, 'replaced' => array( - 0 => '9.4.1', + 0 => '9.4.3', ), ), 'drupal/content_translation' => array( 'dev_requirement' => false, 'replaced' => array( - 0 => '9.4.1', + 0 => '9.4.3', ), ), 'drupal/contextual' => array( 'dev_requirement' => false, 'replaced' => array( - 0 => '9.4.1', + 0 => '9.4.3', ), ), 'drupal/core' => array( - 'pretty_version' => '9.4.1', - 'version' => '9.4.1.0', - 'reference' => '81489e8f0d5fdcd5d502b561f0f8cdf5ccdda614', + 'pretty_version' => '9.4.3', + 'version' => '9.4.3.0', + 'reference' => '7b1a403c093c7abc89ef3df1a6b05bdb19b3ffad', 'type' => 'drupal-core', 'install_path' => __DIR__ . '/../../web/core', 'aliases' => array(), @@ -616,25 +616,25 @@ 'drupal/core-annotation' => array( 'dev_requirement' => false, 'replaced' => array( - 0 => '9.4.1', + 0 => '9.4.3', ), ), 'drupal/core-assertion' => array( 'dev_requirement' => false, 'replaced' => array( - 0 => '9.4.1', + 0 => '9.4.3', ), ), 'drupal/core-bridge' => array( 'dev_requirement' => false, 'replaced' => array( - 0 => '9.4.1', + 0 => '9.4.3', ), ), 'drupal/core-class-finder' => array( 'dev_requirement' => false, 'replaced' => array( - 0 => '9.4.1', + 0 => '9.4.3', ), ), 'drupal/core-composer-scaffold' => array( @@ -649,97 +649,97 @@ 'drupal/core-datetime' => array( 'dev_requirement' => false, 'replaced' => array( - 0 => '9.4.1', + 0 => '9.4.3', ), ), 'drupal/core-dependency-injection' => array( 'dev_requirement' => false, 'replaced' => array( - 0 => '9.4.1', + 0 => '9.4.3', ), ), 'drupal/core-diff' => array( 'dev_requirement' => false, 'replaced' => array( - 0 => '9.4.1', + 0 => '9.4.3', ), ), 'drupal/core-discovery' => array( 'dev_requirement' => false, 'replaced' => array( - 0 => '9.4.1', + 0 => '9.4.3', ), ), 'drupal/core-event-dispatcher' => array( 'dev_requirement' => false, 'replaced' => array( - 0 => '9.4.1', + 0 => '9.4.3', ), ), 'drupal/core-file-cache' => array( 'dev_requirement' => false, 'replaced' => array( - 0 => '9.4.1', + 0 => '9.4.3', ), ), 'drupal/core-file-security' => array( 'dev_requirement' => false, 'replaced' => array( - 0 => '9.4.1', + 0 => '9.4.3', ), ), 'drupal/core-filesystem' => array( 'dev_requirement' => false, 'replaced' => array( - 0 => '9.4.1', + 0 => '9.4.3', ), ), 'drupal/core-front-matter' => array( 'dev_requirement' => false, 'replaced' => array( - 0 => '9.4.1', + 0 => '9.4.3', ), ), 'drupal/core-gettext' => array( 'dev_requirement' => false, 'replaced' => array( - 0 => '9.4.1', + 0 => '9.4.3', ), ), 'drupal/core-graph' => array( 'dev_requirement' => false, 'replaced' => array( - 0 => '9.4.1', + 0 => '9.4.3', ), ), 'drupal/core-http-foundation' => array( 'dev_requirement' => false, 'replaced' => array( - 0 => '9.4.1', + 0 => '9.4.3', ), ), 'drupal/core-php-storage' => array( 'dev_requirement' => false, 'replaced' => array( - 0 => '9.4.1', + 0 => '9.4.3', ), ), 'drupal/core-plugin' => array( 'dev_requirement' => false, 'replaced' => array( - 0 => '9.4.1', + 0 => '9.4.3', ), ), 'drupal/core-proxy-builder' => array( 'dev_requirement' => false, 'replaced' => array( - 0 => '9.4.1', + 0 => '9.4.3', ), ), 'drupal/core-recommended' => array( - 'pretty_version' => '9.4.1', - 'version' => '9.4.1.0', - 'reference' => 'a3ae54715ba7792fe596c2f6a73dfcef217b0577', + 'pretty_version' => '9.4.3', + 'version' => '9.4.3.0', + 'reference' => 'ff8662af0a5963a88ea856e9786e17a51f8e640c', 'type' => 'metapackage', 'install_path' => NULL, 'aliases' => array(), @@ -748,37 +748,37 @@ 'drupal/core-render' => array( 'dev_requirement' => false, 'replaced' => array( - 0 => '9.4.1', + 0 => '9.4.3', ), ), 'drupal/core-serialization' => array( 'dev_requirement' => false, 'replaced' => array( - 0 => '9.4.1', + 0 => '9.4.3', ), ), 'drupal/core-transliteration' => array( 'dev_requirement' => false, 'replaced' => array( - 0 => '9.4.1', + 0 => '9.4.3', ), ), 'drupal/core-utility' => array( 'dev_requirement' => false, 'replaced' => array( - 0 => '9.4.1', + 0 => '9.4.3', ), ), 'drupal/core-uuid' => array( 'dev_requirement' => false, 'replaced' => array( - 0 => '9.4.1', + 0 => '9.4.3', ), ), 'drupal/core-version' => array( 'dev_requirement' => false, 'replaced' => array( - 0 => '9.4.1', + 0 => '9.4.3', ), ), 'drupal/crop' => array( @@ -802,19 +802,19 @@ 'drupal/datetime' => array( 'dev_requirement' => false, 'replaced' => array( - 0 => '9.4.1', + 0 => '9.4.3', ), ), 'drupal/datetime_range' => array( 'dev_requirement' => false, 'replaced' => array( - 0 => '9.4.1', + 0 => '9.4.3', ), ), 'drupal/dblog' => array( 'dev_requirement' => false, 'replaced' => array( - 0 => '9.4.1', + 0 => '9.4.3', ), ), 'drupal/dropzonejs' => array( @@ -838,13 +838,13 @@ 'drupal/dynamic_page_cache' => array( 'dev_requirement' => false, 'replaced' => array( - 0 => '9.4.1', + 0 => '9.4.3', ), ), 'drupal/editor' => array( 'dev_requirement' => false, 'replaced' => array( - 0 => '9.4.1', + 0 => '9.4.3', ), ), 'drupal/editor_advanced_link' => array( @@ -913,7 +913,7 @@ 'drupal/entity_reference' => array( 'dev_requirement' => false, 'replaced' => array( - 0 => '9.4.1', + 0 => '9.4.3', ), ), 'drupal/entity_reference_revisions' => array( @@ -946,7 +946,7 @@ 'drupal/field' => array( 'dev_requirement' => false, 'replaced' => array( - 0 => '9.4.1', + 0 => '9.4.3', ), ), 'drupal/field_group' => array( @@ -961,7 +961,7 @@ 'drupal/field_layout' => array( 'dev_requirement' => false, 'replaced' => array( - 0 => '9.4.1', + 0 => '9.4.3', ), ), 'drupal/field_permissions' => array( @@ -976,13 +976,13 @@ 'drupal/field_ui' => array( 'dev_requirement' => false, 'replaced' => array( - 0 => '9.4.1', + 0 => '9.4.3', ), ), 'drupal/file' => array( 'dev_requirement' => false, 'replaced' => array( - 0 => '9.4.1', + 0 => '9.4.3', ), ), 'drupal/file_browser' => array( @@ -997,7 +997,7 @@ 'drupal/filter' => array( 'dev_requirement' => false, 'replaced' => array( - 0 => '9.4.1', + 0 => '9.4.3', ), ), 'drupal/focal_point' => array( @@ -1012,7 +1012,7 @@ 'drupal/forum' => array( 'dev_requirement' => false, 'replaced' => array( - 0 => '9.4.1', + 0 => '9.4.3', ), ), 'drupal/google_analytics' => array( @@ -1036,25 +1036,25 @@ 'drupal/hal' => array( 'dev_requirement' => false, 'replaced' => array( - 0 => '9.4.1', + 0 => '9.4.3', ), ), 'drupal/help' => array( 'dev_requirement' => false, 'replaced' => array( - 0 => '9.4.1', + 0 => '9.4.3', ), ), 'drupal/help_topics' => array( 'dev_requirement' => false, 'replaced' => array( - 0 => '9.4.1', + 0 => '9.4.3', ), ), 'drupal/history' => array( 'dev_requirement' => false, 'replaced' => array( - 0 => '9.4.1', + 0 => '9.4.3', ), ), 'drupal/honeypot' => array( @@ -1069,7 +1069,7 @@ 'drupal/image' => array( 'dev_requirement' => false, 'replaced' => array( - 0 => '9.4.1', + 0 => '9.4.3', ), ), 'drupal/inline_entity_form' => array( @@ -1084,7 +1084,7 @@ 'drupal/inline_form_errors' => array( 'dev_requirement' => false, 'replaced' => array( - 0 => '9.4.1', + 0 => '9.4.3', ), ), 'drupal/jquery_ui' => array( @@ -1126,25 +1126,25 @@ 'drupal/jsonapi' => array( 'dev_requirement' => false, 'replaced' => array( - 0 => '9.4.1', + 0 => '9.4.3', ), ), 'drupal/language' => array( 'dev_requirement' => false, 'replaced' => array( - 0 => '9.4.1', + 0 => '9.4.3', ), ), 'drupal/layout_builder' => array( 'dev_requirement' => false, 'replaced' => array( - 0 => '9.4.1', + 0 => '9.4.3', ), ), 'drupal/layout_discovery' => array( 'dev_requirement' => false, 'replaced' => array( - 0 => '9.4.1', + 0 => '9.4.3', ), ), 'drupal/libraries' => array( @@ -1159,7 +1159,7 @@ 'drupal/link' => array( 'dev_requirement' => false, 'replaced' => array( - 0 => '9.4.1', + 0 => '9.4.3', ), ), 'drupal/link_attributes' => array( @@ -1183,7 +1183,7 @@ 'drupal/locale' => array( 'dev_requirement' => false, 'replaced' => array( - 0 => '9.4.1', + 0 => '9.4.3', ), ), 'drupal/mathjax' => array( @@ -1198,7 +1198,7 @@ 'drupal/media' => array( 'dev_requirement' => false, 'replaced' => array( - 0 => '9.4.1', + 0 => '9.4.3', ), ), 'drupal/media_entity_browser' => array( @@ -1231,7 +1231,7 @@ 'drupal/media_library' => array( 'dev_requirement' => false, 'replaced' => array( - 0 => '9.4.1', + 0 => '9.4.3', ), ), 'drupal/menu_block' => array( @@ -1255,13 +1255,13 @@ 'drupal/menu_link_content' => array( 'dev_requirement' => false, 'replaced' => array( - 0 => '9.4.1', + 0 => '9.4.3', ), ), 'drupal/menu_ui' => array( 'dev_requirement' => false, 'replaced' => array( - 0 => '9.4.1', + 0 => '9.4.3', ), ), 'drupal/metatag' => array( @@ -1276,7 +1276,7 @@ 'drupal/migrate' => array( 'dev_requirement' => false, 'replaced' => array( - 0 => '9.4.1', + 0 => '9.4.3', ), ), 'drupal/migrate_devel' => array( @@ -1291,19 +1291,19 @@ 'drupal/migrate_drupal' => array( 'dev_requirement' => false, 'replaced' => array( - 0 => '9.4.1', + 0 => '9.4.3', ), ), 'drupal/migrate_drupal_multilingual' => array( 'dev_requirement' => false, 'replaced' => array( - 0 => '9.4.1', + 0 => '9.4.3', ), ), 'drupal/migrate_drupal_ui' => array( 'dev_requirement' => false, 'replaced' => array( - 0 => '9.4.1', + 0 => '9.4.3', ), ), 'drupal/migrate_plus' => array( @@ -1327,7 +1327,7 @@ 'drupal/minimal' => array( 'dev_requirement' => false, 'replaced' => array( - 0 => '9.4.1', + 0 => '9.4.3', ), ), 'drupal/mobile_detect' => array( @@ -1369,31 +1369,31 @@ 'drupal/mysql' => array( 'dev_requirement' => false, 'replaced' => array( - 0 => '9.4.1', + 0 => '9.4.3', ), ), 'drupal/node' => array( 'dev_requirement' => false, 'replaced' => array( - 0 => '9.4.1', + 0 => '9.4.3', ), ), 'drupal/olivero' => array( 'dev_requirement' => false, 'replaced' => array( - 0 => '9.4.1', + 0 => '9.4.3', ), ), 'drupal/options' => array( 'dev_requirement' => false, 'replaced' => array( - 0 => '9.4.1', + 0 => '9.4.3', ), ), 'drupal/page_cache' => array( 'dev_requirement' => false, 'replaced' => array( - 0 => '9.4.1', + 0 => '9.4.3', ), ), 'drupal/pantheon_advanced_page_cache' => array( @@ -1417,13 +1417,13 @@ 'drupal/path' => array( 'dev_requirement' => false, 'replaced' => array( - 0 => '9.4.1', + 0 => '9.4.3', ), ), 'drupal/path_alias' => array( 'dev_requirement' => false, 'replaced' => array( - 0 => '9.4.1', + 0 => '9.4.3', ), ), 'drupal/pathauto' => array( @@ -1438,7 +1438,7 @@ 'drupal/pgsql' => array( 'dev_requirement' => false, 'replaced' => array( - 0 => '9.4.1', + 0 => '9.4.3', ), ), 'drupal/queue_mail' => array( @@ -1453,13 +1453,13 @@ 'drupal/quickedit' => array( 'dev_requirement' => false, 'replaced' => array( - 0 => '9.4.1', + 0 => '9.4.3', ), ), 'drupal/rdf' => array( 'dev_requirement' => false, 'replaced' => array( - 0 => '9.4.1', + 0 => '9.4.3', ), ), 'drupal/rebuild_cache_access' => array( @@ -1501,13 +1501,13 @@ 'drupal/responsive_image' => array( 'dev_requirement' => false, 'replaced' => array( - 0 => '9.4.1', + 0 => '9.4.3', ), ), 'drupal/rest' => array( 'dev_requirement' => false, 'replaced' => array( - 0 => '9.4.1', + 0 => '9.4.3', ), ), 'drupal/roleassign' => array( @@ -1531,7 +1531,7 @@ 'drupal/search' => array( 'dev_requirement' => false, 'replaced' => array( - 0 => '9.4.1', + 0 => '9.4.3', ), ), 'drupal/search_api' => array( @@ -1555,25 +1555,25 @@ 'drupal/serialization' => array( 'dev_requirement' => false, 'replaced' => array( - 0 => '9.4.1', + 0 => '9.4.3', ), ), 'drupal/settings_tray' => array( 'dev_requirement' => false, 'replaced' => array( - 0 => '9.4.1', + 0 => '9.4.3', ), ), 'drupal/seven' => array( 'dev_requirement' => false, 'replaced' => array( - 0 => '9.4.1', + 0 => '9.4.3', ), ), 'drupal/shortcut' => array( 'dev_requirement' => false, 'replaced' => array( - 0 => '9.4.1', + 0 => '9.4.3', ), ), 'drupal/simple_gmap' => array( @@ -1642,25 +1642,25 @@ 'drupal/sqlite' => array( 'dev_requirement' => false, 'replaced' => array( - 0 => '9.4.1', + 0 => '9.4.3', ), ), 'drupal/standard' => array( 'dev_requirement' => false, 'replaced' => array( - 0 => '9.4.1', + 0 => '9.4.3', ), ), 'drupal/stark' => array( 'dev_requirement' => false, 'replaced' => array( - 0 => '9.4.1', + 0 => '9.4.3', ), ), 'drupal/statistics' => array( 'dev_requirement' => false, 'replaced' => array( - 0 => '9.4.1', + 0 => '9.4.3', ), ), 'drupal/superfish' => array( @@ -1684,31 +1684,31 @@ 'drupal/syslog' => array( 'dev_requirement' => false, 'replaced' => array( - 0 => '9.4.1', + 0 => '9.4.3', ), ), 'drupal/system' => array( 'dev_requirement' => false, 'replaced' => array( - 0 => '9.4.1', + 0 => '9.4.3', ), ), 'drupal/taxonomy' => array( 'dev_requirement' => false, 'replaced' => array( - 0 => '9.4.1', + 0 => '9.4.3', ), ), 'drupal/telephone' => array( 'dev_requirement' => false, 'replaced' => array( - 0 => '9.4.1', + 0 => '9.4.3', ), ), 'drupal/text' => array( 'dev_requirement' => false, 'replaced' => array( - 0 => '9.4.1', + 0 => '9.4.3', ), ), 'drupal/token' => array( @@ -1723,19 +1723,19 @@ 'drupal/toolbar' => array( 'dev_requirement' => false, 'replaced' => array( - 0 => '9.4.1', + 0 => '9.4.3', ), ), 'drupal/tour' => array( 'dev_requirement' => false, 'replaced' => array( - 0 => '9.4.1', + 0 => '9.4.3', ), ), 'drupal/tracker' => array( 'dev_requirement' => false, 'replaced' => array( - 0 => '9.4.1', + 0 => '9.4.3', ), ), 'drupal/twig_tweak' => array( @@ -1768,13 +1768,13 @@ 'drupal/update' => array( 'dev_requirement' => false, 'replaced' => array( - 0 => '9.4.1', + 0 => '9.4.3', ), ), 'drupal/user' => array( 'dev_requirement' => false, 'replaced' => array( - 0 => '9.4.1', + 0 => '9.4.3', ), ), 'drupal/userprotect' => array( @@ -1807,7 +1807,7 @@ 'drupal/views' => array( 'dev_requirement' => false, 'replaced' => array( - 0 => '9.4.1', + 0 => '9.4.3', ), ), 'drupal/views_ajax_history' => array( @@ -1867,7 +1867,7 @@ 'drupal/views_ui' => array( 'dev_requirement' => false, 'replaced' => array( - 0 => '9.4.1', + 0 => '9.4.3', ), ), 'drupal/webform' => array( @@ -1882,13 +1882,13 @@ 'drupal/workflows' => array( 'dev_requirement' => false, 'replaced' => array( - 0 => '9.4.1', + 0 => '9.4.3', ), ), 'drupal/workspaces' => array( 'dev_requirement' => false, 'replaced' => array( - 0 => '9.4.1', + 0 => '9.4.3', ), ), 'drush-ops/behat-drush-endpoint' => array( @@ -2027,9 +2027,9 @@ 'dev_requirement' => false, ), 'laminas/laminas-diactoros' => array( - 'pretty_version' => '2.11.0', - 'version' => '2.11.0.0', - 'reference' => 'd1bc565b23c2040fafde398a8a5db083c47928c0', + 'pretty_version' => '2.11.3', + 'version' => '2.11.3.0', + 'reference' => '1f97b0c52eafd108e09c76d6b29d83ef4a855f76', 'type' => 'library', 'install_path' => __DIR__ . '/../laminas/laminas-diactoros', 'aliases' => array(), @@ -2125,7 +2125,7 @@ 'osu-asc-webservices/d8-upstream' => array( 'pretty_version' => 'dev-master', 'version' => 'dev-master', - 'reference' => '07a7c2435c9d4e8234762b2e1e5bea728ccd9e76', + 'reference' => 'f3adbe0a3bfef44fba6e4ed128a583c42dc7445f', 'type' => 'project', 'install_path' => __DIR__ . '/../../', 'aliases' => array(), @@ -2676,8 +2676,8 @@ 'dev_requirement' => false, ), 'symfony/deprecation-contracts' => array( - 'pretty_version' => 'v2.5.1', - 'version' => '2.5.1.0', + 'pretty_version' => 'v2.5.2', + 'version' => '2.5.2.0', 'reference' => 'e8b495ea28c1d97b5e0c121748d6f9b53d075c66', 'type' => 'library', 'install_path' => __DIR__ . '/../symfony/deprecation-contracts', @@ -2712,8 +2712,8 @@ 'dev_requirement' => false, ), 'symfony/event-dispatcher-contracts' => array( - 'pretty_version' => 'v1.1.12', - 'version' => '1.1.12.0', + 'pretty_version' => 'v1.1.13', + 'version' => '1.1.13.0', 'reference' => '1d5cd762abaa6b2a4169d3e77610193a7157129e', 'type' => 'library', 'install_path' => __DIR__ . '/../symfony/event-dispatcher-contracts', @@ -2745,9 +2745,9 @@ 'dev_requirement' => false, ), 'symfony/http-client-contracts' => array( - 'pretty_version' => 'v2.5.1', - 'version' => '2.5.1.0', - 'reference' => '1a4f708e4e87f335d1b1be6148060739152f0bd5', + 'pretty_version' => 'v2.5.2', + 'version' => '2.5.2.0', + 'reference' => 'ba6a9f0e8f3edd190520ee3b9a958596b6ca2e70', 'type' => 'library', 'install_path' => __DIR__ . '/../symfony/http-client-contracts', 'aliases' => array(), @@ -2898,9 +2898,9 @@ 'dev_requirement' => false, ), 'symfony/service-contracts' => array( - 'pretty_version' => 'v2.5.1', - 'version' => '2.5.1.0', - 'reference' => '24d9dc654b83e91aa59f9d167b131bc3b5bea24c', + 'pretty_version' => 'v2.5.2', + 'version' => '2.5.2.0', + 'reference' => '4b426aac47d6427cc1a1d0f7e2ac724627f5966c', 'type' => 'library', 'install_path' => __DIR__ . '/../symfony/service-contracts', 'aliases' => array(), @@ -2922,9 +2922,9 @@ 'dev_requirement' => false, ), 'symfony/translation-contracts' => array( - 'pretty_version' => 'v2.5.1', - 'version' => '2.5.1.0', - 'reference' => '1211df0afa701e45a04253110e959d4af4ef0f07', + 'pretty_version' => 'v2.5.2', + 'version' => '2.5.2.0', + 'reference' => '136b19dd05cdf0709db6537d058bcab6dd6e2dbe', 'type' => 'library', 'install_path' => __DIR__ . '/../symfony/translation-contracts', 'aliases' => array(), diff --git a/vendor/doctrine/annotations/composer.json b/vendor/doctrine/annotations/composer.json index 00d0231075a1116538b27cc437f27e6da28d5bd8..b4dfbd390def5de22f6bd2d7a80ede5c1d6e9c1b 100644 --- a/vendor/doctrine/annotations/composer.json +++ b/vendor/doctrine/annotations/composer.json @@ -1,17 +1,36 @@ { "name": "doctrine/annotations", - "type": "library", "description": "Docblock Annotations Parser", - "keywords": ["annotations", "docblock", "parser"], - "homepage": "https://www.doctrine-project.org/projects/annotations.html", "license": "MIT", + "type": "library", + "keywords": [ + "annotations", + "docblock", + "parser" + ], "authors": [ - {"name": "Guilherme Blanco", "email": "guilhermeblanco@gmail.com"}, - {"name": "Roman Borschel", "email": "roman@code-factory.org"}, - {"name": "Benjamin Eberlei", "email": "kontakt@beberlei.de"}, - {"name": "Jonathan Wage", "email": "jonwage@gmail.com"}, - {"name": "Johannes Schmitt", "email": "schmittjoh@gmail.com"} + { + "name": "Guilherme Blanco", + "email": "guilhermeblanco@gmail.com" + }, + { + "name": "Roman Borschel", + "email": "roman@code-factory.org" + }, + { + "name": "Benjamin Eberlei", + "email": "kontakt@beberlei.de" + }, + { + "name": "Jonathan Wage", + "email": "jonwage@gmail.com" + }, + { + "name": "Johannes Schmitt", + "email": "schmittjoh@gmail.com" + } ], + "homepage": "https://www.doctrine-project.org/projects/annotations.html", "require": { "php": "^7.1 || ^8.0", "ext-tokenizer": "*", @@ -21,15 +40,15 @@ "require-dev": { "doctrine/cache": "^1.11 || ^2.0", "doctrine/coding-standard": "^6.0 || ^8.1", - "phpstan/phpstan": "^0.12.20", + "phpstan/phpstan": "^1.4.10 || ^1.8.0", "phpunit/phpunit": "^7.5 || ^8.0 || ^9.1.5", - "symfony/cache": "^4.4 || ^5.2" - }, - "config": { - "sort-packages": true + "symfony/cache": "^4.4 || ^5.2", + "vimeo/psalm": "^4.10" }, "autoload": { - "psr-4": { "Doctrine\\Common\\Annotations\\": "lib/Doctrine/Common/Annotations" } + "psr-4": { + "Doctrine\\Common\\Annotations\\": "lib/Doctrine/Common/Annotations" + } }, "autoload-dev": { "psr-4": { @@ -40,5 +59,11 @@ "tests/Doctrine/Tests/Common/Annotations/Fixtures/functions.php", "tests/Doctrine/Tests/Common/Annotations/Fixtures/SingleClassLOC1000.php" ] + }, + "config": { + "allow-plugins": { + "dealerdirect/phpcodesniffer-composer-installer": true + }, + "sort-packages": true } } diff --git a/vendor/doctrine/annotations/lib/Doctrine/Common/Annotations/AnnotationException.php b/vendor/doctrine/annotations/lib/Doctrine/Common/Annotations/AnnotationException.php index b1ea64e6f5f959c1484c318f7c55ef1ccb06ac53..4d91825e560481aa33781cc841e41b705fb5fcb4 100644 --- a/vendor/doctrine/annotations/lib/Doctrine/Common/Annotations/AnnotationException.php +++ b/vendor/doctrine/annotations/lib/Doctrine/Common/Annotations/AnnotationException.php @@ -3,6 +3,7 @@ namespace Doctrine\Common\Annotations; use Exception; +use Throwable; use function get_class; use function gettype; @@ -47,9 +48,9 @@ public static function semanticalError($message) * * @return AnnotationException */ - public static function creationError($message) + public static function creationError($message, ?Throwable $previous = null) { - return new self('[Creation Error] ' . $message); + return new self('[Creation Error] ' . $message, 0, $previous); } /** diff --git a/vendor/doctrine/annotations/lib/Doctrine/Common/Annotations/DocParser.php b/vendor/doctrine/annotations/lib/Doctrine/Common/Annotations/DocParser.php index ae530c50f57cc7530aaa0fd88f3cb07746b862a2..80f307caba39cb39ab2019362d8f2235604bc0cc 100644 --- a/vendor/doctrine/annotations/lib/Doctrine/Common/Annotations/DocParser.php +++ b/vendor/doctrine/annotations/lib/Doctrine/Common/Annotations/DocParser.php @@ -12,6 +12,7 @@ use ReflectionProperty; use RuntimeException; use stdClass; +use Throwable; use function array_keys; use function array_map; @@ -941,7 +942,7 @@ private function Annotation() if (self::$annotationMetadata[$name]['has_named_argument_constructor']) { if (PHP_VERSION_ID >= 80000) { - return new $name(...$values); + return $this->instantiateAnnotiation($originalName, $this->context, $name, $values); } $positionalValues = []; @@ -968,16 +969,16 @@ private function Annotation() $positionalValues[self::$annotationMetadata[$name]['constructor_args'][$property]['position']] = $value; } - return new $name(...$positionalValues); + return $this->instantiateAnnotiation($originalName, $this->context, $name, $positionalValues); } // check if the annotation expects values via the constructor, // or directly injected into public properties if (self::$annotationMetadata[$name]['has_constructor'] === true) { - return new $name($values); + return $this->instantiateAnnotiation($originalName, $this->context, $name, [$values]); } - $instance = new $name(); + $instance = $this->instantiateAnnotiation($originalName, $this->context, $name, []); foreach ($values as $property => $value) { if (! isset(self::$annotationMetadata[$name]['properties'][$property])) { @@ -1456,4 +1457,31 @@ private function resolvePositionalValues(array $arguments, string $name): array return $values; } + + /** + * Try to instantiate the annotation and catch and process any exceptions related to failure + * + * @param class-string $name + * @param array<string,mixed> $arguments + * + * @return object + * + * @throws AnnotationException + */ + private function instantiateAnnotiation(string $originalName, string $context, string $name, array $arguments) + { + try { + return new $name(...$arguments); + } catch (Throwable $exception) { + throw AnnotationException::creationError( + sprintf( + 'An error occurred while instantiating the annotation @%s declared on %s: "%s".', + $originalName, + $context, + $exception->getMessage() + ), + $exception + ); + } + } } diff --git a/vendor/doctrine/annotations/lib/Doctrine/Common/Annotations/ImplicitlyIgnoredAnnotationNames.php b/vendor/doctrine/annotations/lib/Doctrine/Common/Annotations/ImplicitlyIgnoredAnnotationNames.php index 2efeb1d22165bdf664083481c23dd6d0e3657b8b..ab27f8a5cdc0c9b27b6bac79a42e1bc680dca02b 100644 --- a/vendor/doctrine/annotations/lib/Doctrine/Common/Annotations/ImplicitlyIgnoredAnnotationNames.php +++ b/vendor/doctrine/annotations/lib/Doctrine/Common/Annotations/ImplicitlyIgnoredAnnotationNames.php @@ -147,6 +147,7 @@ final class ImplicitlyIgnoredAnnotationNames // PHPStan, Psalm 'extends' => true, 'implements' => true, + 'readonly' => true, 'template' => true, 'use' => true, diff --git a/vendor/doctrine/annotations/lib/Doctrine/Common/Annotations/IndexedReader.php b/vendor/doctrine/annotations/lib/Doctrine/Common/Annotations/IndexedReader.php index 42e70765db7eb036132fd5effaef4ee73e050daf..62dcf7487b28b322a43765b7d4b1f880d5696222 100644 --- a/vendor/doctrine/annotations/lib/Doctrine/Common/Annotations/IndexedReader.php +++ b/vendor/doctrine/annotations/lib/Doctrine/Common/Annotations/IndexedReader.php @@ -38,9 +38,9 @@ public function getClassAnnotations(ReflectionClass $class) /** * {@inheritDoc} */ - public function getClassAnnotation(ReflectionClass $class, $annotation) + public function getClassAnnotation(ReflectionClass $class, $annotationName) { - return $this->delegate->getClassAnnotation($class, $annotation); + return $this->delegate->getClassAnnotation($class, $annotationName); } /** @@ -59,9 +59,9 @@ public function getMethodAnnotations(ReflectionMethod $method) /** * {@inheritDoc} */ - public function getMethodAnnotation(ReflectionMethod $method, $annotation) + public function getMethodAnnotation(ReflectionMethod $method, $annotationName) { - return $this->delegate->getMethodAnnotation($method, $annotation); + return $this->delegate->getMethodAnnotation($method, $annotationName); } /** @@ -80,9 +80,9 @@ public function getPropertyAnnotations(ReflectionProperty $property) /** * {@inheritDoc} */ - public function getPropertyAnnotation(ReflectionProperty $property, $annotation) + public function getPropertyAnnotation(ReflectionProperty $property, $annotationName) { - return $this->delegate->getPropertyAnnotation($property, $annotation); + return $this->delegate->getPropertyAnnotation($property, $annotationName); } /** diff --git a/vendor/doctrine/annotations/psalm.xml b/vendor/doctrine/annotations/psalm.xml new file mode 100644 index 0000000000000000000000000000000000000000..e6af3892387744afa95a49d59498929bde5da218 --- /dev/null +++ b/vendor/doctrine/annotations/psalm.xml @@ -0,0 +1,15 @@ +<?xml version="1.0"?> +<psalm + errorLevel="7" + resolveFromConfigFile="true" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xmlns="https://getpsalm.org/schema/config" + xsi:schemaLocation="https://getpsalm.org/schema/config vendor/vimeo/psalm/config.xsd" +> + <projectFiles> + <directory name="lib/Doctrine/Common/Annotations" /> + <ignoreFiles> + <directory name="vendor" /> + </ignoreFiles> + </projectFiles> +</psalm> diff --git a/vendor/laminas/laminas-diactoros/composer.lock b/vendor/laminas/laminas-diactoros/composer.lock index 6f00fc023ea8819d579f60d70447a017c97e22f4..738c3e556ab9eb1d6a32f007c944c0f11fd00d25 100644 --- a/vendor/laminas/laminas-diactoros/composer.lock +++ b/vendor/laminas/laminas-diactoros/composer.lock @@ -357,30 +357,30 @@ }, { "name": "composer/pcre", - "version": "1.0.1", + "version": "2.0.0", "source": { "type": "git", "url": "https://github.com/composer/pcre.git", - "reference": "67a32d7d6f9f560b726ab25a061b38ff3a80c560" + "reference": "c8e9d27cfc5ed22643c19c160455b473ffd8aabe" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/pcre/zipball/67a32d7d6f9f560b726ab25a061b38ff3a80c560", - "reference": "67a32d7d6f9f560b726ab25a061b38ff3a80c560", + "url": "https://api.github.com/repos/composer/pcre/zipball/c8e9d27cfc5ed22643c19c160455b473ffd8aabe", + "reference": "c8e9d27cfc5ed22643c19c160455b473ffd8aabe", "shasum": "" }, "require": { - "php": "^5.3.2 || ^7.0 || ^8.0" + "php": "^7.2 || ^8.0" }, "require-dev": { "phpstan/phpstan": "^1.3", "phpstan/phpstan-strict-rules": "^1.1", - "symfony/phpunit-bridge": "^4.2 || ^5" + "symfony/phpunit-bridge": "^5" }, "type": "library", "extra": { "branch-alias": { - "dev-main": "1.x-dev" + "dev-main": "2.x-dev" } }, "autoload": { @@ -408,7 +408,7 @@ ], "support": { "issues": "https://github.com/composer/pcre/issues", - "source": "https://github.com/composer/pcre/tree/1.0.1" + "source": "https://github.com/composer/pcre/tree/2.0.0" }, "funding": [ { @@ -424,20 +424,20 @@ "type": "tidelift" } ], - "time": "2022-01-21T20:24:37+00:00" + "time": "2022-02-25T20:05:29+00:00" }, { "name": "composer/semver", - "version": "3.2.9", + "version": "3.3.2", "source": { "type": "git", "url": "https://github.com/composer/semver.git", - "reference": "a951f614bd64dcd26137bc9b7b2637ddcfc57649" + "reference": "3953f23262f2bff1919fc82183ad9acb13ff62c9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/semver/zipball/a951f614bd64dcd26137bc9b7b2637ddcfc57649", - "reference": "a951f614bd64dcd26137bc9b7b2637ddcfc57649", + "url": "https://api.github.com/repos/composer/semver/zipball/3953f23262f2bff1919fc82183ad9acb13ff62c9", + "reference": "3953f23262f2bff1919fc82183ad9acb13ff62c9", "shasum": "" }, "require": { @@ -489,7 +489,7 @@ "support": { "irc": "irc://irc.freenode.org/composer", "issues": "https://github.com/composer/semver/issues", - "source": "https://github.com/composer/semver/tree/3.2.9" + "source": "https://github.com/composer/semver/tree/3.3.2" }, "funding": [ { @@ -505,24 +505,24 @@ "type": "tidelift" } ], - "time": "2022-02-04T13:58:43+00:00" + "time": "2022-04-01T19:23:25+00:00" }, { "name": "composer/xdebug-handler", - "version": "3.0.1", + "version": "3.0.3", "source": { "type": "git", "url": "https://github.com/composer/xdebug-handler.git", - "reference": "12f1b79476638a5615ed00ea6adbb269cec96fd8" + "reference": "ced299686f41dce890debac69273b47ffe98a40c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/xdebug-handler/zipball/12f1b79476638a5615ed00ea6adbb269cec96fd8", - "reference": "12f1b79476638a5615ed00ea6adbb269cec96fd8", + "url": "https://api.github.com/repos/composer/xdebug-handler/zipball/ced299686f41dce890debac69273b47ffe98a40c", + "reference": "ced299686f41dce890debac69273b47ffe98a40c", "shasum": "" }, "require": { - "composer/pcre": "^1", + "composer/pcre": "^1 || ^2 || ^3", "php": "^7.2.5 || ^8.0", "psr/log": "^1 || ^2 || ^3" }, @@ -555,7 +555,7 @@ "support": { "irc": "irc://irc.freenode.org/composer", "issues": "https://github.com/composer/xdebug-handler/issues", - "source": "https://github.com/composer/xdebug-handler/tree/3.0.1" + "source": "https://github.com/composer/xdebug-handler/tree/3.0.3" }, "funding": [ { @@ -571,7 +571,7 @@ "type": "tidelift" } ], - "time": "2022-01-04T18:29:42+00:00" + "time": "2022-02-25T21:32:43+00:00" }, { "name": "dnoegel/php-xdg-base-dir", @@ -612,29 +612,30 @@ }, { "name": "doctrine/instantiator", - "version": "1.4.0", + "version": "1.4.1", "source": { "type": "git", "url": "https://github.com/doctrine/instantiator.git", - "reference": "d56bf6102915de5702778fe20f2de3b2fe570b5b" + "reference": "10dcfce151b967d20fde1b34ae6640712c3891bc" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/instantiator/zipball/d56bf6102915de5702778fe20f2de3b2fe570b5b", - "reference": "d56bf6102915de5702778fe20f2de3b2fe570b5b", + "url": "https://api.github.com/repos/doctrine/instantiator/zipball/10dcfce151b967d20fde1b34ae6640712c3891bc", + "reference": "10dcfce151b967d20fde1b34ae6640712c3891bc", "shasum": "" }, "require": { "php": "^7.1 || ^8.0" }, "require-dev": { - "doctrine/coding-standard": "^8.0", + "doctrine/coding-standard": "^9", "ext-pdo": "*", "ext-phar": "*", - "phpbench/phpbench": "^0.13 || 1.0.0-alpha2", - "phpstan/phpstan": "^0.12", - "phpstan/phpstan-phpunit": "^0.12", - "phpunit/phpunit": "^7.0 || ^8.0 || ^9.0" + "phpbench/phpbench": "^0.16 || ^1", + "phpstan/phpstan": "^1.4", + "phpstan/phpstan-phpunit": "^1", + "phpunit/phpunit": "^7.5 || ^8.5 || ^9.5", + "vimeo/psalm": "^4.22" }, "type": "library", "autoload": { @@ -661,7 +662,7 @@ ], "support": { "issues": "https://github.com/doctrine/instantiator/issues", - "source": "https://github.com/doctrine/instantiator/tree/1.4.0" + "source": "https://github.com/doctrine/instantiator/tree/1.4.1" }, "funding": [ { @@ -677,7 +678,7 @@ "type": "tidelift" } ], - "time": "2020-11-10T18:47:58+00:00" + "time": "2022-03-03T08:28:38+00:00" }, { "name": "felixfbecker/advanced-json-rpc", @@ -726,16 +727,16 @@ }, { "name": "felixfbecker/language-server-protocol", - "version": "1.5.1", + "version": "v1.5.2", "source": { "type": "git", "url": "https://github.com/felixfbecker/php-language-server-protocol.git", - "reference": "9d846d1f5cf101deee7a61c8ba7caa0a975cd730" + "reference": "6e82196ffd7c62f7794d778ca52b69feec9f2842" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/felixfbecker/php-language-server-protocol/zipball/9d846d1f5cf101deee7a61c8ba7caa0a975cd730", - "reference": "9d846d1f5cf101deee7a61c8ba7caa0a975cd730", + "url": "https://api.github.com/repos/felixfbecker/php-language-server-protocol/zipball/6e82196ffd7c62f7794d778ca52b69feec9f2842", + "reference": "6e82196ffd7c62f7794d778ca52b69feec9f2842", "shasum": "" }, "require": { @@ -776,9 +777,9 @@ ], "support": { "issues": "https://github.com/felixfbecker/php-language-server-protocol/issues", - "source": "https://github.com/felixfbecker/php-language-server-protocol/tree/1.5.1" + "source": "https://github.com/felixfbecker/php-language-server-protocol/tree/v1.5.2" }, - "time": "2021-02-22T14:02:09+00:00" + "time": "2022-03-02T22:36:06+00:00" }, { "name": "http-interop/http-factory-tests", @@ -935,25 +936,29 @@ }, { "name": "myclabs/deep-copy", - "version": "1.10.2", + "version": "1.11.0", "source": { "type": "git", "url": "https://github.com/myclabs/DeepCopy.git", - "reference": "776f831124e9c62e1a2c601ecc52e776d8bb7220" + "reference": "14daed4296fae74d9e3201d2c4925d1acb7aa614" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/776f831124e9c62e1a2c601ecc52e776d8bb7220", - "reference": "776f831124e9c62e1a2c601ecc52e776d8bb7220", + "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/14daed4296fae74d9e3201d2c4925d1acb7aa614", + "reference": "14daed4296fae74d9e3201d2c4925d1acb7aa614", "shasum": "" }, "require": { "php": "^7.1 || ^8.0" }, + "conflict": { + "doctrine/collections": "<1.6.8", + "doctrine/common": "<2.13.3 || >=3,<3.2.2" + }, "require-dev": { - "doctrine/collections": "^1.0", - "doctrine/common": "^2.6", - "phpunit/phpunit": "^7.1" + "doctrine/collections": "^1.6.8", + "doctrine/common": "^2.13.3 || ^3.2.2", + "phpunit/phpunit": "^7.5.20 || ^8.5.23 || ^9.5.13" }, "type": "library", "autoload": { @@ -978,7 +983,7 @@ ], "support": { "issues": "https://github.com/myclabs/DeepCopy/issues", - "source": "https://github.com/myclabs/DeepCopy/tree/1.10.2" + "source": "https://github.com/myclabs/DeepCopy/tree/1.11.0" }, "funding": [ { @@ -986,7 +991,7 @@ "type": "tidelift" } ], - "time": "2020-11-13T09:40:50+00:00" + "time": "2022-03-03T13:19:32+00:00" }, { "name": "netresearch/jsonmapper", @@ -1041,16 +1046,16 @@ }, { "name": "nikic/php-parser", - "version": "v4.13.2", + "version": "v4.14.0", "source": { "type": "git", "url": "https://github.com/nikic/PHP-Parser.git", - "reference": "210577fe3cf7badcc5814d99455df46564f3c077" + "reference": "34bea19b6e03d8153165d8f30bba4c3be86184c1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/210577fe3cf7badcc5814d99455df46564f3c077", - "reference": "210577fe3cf7badcc5814d99455df46564f3c077", + "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/34bea19b6e03d8153165d8f30bba4c3be86184c1", + "reference": "34bea19b6e03d8153165d8f30bba4c3be86184c1", "shasum": "" }, "require": { @@ -1091,9 +1096,9 @@ ], "support": { "issues": "https://github.com/nikic/PHP-Parser/issues", - "source": "https://github.com/nikic/PHP-Parser/tree/v4.13.2" + "source": "https://github.com/nikic/PHP-Parser/tree/v4.14.0" }, - "time": "2021-11-30T19:35:32+00:00" + "time": "2022-05-31T20:59:12+00:00" }, { "name": "openlss/lib-array2xml", @@ -1430,16 +1435,16 @@ }, { "name": "phpdocumentor/type-resolver", - "version": "1.6.0", + "version": "1.6.1", "source": { "type": "git", "url": "https://github.com/phpDocumentor/TypeResolver.git", - "reference": "93ebd0014cab80c4ea9f5e297ea48672f1b87706" + "reference": "77a32518733312af16a44300404e945338981de3" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/93ebd0014cab80c4ea9f5e297ea48672f1b87706", - "reference": "93ebd0014cab80c4ea9f5e297ea48672f1b87706", + "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/77a32518733312af16a44300404e945338981de3", + "reference": "77a32518733312af16a44300404e945338981de3", "shasum": "" }, "require": { @@ -1474,9 +1479,9 @@ "description": "A PSR-5 based resolver of Class names, Types and Structural Element Names", "support": { "issues": "https://github.com/phpDocumentor/TypeResolver/issues", - "source": "https://github.com/phpDocumentor/TypeResolver/tree/1.6.0" + "source": "https://github.com/phpDocumentor/TypeResolver/tree/1.6.1" }, - "time": "2022-01-04T19:58:01+00:00" + "time": "2022-03-15T21:29:03+00:00" }, { "name": "phpspec/prophecy", @@ -1599,16 +1604,16 @@ }, { "name": "phpunit/php-code-coverage", - "version": "9.2.11", + "version": "9.2.15", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-code-coverage.git", - "reference": "665a1ac0a763c51afc30d6d130dac0813092b17f" + "reference": "2e9da11878c4202f97915c1cb4bb1ca318a63f5f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/665a1ac0a763c51afc30d6d130dac0813092b17f", - "reference": "665a1ac0a763c51afc30d6d130dac0813092b17f", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/2e9da11878c4202f97915c1cb4bb1ca318a63f5f", + "reference": "2e9da11878c4202f97915c1cb4bb1ca318a63f5f", "shasum": "" }, "require": { @@ -1664,7 +1669,7 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/php-code-coverage/issues", - "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.11" + "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.15" }, "funding": [ { @@ -1672,7 +1677,7 @@ "type": "github" } ], - "time": "2022-02-18T12:46:09+00:00" + "time": "2022-03-07T09:28:20+00:00" }, { "name": "phpunit/php-file-iterator", @@ -1917,16 +1922,16 @@ }, { "name": "phpunit/phpunit", - "version": "9.5.14", + "version": "9.5.21", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "1883687169c017d6ae37c58883ca3994cfc34189" + "reference": "0e32b76be457de00e83213528f6bb37e2a38fcb1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/1883687169c017d6ae37c58883ca3994cfc34189", - "reference": "1883687169c017d6ae37c58883ca3994cfc34189", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/0e32b76be457de00e83213528f6bb37e2a38fcb1", + "reference": "0e32b76be457de00e83213528f6bb37e2a38fcb1", "shasum": "" }, "require": { @@ -1942,7 +1947,7 @@ "phar-io/version": "^3.0.2", "php": ">=7.3", "phpspec/prophecy": "^1.12.1", - "phpunit/php-code-coverage": "^9.2.7", + "phpunit/php-code-coverage": "^9.2.13", "phpunit/php-file-iterator": "^3.0.5", "phpunit/php-invoker": "^3.1.1", "phpunit/php-text-template": "^2.0.3", @@ -1956,11 +1961,10 @@ "sebastian/global-state": "^5.0.1", "sebastian/object-enumerator": "^4.0.3", "sebastian/resource-operations": "^3.0.3", - "sebastian/type": "^2.3.4", + "sebastian/type": "^3.0", "sebastian/version": "^3.0.2" }, "require-dev": { - "ext-pdo": "*", "phpspec/prophecy-phpunit": "^2.0.1" }, "suggest": { @@ -2004,7 +2008,7 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/phpunit/issues", - "source": "https://github.com/sebastianbergmann/phpunit/tree/9.5.14" + "source": "https://github.com/sebastianbergmann/phpunit/tree/9.5.21" }, "funding": [ { @@ -2016,7 +2020,7 @@ "type": "github" } ], - "time": "2022-02-18T12:54:07+00:00" + "time": "2022-06-19T12:14:25+00:00" }, { "name": "psalm/plugin-phpunit", @@ -2542,16 +2546,16 @@ }, { "name": "sebastian/environment", - "version": "5.1.3", + "version": "5.1.4", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/environment.git", - "reference": "388b6ced16caa751030f6a69e588299fa09200ac" + "reference": "1b5dff7bb151a4db11d49d90e5408e4e938270f7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/388b6ced16caa751030f6a69e588299fa09200ac", - "reference": "388b6ced16caa751030f6a69e588299fa09200ac", + "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/1b5dff7bb151a4db11d49d90e5408e4e938270f7", + "reference": "1b5dff7bb151a4db11d49d90e5408e4e938270f7", "shasum": "" }, "require": { @@ -2593,7 +2597,7 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/environment/issues", - "source": "https://github.com/sebastianbergmann/environment/tree/5.1.3" + "source": "https://github.com/sebastianbergmann/environment/tree/5.1.4" }, "funding": [ { @@ -2601,7 +2605,7 @@ "type": "github" } ], - "time": "2020-09-28T05:52:38+00:00" + "time": "2022-04-03T09:37:03+00:00" }, { "name": "sebastian/exporter", @@ -3033,28 +3037,28 @@ }, { "name": "sebastian/type", - "version": "2.3.4", + "version": "3.0.0", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/type.git", - "reference": "b8cd8a1c753c90bc1a0f5372170e3e489136f914" + "reference": "b233b84bc4465aff7b57cf1c4bc75c86d00d6dad" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/type/zipball/b8cd8a1c753c90bc1a0f5372170e3e489136f914", - "reference": "b8cd8a1c753c90bc1a0f5372170e3e489136f914", + "url": "https://api.github.com/repos/sebastianbergmann/type/zipball/b233b84bc4465aff7b57cf1c4bc75c86d00d6dad", + "reference": "b233b84bc4465aff7b57cf1c4bc75c86d00d6dad", "shasum": "" }, "require": { "php": ">=7.3" }, "require-dev": { - "phpunit/phpunit": "^9.3" + "phpunit/phpunit": "^9.5" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "2.3-dev" + "dev-master": "3.0-dev" } }, "autoload": { @@ -3077,7 +3081,7 @@ "homepage": "https://github.com/sebastianbergmann/type", "support": { "issues": "https://github.com/sebastianbergmann/type/issues", - "source": "https://github.com/sebastianbergmann/type/tree/2.3.4" + "source": "https://github.com/sebastianbergmann/type/tree/3.0.0" }, "funding": [ { @@ -3085,7 +3089,7 @@ "type": "github" } ], - "time": "2021-06-15T12:49:02+00:00" + "time": "2022-03-15T09:54:48+00:00" }, { "name": "sebastian/version", @@ -3225,16 +3229,16 @@ }, { "name": "symfony/console", - "version": "v5.4.3", + "version": "v5.4.9", "source": { "type": "git", "url": "https://github.com/symfony/console.git", - "reference": "a2a86ec353d825c75856c6fd14fac416a7bdb6b8" + "reference": "829d5d1bf60b2efeb0887b7436873becc71a45eb" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/a2a86ec353d825c75856c6fd14fac416a7bdb6b8", - "reference": "a2a86ec353d825c75856c6fd14fac416a7bdb6b8", + "url": "https://api.github.com/repos/symfony/console/zipball/829d5d1bf60b2efeb0887b7436873becc71a45eb", + "reference": "829d5d1bf60b2efeb0887b7436873becc71a45eb", "shasum": "" }, "require": { @@ -3304,7 +3308,7 @@ "terminal" ], "support": { - "source": "https://github.com/symfony/console/tree/v5.4.3" + "source": "https://github.com/symfony/console/tree/v5.4.9" }, "funding": [ { @@ -3320,20 +3324,20 @@ "type": "tidelift" } ], - "time": "2022-01-26T16:28:35+00:00" + "time": "2022-05-18T06:17:34+00:00" }, { "name": "symfony/deprecation-contracts", - "version": "v2.5.0", + "version": "v2.5.1", "source": { "type": "git", "url": "https://github.com/symfony/deprecation-contracts.git", - "reference": "6f981ee24cf69ee7ce9736146d1c57c2780598a8" + "reference": "e8b495ea28c1d97b5e0c121748d6f9b53d075c66" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/6f981ee24cf69ee7ce9736146d1c57c2780598a8", - "reference": "6f981ee24cf69ee7ce9736146d1c57c2780598a8", + "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/e8b495ea28c1d97b5e0c121748d6f9b53d075c66", + "reference": "e8b495ea28c1d97b5e0c121748d6f9b53d075c66", "shasum": "" }, "require": { @@ -3371,7 +3375,7 @@ "description": "A generic function and convention to trigger deprecation notices", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/deprecation-contracts/tree/v2.5.0" + "source": "https://github.com/symfony/deprecation-contracts/tree/v2.5.1" }, "funding": [ { @@ -3387,20 +3391,20 @@ "type": "tidelift" } ], - "time": "2021-07-12T14:48:14+00:00" + "time": "2022-01-02T09:53:40+00:00" }, { "name": "symfony/polyfill-ctype", - "version": "v1.24.0", + "version": "v1.26.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-ctype.git", - "reference": "30885182c981ab175d4d034db0f6f469898070ab" + "reference": "6fd1b9a79f6e3cf65f9e679b23af304cd9e010d4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/30885182c981ab175d4d034db0f6f469898070ab", - "reference": "30885182c981ab175d4d034db0f6f469898070ab", + "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/6fd1b9a79f6e3cf65f9e679b23af304cd9e010d4", + "reference": "6fd1b9a79f6e3cf65f9e679b23af304cd9e010d4", "shasum": "" }, "require": { @@ -3415,7 +3419,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "1.23-dev" + "dev-main": "1.26-dev" }, "thanks": { "name": "symfony/polyfill", @@ -3423,12 +3427,12 @@ } }, "autoload": { - "psr-4": { - "Symfony\\Polyfill\\Ctype\\": "" - }, "files": [ "bootstrap.php" - ] + ], + "psr-4": { + "Symfony\\Polyfill\\Ctype\\": "" + } }, "notification-url": "https://packagist.org/downloads/", "license": [ @@ -3453,7 +3457,7 @@ "portable" ], "support": { - "source": "https://github.com/symfony/polyfill-ctype/tree/v1.24.0" + "source": "https://github.com/symfony/polyfill-ctype/tree/v1.26.0" }, "funding": [ { @@ -3469,20 +3473,20 @@ "type": "tidelift" } ], - "time": "2021-10-20T20:35:02+00:00" + "time": "2022-05-24T11:49:31+00:00" }, { "name": "symfony/polyfill-intl-grapheme", - "version": "v1.24.0", + "version": "v1.26.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-intl-grapheme.git", - "reference": "81b86b50cf841a64252b439e738e97f4a34e2783" + "reference": "433d05519ce6990bf3530fba6957499d327395c2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/81b86b50cf841a64252b439e738e97f4a34e2783", - "reference": "81b86b50cf841a64252b439e738e97f4a34e2783", + "url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/433d05519ce6990bf3530fba6957499d327395c2", + "reference": "433d05519ce6990bf3530fba6957499d327395c2", "shasum": "" }, "require": { @@ -3494,7 +3498,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "1.23-dev" + "dev-main": "1.26-dev" }, "thanks": { "name": "symfony/polyfill", @@ -3534,7 +3538,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.24.0" + "source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.26.0" }, "funding": [ { @@ -3550,20 +3554,20 @@ "type": "tidelift" } ], - "time": "2021-11-23T21:10:46+00:00" + "time": "2022-05-24T11:49:31+00:00" }, { "name": "symfony/polyfill-intl-normalizer", - "version": "v1.24.0", + "version": "v1.26.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-intl-normalizer.git", - "reference": "8590a5f561694770bdcd3f9b5c69dde6945028e8" + "reference": "219aa369ceff116e673852dce47c3a41794c14bd" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/8590a5f561694770bdcd3f9b5c69dde6945028e8", - "reference": "8590a5f561694770bdcd3f9b5c69dde6945028e8", + "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/219aa369ceff116e673852dce47c3a41794c14bd", + "reference": "219aa369ceff116e673852dce47c3a41794c14bd", "shasum": "" }, "require": { @@ -3575,7 +3579,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "1.23-dev" + "dev-main": "1.26-dev" }, "thanks": { "name": "symfony/polyfill", @@ -3618,7 +3622,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.24.0" + "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.26.0" }, "funding": [ { @@ -3634,20 +3638,20 @@ "type": "tidelift" } ], - "time": "2021-02-19T12:13:01+00:00" + "time": "2022-05-24T11:49:31+00:00" }, { "name": "symfony/polyfill-mbstring", - "version": "v1.24.0", + "version": "v1.26.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-mbstring.git", - "reference": "0abb51d2f102e00a4eefcf46ba7fec406d245825" + "reference": "9344f9cb97f3b19424af1a21a3b0e75b0a7d8d7e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/0abb51d2f102e00a4eefcf46ba7fec406d245825", - "reference": "0abb51d2f102e00a4eefcf46ba7fec406d245825", + "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/9344f9cb97f3b19424af1a21a3b0e75b0a7d8d7e", + "reference": "9344f9cb97f3b19424af1a21a3b0e75b0a7d8d7e", "shasum": "" }, "require": { @@ -3662,7 +3666,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "1.23-dev" + "dev-main": "1.26-dev" }, "thanks": { "name": "symfony/polyfill", @@ -3701,7 +3705,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.24.0" + "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.26.0" }, "funding": [ { @@ -3717,20 +3721,20 @@ "type": "tidelift" } ], - "time": "2021-11-30T18:21:41+00:00" + "time": "2022-05-24T11:49:31+00:00" }, { "name": "symfony/polyfill-php73", - "version": "v1.24.0", + "version": "v1.26.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php73.git", - "reference": "cc5db0e22b3cb4111010e48785a97f670b350ca5" + "reference": "e440d35fa0286f77fb45b79a03fedbeda9307e85" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php73/zipball/cc5db0e22b3cb4111010e48785a97f670b350ca5", - "reference": "cc5db0e22b3cb4111010e48785a97f670b350ca5", + "url": "https://api.github.com/repos/symfony/polyfill-php73/zipball/e440d35fa0286f77fb45b79a03fedbeda9307e85", + "reference": "e440d35fa0286f77fb45b79a03fedbeda9307e85", "shasum": "" }, "require": { @@ -3739,7 +3743,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "1.23-dev" + "dev-main": "1.26-dev" }, "thanks": { "name": "symfony/polyfill", @@ -3780,7 +3784,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-php73/tree/v1.24.0" + "source": "https://github.com/symfony/polyfill-php73/tree/v1.26.0" }, "funding": [ { @@ -3796,20 +3800,20 @@ "type": "tidelift" } ], - "time": "2021-06-05T21:20:04+00:00" + "time": "2022-05-24T11:49:31+00:00" }, { "name": "symfony/polyfill-php80", - "version": "v1.24.0", + "version": "v1.26.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php80.git", - "reference": "57b712b08eddb97c762a8caa32c84e037892d2e9" + "reference": "cfa0ae98841b9e461207c13ab093d76b0fa7bace" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/57b712b08eddb97c762a8caa32c84e037892d2e9", - "reference": "57b712b08eddb97c762a8caa32c84e037892d2e9", + "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/cfa0ae98841b9e461207c13ab093d76b0fa7bace", + "reference": "cfa0ae98841b9e461207c13ab093d76b0fa7bace", "shasum": "" }, "require": { @@ -3818,7 +3822,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "1.23-dev" + "dev-main": "1.26-dev" }, "thanks": { "name": "symfony/polyfill", @@ -3863,7 +3867,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-php80/tree/v1.24.0" + "source": "https://github.com/symfony/polyfill-php80/tree/v1.26.0" }, "funding": [ { @@ -3879,26 +3883,26 @@ "type": "tidelift" } ], - "time": "2021-09-13T13:58:33+00:00" + "time": "2022-05-10T07:21:04+00:00" }, { "name": "symfony/service-contracts", - "version": "v2.5.0", + "version": "v2.5.1", "source": { "type": "git", "url": "https://github.com/symfony/service-contracts.git", - "reference": "1ab11b933cd6bc5464b08e81e2c5b07dec58b0fc" + "reference": "24d9dc654b83e91aa59f9d167b131bc3b5bea24c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/service-contracts/zipball/1ab11b933cd6bc5464b08e81e2c5b07dec58b0fc", - "reference": "1ab11b933cd6bc5464b08e81e2c5b07dec58b0fc", + "url": "https://api.github.com/repos/symfony/service-contracts/zipball/24d9dc654b83e91aa59f9d167b131bc3b5bea24c", + "reference": "24d9dc654b83e91aa59f9d167b131bc3b5bea24c", "shasum": "" }, "require": { "php": ">=7.2.5", "psr/container": "^1.1", - "symfony/deprecation-contracts": "^2.1" + "symfony/deprecation-contracts": "^2.1|^3" }, "conflict": { "ext-psr": "<1.1|>=2" @@ -3946,7 +3950,7 @@ "standards" ], "support": { - "source": "https://github.com/symfony/service-contracts/tree/v2.5.0" + "source": "https://github.com/symfony/service-contracts/tree/v2.5.1" }, "funding": [ { @@ -3962,20 +3966,20 @@ "type": "tidelift" } ], - "time": "2021-11-04T16:48:04+00:00" + "time": "2022-03-13T20:07:29+00:00" }, { "name": "symfony/string", - "version": "v5.4.3", + "version": "v5.4.9", "source": { "type": "git", "url": "https://github.com/symfony/string.git", - "reference": "92043b7d8383e48104e411bc9434b260dbeb5a10" + "reference": "985e6a9703ef5ce32ba617c9c7d97873bb7b2a99" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/string/zipball/92043b7d8383e48104e411bc9434b260dbeb5a10", - "reference": "92043b7d8383e48104e411bc9434b260dbeb5a10", + "url": "https://api.github.com/repos/symfony/string/zipball/985e6a9703ef5ce32ba617c9c7d97873bb7b2a99", + "reference": "985e6a9703ef5ce32ba617c9c7d97873bb7b2a99", "shasum": "" }, "require": { @@ -3997,12 +4001,12 @@ }, "type": "library", "autoload": { - "psr-4": { - "Symfony\\Component\\String\\": "" - }, "files": [ "Resources/functions.php" ], + "psr-4": { + "Symfony\\Component\\String\\": "" + }, "exclude-from-classmap": [ "/Tests/" ] @@ -4032,7 +4036,7 @@ "utf8" ], "support": { - "source": "https://github.com/symfony/string/tree/v5.4.3" + "source": "https://github.com/symfony/string/tree/v5.4.9" }, "funding": [ { @@ -4048,7 +4052,7 @@ "type": "tidelift" } ], - "time": "2022-01-02T09:53:40+00:00" + "time": "2022-04-19T10:40:37+00:00" }, { "name": "theseer/tokenizer", @@ -4102,16 +4106,16 @@ }, { "name": "vimeo/psalm", - "version": "4.21.0", + "version": "4.23.0", "source": { "type": "git", "url": "https://github.com/vimeo/psalm.git", - "reference": "d8bec4c7aaee111a532daec32fb09de5687053d1" + "reference": "f1fe6ff483bf325c803df9f510d09a03fd796f88" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/vimeo/psalm/zipball/d8bec4c7aaee111a532daec32fb09de5687053d1", - "reference": "d8bec4c7aaee111a532daec32fb09de5687053d1", + "url": "https://api.github.com/repos/vimeo/psalm/zipball/f1fe6ff483bf325c803df9f510d09a03fd796f88", + "reference": "f1fe6ff483bf325c803df9f510d09a03fd796f88", "shasum": "" }, "require": { @@ -4136,6 +4140,7 @@ "php": "^7.1|^8", "sebastian/diff": "^3.0 || ^4.0", "symfony/console": "^3.4.17 || ^4.1.6 || ^5.0 || ^6.0", + "symfony/polyfill-php80": "^1.25", "webmozart/path-util": "^2.3" }, "provide": { @@ -4202,27 +4207,27 @@ ], "support": { "issues": "https://github.com/vimeo/psalm/issues", - "source": "https://github.com/vimeo/psalm/tree/4.21.0" + "source": "https://github.com/vimeo/psalm/tree/4.23.0" }, - "time": "2022-02-18T04:34:15+00:00" + "time": "2022-04-28T17:35:49+00:00" }, { "name": "webmozart/assert", - "version": "1.10.0", + "version": "1.11.0", "source": { "type": "git", "url": "https://github.com/webmozarts/assert.git", - "reference": "6964c76c7804814a842473e0c8fd15bab0f18e25" + "reference": "11cb2199493b2f8a3b53e7f19068fc6aac760991" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/webmozarts/assert/zipball/6964c76c7804814a842473e0c8fd15bab0f18e25", - "reference": "6964c76c7804814a842473e0c8fd15bab0f18e25", + "url": "https://api.github.com/repos/webmozarts/assert/zipball/11cb2199493b2f8a3b53e7f19068fc6aac760991", + "reference": "11cb2199493b2f8a3b53e7f19068fc6aac760991", "shasum": "" }, "require": { - "php": "^7.2 || ^8.0", - "symfony/polyfill-ctype": "^1.8" + "ext-ctype": "*", + "php": "^7.2 || ^8.0" }, "conflict": { "phpstan/phpstan": "<0.12.20", @@ -4260,9 +4265,9 @@ ], "support": { "issues": "https://github.com/webmozarts/assert/issues", - "source": "https://github.com/webmozarts/assert/tree/1.10.0" + "source": "https://github.com/webmozarts/assert/tree/1.11.0" }, - "time": "2021-03-09T10:59:23+00:00" + "time": "2022-06-03T18:03:27+00:00" }, { "name": "webmozart/path-util", diff --git a/vendor/laminas/laminas-diactoros/psalm-baseline.xml b/vendor/laminas/laminas-diactoros/psalm-baseline.xml index fc5a8bafac0436b1921886774b31e837d6c1b5de..47be887f6b855d4716f1af21954c7c3738d583af 100644 --- a/vendor/laminas/laminas-diactoros/psalm-baseline.xml +++ b/vendor/laminas/laminas-diactoros/psalm-baseline.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8"?> -<files psalm-version="4.21.0@d8bec4c7aaee111a532daec32fb09de5687053d1"> +<files psalm-version="4.23.0@f1fe6ff483bf325c803df9f510d09a03fd796f88"> <file src="src/CallbackStream.php"> <ImplementedReturnTypeMismatch occurrences="1"> <code>null|callable</code> @@ -242,13 +242,52 @@ </ParamNameMismatch> </file> <file src="src/ServerRequestFactory.php"> - <MixedArgument occurrences="1"> + <LessSpecificReturnStatement occurrences="1"/> + <MixedArgument occurrences="2"> <code>$headers['cookie']</code> + <code>$host</code> </MixedArgument> + <MixedArgumentTypeCoercion occurrences="1"> + <code>$headers</code> + </MixedArgumentTypeCoercion> + <MixedAssignment occurrences="3"> + <code>$iisUrlRewritten</code> + <code>$requestUri</code> + <code>$unencodedUrl</code> + </MixedAssignment> + <MixedInferredReturnType occurrences="1"> + <code>array{string, int|null}</code> + </MixedInferredReturnType> + <MixedReturnStatement occurrences="1"> + <code>$defaults</code> + </MixedReturnStatement> + <MixedReturnTypeCoercion occurrences="1"> + <code>self::marshalHostAndPortFromHeader($host)</code> + </MixedReturnTypeCoercion> + <MoreSpecificReturnType occurrences="1"> + <code>ServerRequest</code> + </MoreSpecificReturnType> <RedundantConditionGivenDocblockType occurrences="1"> <code>is_callable(self::$apacheRequestHeaders)</code> </RedundantConditionGivenDocblockType> </file> + <file src="src/ServerRequestFilter/FilterUsingXForwardedHeaders.php"> + <ImpureMethodCall occurrences="7"> + <code>getHeaderLine</code> + <code>getServerParams</code> + <code>getUri</code> + <code>withHost</code> + <code>withPort</code> + <code>withScheme</code> + <code>withUri</code> + </ImpureMethodCall> + <LessSpecificReturnStatement occurrences="1"> + <code>$proxyCIDRList</code> + </LessSpecificReturnStatement> + <MoreSpecificReturnType occurrences="1"> + <code>list<non-empty-string></code> + </MoreSpecificReturnType> + </file> <file src="src/Stream.php"> <InvalidArgument occurrences="1"/> <MixedInferredReturnType occurrences="1"> @@ -1125,54 +1164,10 @@ </MissingReturnType> </file> <file src="test/UploadedFileTest.php"> - <MissingParamType occurrences="6"> - <code>$path</code> - <code>$status</code> - <code>$status</code> - <code>$status</code> - <code>$status</code> - <code>$streamOrFile</code> - </MissingParamType> - <MissingPropertyType occurrences="1"> - <code>$tmpFile</code> - </MissingPropertyType> - <MissingReturnType occurrences="24"> - <code>errorConstantsAndMessages</code> - <code>invalidErrorStatuses</code> - <code>invalidMovePaths</code> - <code>invalidStreams</code> - <code>nonOkErrorStatus</code> - <code>testCannotRetrieveStreamAfterMove</code> - <code>testConstructorDoesNotRaiseExceptionForInvalidStreamWhenErrorStatusPresent</code> - <code>testGetStreamRaisesExceptionWhenErrorStatusPresent</code> - <code>testGetStreamRaisesExceptionWithAppropriateMessageWhenUploadErrorDetected</code> - <code>testGetStreamReturnsOriginalStreamObject</code> - <code>testGetStreamReturnsStreamForFile</code> - <code>testGetStreamReturnsWrappedPhpStream</code> - <code>testMoveCannotBeCalledMoreThanOnce</code> - <code>testMoveRaisesExceptionForInvalidPath</code> - <code>testMoveToCreatesStreamIfOnlyAFilenameWasProvided</code> - <code>testMoveToRaisesExceptionWhenErrorStatusPresent</code> - <code>testMoveToRaisesExceptionWithAppropriateMessageWhenUploadErrorDetected</code> - <code>testMovesFileToDesignatedPath</code> - <code>testRaisesExceptionOnInvalidErrorStatus</code> - <code>testRaisesExceptionOnInvalidStreamOrFile</code> - <code>testValidClientFilename</code> - <code>testValidClientMediaType</code> - <code>testValidNullClientFilename</code> - <code>testValidSize</code> - </MissingReturnType> - <MixedArgument occurrences="6"> + <MixedArgument occurrences="2"> <code>$path</code> - <code>$status</code> - <code>$status</code> - <code>$status</code> - <code>$status</code> <code>$streamOrFile</code> </MixedArgument> - <UndefinedThisPropertyAssignment occurrences="1"> - <code>$this->tmpfile</code> - </UndefinedThisPropertyAssignment> </file> <file src="test/UriTest.php"> <InvalidScalarArgument occurrences="2"> diff --git a/vendor/laminas/laminas-diactoros/psalm.xml.dist b/vendor/laminas/laminas-diactoros/psalm.xml.dist index 9cee6e9efd78015a2a3c7be7c85eb5f08ab603b5..0a854e5436054670a32717b7cd78fd14b50e92b4 100644 --- a/vendor/laminas/laminas-diactoros/psalm.xml.dist +++ b/vendor/laminas/laminas-diactoros/psalm.xml.dist @@ -15,11 +15,26 @@ </projectFiles> <issueHandlers> + <DeprecatedFunction> + <errorLevel type="suppress"> + <referencedFunction name="laminas\diactoros\marshalurifromsapi"/> + </errorLevel> + </DeprecatedFunction> + + <InternalClass> + <errorLevel type="suppress"> + <referencedClass name="Laminas\Diactoros\ServerRequestFilter\IPRange"/> + </errorLevel> + </InternalClass> + <InternalMethod> <errorLevel type="suppress"> <referencedMethod name="PHPUnit\Framework\MockObject\Builder\InvocationMocker::method"/> <referencedMethod name="PHPUnit\Framework\MockObject\Builder\InvocationMocker::willReturn"/> <referencedMethod name="PHPUnit\Framework\MockObject\Builder\InvocationMocker::with"/> + <referencedMethod name="Laminas\Diactoros\ServerRequestFilter\IPRange::matches"/> + <referencedMethod name="Laminas\Diactoros\ServerRequestFilter\IPRange::matchesIPv4"/> + <referencedMethod name="Laminas\Diactoros\ServerRequestFilter\IPRange::matchesIPv6"/> </errorLevel> </InternalMethod> diff --git a/vendor/laminas/laminas-diactoros/src/ConfigProvider.php b/vendor/laminas/laminas-diactoros/src/ConfigProvider.php index 32510d1f686126a4a58a9a2fe74d6e1753a18881..78afa0474e8edb3adb437449ac188d62d443bf18 100644 --- a/vendor/laminas/laminas-diactoros/src/ConfigProvider.php +++ b/vendor/laminas/laminas-diactoros/src/ConfigProvider.php @@ -13,6 +13,11 @@ class ConfigProvider { + public const CONFIG_KEY = 'laminas-diactoros'; + public const X_FORWARDED = 'x-forwarded-request-filter'; + public const X_FORWARDED_TRUSTED_PROXIES = 'trusted-proxies'; + public const X_FORWARDED_TRUSTED_HEADERS = 'trusted-headers'; + /** * Retrieve configuration for laminas-diactoros. * @@ -22,6 +27,7 @@ public function __invoke() : array { return [ 'dependencies' => $this->getDependencies(), + self::CONFIG_KEY => $this->getComponentConfig(), ]; } @@ -31,6 +37,7 @@ public function __invoke() : array */ public function getDependencies() : array { + // @codingStandardsIgnoreStart return [ 'invokables' => [ RequestFactoryInterface::class => RequestFactory::class, @@ -41,5 +48,16 @@ public function getDependencies() : array UriFactoryInterface::class => UriFactory::class ], ]; + // @codingStandardsIgnoreEnd + } + + public function getComponentConfig(): array + { + return [ + self::X_FORWARDED => [ + self::X_FORWARDED_TRUSTED_PROXIES => '', + self::X_FORWARDED_TRUSTED_HEADERS => [], + ], + ]; } } diff --git a/vendor/laminas/laminas-diactoros/src/Exception/InvalidForwardedHeaderNameException.php b/vendor/laminas/laminas-diactoros/src/Exception/InvalidForwardedHeaderNameException.php new file mode 100644 index 0000000000000000000000000000000000000000..1c446439f9fa26033e637b139435993efbdf7a79 --- /dev/null +++ b/vendor/laminas/laminas-diactoros/src/Exception/InvalidForwardedHeaderNameException.php @@ -0,0 +1,24 @@ +<?php + +declare(strict_types=1); + +namespace Laminas\Diactoros\Exception; + +use Laminas\Diactoros\ServerRequestFilter\FilterUsingXForwardedHeaders; + +class InvalidForwardedHeaderNameException extends RuntimeException implements ExceptionInterface +{ + /** @param mixed $name */ + public static function forHeader($name): self + { + if (! is_string($name)) { + $name = sprintf('(value of type %s)', is_object($name) ? get_class($name) : gettype($name)); + } + + return new self(sprintf( + 'Invalid X-Forwarded-* header name "%s" provided to %s', + $name, + FilterUsingXForwardedHeaders::class + )); + } +} diff --git a/vendor/laminas/laminas-diactoros/src/Exception/InvalidProxyAddressException.php b/vendor/laminas/laminas-diactoros/src/Exception/InvalidProxyAddressException.php new file mode 100644 index 0000000000000000000000000000000000000000..3c8a68d29c16f801fe2fb594076d299d3972f6ae --- /dev/null +++ b/vendor/laminas/laminas-diactoros/src/Exception/InvalidProxyAddressException.php @@ -0,0 +1,29 @@ +<?php + +declare(strict_types=1); + +namespace Laminas\Diactoros\Exception; + +class InvalidProxyAddressException extends RuntimeException implements ExceptionInterface +{ + /** @param mixed $proxy */ + public static function forInvalidProxyArgument($proxy): self + { + $type = is_object($proxy) ? get_class($proxy) : gettype($proxy); + return new self(sprintf( + 'Invalid proxy of type "%s" provided;' + . ' must be a valid IPv4 or IPv6 address, optionally with a subnet mask provided' + . ' or an array of such values', + $type, + )); + } + + public static function forAddress(string $address): self + { + return new self(sprintf( + 'Invalid proxy address "%s" provided;' + . ' must be a valid IPv4 or IPv6 address, optionally with a subnet mask provided', + $address, + )); + } +} diff --git a/vendor/laminas/laminas-diactoros/src/ServerRequestFactory.php b/vendor/laminas/laminas-diactoros/src/ServerRequestFactory.php index 3cde0e0c020188198c04e19f86275072bef4ef68..30eb71cbe0ef597b827d8beda2154bae2561fade 100644 --- a/vendor/laminas/laminas-diactoros/src/ServerRequestFactory.php +++ b/vendor/laminas/laminas-diactoros/src/ServerRequestFactory.php @@ -4,6 +4,8 @@ namespace Laminas\Diactoros; +use Laminas\Diactoros\ServerRequestFilter\FilterServerRequestInterface; +use Laminas\Diactoros\ServerRequestFilter\FilterUsingXForwardedHeaders; use Psr\Http\Message\ServerRequestFactoryInterface; use Psr\Http\Message\ServerRequestInterface; @@ -42,6 +44,11 @@ class ServerRequestFactory implements ServerRequestFactoryInterface * @param array $body $_POST superglobal * @param array $cookies $_COOKIE superglobal * @param array $files $_FILES superglobal + * @param null|FilterServerRequestInterface $requestFilter If present, the + * generated request will be passed to this instance and the result + * returned by this method. When not present, a default instance of + * FilterUsingXForwardedHeaders is created, using the `trustReservedSubnets()` + * constructor. * @return ServerRequest */ public static function fromGlobals( @@ -49,8 +56,11 @@ public static function fromGlobals( array $query = null, array $body = null, array $cookies = null, - array $files = null + array $files = null, + ?FilterServerRequestInterface $requestFilter = null ) : ServerRequest { + $requestFilter = $requestFilter ?: FilterUsingXForwardedHeaders::trustReservedSubnets(); + $server = normalizeServer( $server ?: $_SERVER, is_callable(self::$apacheRequestHeaders) ? self::$apacheRequestHeaders : null @@ -62,10 +72,10 @@ public static function fromGlobals( $cookies = parseCookieHeader($headers['cookie']); } - return new ServerRequest( + return $requestFilter(new ServerRequest( $server, $files, - marshalUriFromSapi($server, $headers), + self::marshalUriFromSapi($server, $headers), marshalMethodFromSapi($server), 'php://input', $headers, @@ -73,7 +83,7 @@ public static function fromGlobals( $query ?: $_GET, $body ?: $_POST, marshalProtocolVersionFromSapi($server) - ); + )); } /** @@ -91,4 +101,210 @@ public function createServerRequest(string $method, $uri, array $serverParams = 'php://temp' ); } + + /** + * Marshal a Uri instance based on the values present in the $_SERVER array and headers. + * + * @param array<string, string|list<string>> $headers + * @param array $server SAPI parameters + */ + private static function marshalUriFromSapi(array $server, array $headers) : Uri + { + $uri = new Uri(''); + + // URI scheme + $https = false; + if (array_key_exists('HTTPS', $server)) { + $https = self::marshalHttpsValue($server['HTTPS']); + } elseif (array_key_exists('https', $server)) { + $https = self::marshalHttpsValue($server['https']); + } + + $uri = $uri->withScheme($https ? 'https' : 'http'); + + // Set the host + [$host, $port] = self::marshalHostAndPort($server, $headers); + if (! empty($host)) { + $uri = $uri->withHost($host); + if (! empty($port)) { + $uri = $uri->withPort($port); + } + } + + // URI path + $path = self::marshalRequestPath($server); + + // Strip query string + $path = explode('?', $path, 2)[0]; + + // URI query + $query = ''; + if (isset($server['QUERY_STRING'])) { + $query = ltrim((string) $server['QUERY_STRING'], '?'); + } + + // URI fragment + $fragment = ''; + if (strpos($path, '#') !== false) { + [$path, $fragment] = explode('#', $path, 2); + } + + return $uri + ->withPath($path) + ->withFragment($fragment) + ->withQuery($query); + } + + /** + * Marshal the host and port from the PHP environment. + * + * @param array<string, string|list<string>> $headers + * @return array{string, int|null} Array of two items, host and port, + * in that order (can be passed to a list() operation). + */ + private static function marshalHostAndPort(array $server, array $headers) : array + { + static $defaults = ['', null]; + + $host = self::getHeaderFromArray('host', $headers, false); + if ($host !== false) { + return self::marshalHostAndPortFromHeader($host); + } + + if (! isset($server['SERVER_NAME'])) { + return $defaults; + } + + $host = (string) $server['SERVER_NAME']; + $port = isset($server['SERVER_PORT']) ? (int) $server['SERVER_PORT'] : null; + + if (! isset($server['SERVER_ADDR']) + || ! preg_match('/^\[[0-9a-fA-F\:]+\]$/', $host) + ) { + return [$host, $port]; + } + + // Misinterpreted IPv6-Address + // Reported for Safari on Windows + return self::marshalIpv6HostAndPort($server, $port); + } + + /** + * @return array{string, int|null} Array of two items, host and port, + * in that order (can be passed to a list() operation). + */ + private static function marshalIpv6HostAndPort(array $server, ?int $port) : array + { + $host = '[' . (string) $server['SERVER_ADDR'] . ']'; + $port = $port ?: 80; + $portSeparatorPos = strrpos($host, ':'); + + if (false === $portSeparatorPos) { + return [$host, $port]; + } + + if ($port . ']' === substr($host, $portSeparatorPos + 1)) { + // The last digit of the IPv6-Address has been taken as port + // Unset the port so the default port can be used + $port = null; + } + return [$host, $port]; + } + + /** + * Detect the path for the request + * + * Looks at a variety of criteria in order to attempt to autodetect the base + * request path, including: + * + * - IIS7 UrlRewrite environment + * - REQUEST_URI + * - ORIG_PATH_INFO + */ + private static function marshalRequestPath(array $server) : string + { + // IIS7 with URL Rewrite: make sure we get the unencoded url + // (double slash problem). + $iisUrlRewritten = $server['IIS_WasUrlRewritten'] ?? null; + $unencodedUrl = $server['UNENCODED_URL'] ?? ''; + if ('1' === $iisUrlRewritten && is_string($unencodedUrl) && '' !== $unencodedUrl) { + return $unencodedUrl; + } + + $requestUri = $server['REQUEST_URI'] ?? null; + + if (is_string($requestUri)) { + return preg_replace('#^[^/:]+://[^/]+#', '', $requestUri); + } + + $origPathInfo = $server['ORIG_PATH_INFO'] ?? ''; + if (! is_string($origPathInfo) || '' === $origPathInfo) { + return '/'; + } + + return $origPathInfo; + } + + /** + * @param mixed $https + */ + private static function marshalHttpsValue($https) : bool + { + if (is_bool($https)) { + return $https; + } + + if (! is_string($https)) { + throw new Exception\InvalidArgumentException(sprintf( + 'SAPI HTTPS value MUST be a string or boolean; received %s', + gettype($https) + )); + } + + return 'on' === strtolower($https); + } + + /** + * @param string|list<string> $host + * @return array Array of two items, host and port, in that order (can be + * passed to a list() operation). + */ + private static function marshalHostAndPortFromHeader($host): array + { + if (is_array($host)) { + $host = implode(', ', $host); + } + + $port = null; + + // works for regname, IPv4 & IPv6 + if (preg_match('|\:(\d+)$|', $host, $matches)) { + $host = substr($host, 0, -1 * (strlen($matches[1]) + 1)); + $port = (int) $matches[1]; + } + + return [$host, $port]; + } + + /** + * Retrieve a header value from an array of headers using a case-insensitive lookup. + * + * @param array<string, string|list<string>> $headers Key/value header pairs + * @param mixed $default Default value to return if header not found + * @return mixed + */ + private static function getHeaderFromArray(string $name, array $headers, $default = null) + { + $header = strtolower($name); + $headers = array_change_key_case($headers, CASE_LOWER); + if (! array_key_exists($header, $headers)) { + return $default; + } + + if (is_string($headers[$header])) { + return $headers[$header]; + } + + return implode(', ', $headers[$header]); + } } diff --git a/vendor/laminas/laminas-diactoros/src/ServerRequestFilter/DoNotFilter.php b/vendor/laminas/laminas-diactoros/src/ServerRequestFilter/DoNotFilter.php new file mode 100644 index 0000000000000000000000000000000000000000..7a6867a863b6cfedcbe04259e98df8dc42b1f907 --- /dev/null +++ b/vendor/laminas/laminas-diactoros/src/ServerRequestFilter/DoNotFilter.php @@ -0,0 +1,15 @@ +<?php + +declare(strict_types=1); + +namespace Laminas\Diactoros\ServerRequestFilter; + +use Psr\Http\Message\ServerRequestInterface; + +final class DoNotFilter implements FilterServerRequestInterface +{ + public function __invoke(ServerRequestInterface $request): ServerRequestInterface + { + return $request; + } +} diff --git a/vendor/laminas/laminas-diactoros/src/ServerRequestFilter/FilterServerRequestInterface.php b/vendor/laminas/laminas-diactoros/src/ServerRequestFilter/FilterServerRequestInterface.php new file mode 100644 index 0000000000000000000000000000000000000000..4de57d6d5fc6db603e2bb9aa51c1a001272cb6ea --- /dev/null +++ b/vendor/laminas/laminas-diactoros/src/ServerRequestFilter/FilterServerRequestInterface.php @@ -0,0 +1,29 @@ +<?php + +declare(strict_types=1); + +namespace Laminas\Diactoros\ServerRequestFilter; + +use Psr\Http\Message\ServerRequestInterface; + +/** + * Filter/initialize a server request. + * + * Implementations of this interface will take an incoming request, and + * decide if additional modifications are necessary. As examples: + * + * - Injecting a unique request identifier header. + * - Using the X-Forwarded-* headers to rewrite the URI to reflect the original request. + * - Using the Forwarded header to rewrite the URI to reflect the original request. + * + * This functionality is consumed by the ServerRequestFactory using the request + * instance it generates, just prior to returning a request. + */ +interface FilterServerRequestInterface +{ + /** + * Determine if a request needs further modification, and if so, return a + * new instance reflecting those modifications. + */ + public function __invoke(ServerRequestInterface $request): ServerRequestInterface; +} diff --git a/vendor/laminas/laminas-diactoros/src/ServerRequestFilter/FilterUsingXForwardedHeaders.php b/vendor/laminas/laminas-diactoros/src/ServerRequestFilter/FilterUsingXForwardedHeaders.php new file mode 100644 index 0000000000000000000000000000000000000000..00b9707b454b4bfe4008c05db14f4c6d30a5a008 --- /dev/null +++ b/vendor/laminas/laminas-diactoros/src/ServerRequestFilter/FilterUsingXForwardedHeaders.php @@ -0,0 +1,257 @@ +<?php + +declare(strict_types=1); + +namespace Laminas\Diactoros\ServerRequestFilter; + +use Laminas\Diactoros\Exception\InvalidForwardedHeaderNameException; +use Laminas\Diactoros\Exception\InvalidProxyAddressException; +use Psr\Http\Message\ServerRequestInterface; + +/** + * Modify the URI to reflect the X-Forwarded-* headers. + * + * If the request comes from a trusted proxy, this filter will analyze the + * various X-Forwarded-* headers, if any, and if they are marked as trusted, + * in order to return a new request that composes a URI instance that reflects + * those headers. + * + * @psalm-immutable +*/ +final class FilterUsingXForwardedHeaders implements FilterServerRequestInterface +{ + public const HEADER_HOST = 'X-FORWARDED-HOST'; + public const HEADER_PORT = 'X-FORWARDED-PORT'; + public const HEADER_PROTO = 'X-FORWARDED-PROTO'; + + private const X_FORWARDED_HEADERS = [ + self::HEADER_HOST, + self::HEADER_PORT, + self::HEADER_PROTO, + ]; + + /** + * @var list<FilterUsingXForwardedHeaders::HEADER_*> + */ + private $trustedHeaders; + + /** @var list<non-empty-string> */ + private $trustedProxies; + + /** + * Only allow construction via named constructors + * + * @param list<non-empty-string> $trustedProxies + * @param list<FilterUsingXForwardedHeaders::HEADER_*> $trustedHeaders + */ + private function __construct( + array $trustedProxies = [], + array $trustedHeaders = [] + ) { + $this->trustedProxies = $trustedProxies; + $this->trustedHeaders = $trustedHeaders; + } + + public function __invoke(ServerRequestInterface $request): ServerRequestInterface + { + $remoteAddress = $request->getServerParams()['REMOTE_ADDR'] ?? ''; + + if ('' === $remoteAddress || ! is_string($remoteAddress)) { + // Should we trigger a warning here? + return $request; + } + + if (! $this->isFromTrustedProxy($remoteAddress)) { + // Do nothing + return $request; + } + + // Update the URI based on the trusted headers + $uri = $originalUri = $request->getUri(); + foreach ($this->trustedHeaders as $headerName) { + $header = $request->getHeaderLine($headerName); + if ('' === $header || false !== strpos($header, ',')) { + // Reject empty headers and/or headers with multiple values + continue; + } + + switch ($headerName) { + case self::HEADER_HOST: + $uri = $uri->withHost($header); + break; + case self::HEADER_PORT: + $uri = $uri->withPort((int) $header); + break; + case self::HEADER_PROTO: + $scheme = strtolower($header) === 'https' ? 'https' : 'http'; + $uri = $uri->withScheme($scheme); + break; + } + } + + if ($uri !== $originalUri) { + return $request->withUri($uri); + } + + return $request; + } + + /** + * Indicate which proxies and which X-Forwarded headers to trust. + * + * @param list<non-empty-string> $proxyCIDRList Each element may + * be an IP address or a subnet specified using CIDR notation; both IPv4 + * and IPv6 are supported. The special string "*" will be translated to + * two entries, "0.0.0.0/0" and "::/0". An empty list indicates no + * proxies are trusted. + * @param list<FilterUsingXForwardedHeaders::HEADER_*> $trustedHeaders If + * the list is empty, all X-Forwarded headers are trusted. + * @throws InvalidProxyAddressException + * @throws InvalidForwardedHeaderNameException + */ + public static function trustProxies( + array $proxyCIDRList, + array $trustedHeaders = self::X_FORWARDED_HEADERS + ): self { + $proxyCIDRList = self::normalizeProxiesList($proxyCIDRList); + self::validateTrustedHeaders($trustedHeaders); + + return new self($proxyCIDRList, $trustedHeaders); + } + + /** + * Trust any X-FORWARDED-* headers from any address. + * + * This is functionally equivalent to calling `trustProxies(['*'])`. + * + * WARNING: Only do this if you know for certain that your application + * sits behind a trusted proxy that cannot be spoofed. This should only + * be the case if your server is not publicly addressable, and all requests + * are routed via a reverse proxy (e.g., a load balancer, a server such as + * Caddy, when using Traefik, etc.). + */ + public static function trustAny(): self + { + return self::trustProxies(['*']); + } + + /** + * Trust X-Forwarded headers from reserved subnetworks. + * + * This is functionally equivalent to calling `trustProxies()` where the + * `$proxcyCIDRList` argument is a list with the following: + * + * - 10.0.0.0/8 + * - 127.0.0.0/8 + * - 172.16.0.0/12 + * - 192.168.0.0/16 + * - ::1/128 (IPv6 localhost) + * - fc00::/7 (IPv6 private networks) + * - fe80::/10 (IPv6 local-link addresses) + * + * @param list<FilterUsingXForwardedHeaders::HEADER_*> $trustedHeaders If + * the list is empty, all X-Forwarded headers are trusted. + * @throws InvalidForwardedHeaderNameException + */ + public static function trustReservedSubnets(array $trustedHeaders = self::X_FORWARDED_HEADERS): self + { + return self::trustProxies([ + '10.0.0.0/8', + '127.0.0.0/8', + '172.16.0.0/12', + '192.168.0.0/16', + '::1/128', // ipv6 localhost + 'fc00::/7', // ipv6 private networks + 'fe80::/10', // ipv6 local-link addresses + ], $trustedHeaders); + } + + private function isFromTrustedProxy(string $remoteAddress): bool + { + foreach ($this->trustedProxies as $proxy) { + if (IPRange::matches($remoteAddress, $proxy)) { + return true; + } + } + + return false; + } + + /** @throws InvalidForwardedHeaderNameException */ + private static function validateTrustedHeaders(array $headers): void + { + foreach ($headers as $header) { + if (! in_array($header, self::X_FORWARDED_HEADERS, true)) { + throw InvalidForwardedHeaderNameException::forHeader($header); + } + } + } + + /** + * @param list<non-empty-string> $proxyCIDRList + * @return list<non-empty-string> + * @throws InvalidProxyAddressException + */ + private static function normalizeProxiesList(array $proxyCIDRList): array + { + $foundWildcard = false; + + foreach ($proxyCIDRList as $index => $cidr) { + if ($cidr === '*') { + unset($proxyCIDRList[$index]); + $foundWildcard = true; + continue; + } + + if (! self::validateProxyCIDR($cidr)) { + throw InvalidProxyAddressException::forAddress($cidr); + } + } + + if ($foundWildcard) { + $proxyCIDRList[] = '0.0.0.0/0'; + $proxyCIDRList[] = '::/0'; + } + + return $proxyCIDRList; + } + + /** + * @param mixed $cidr + */ + private static function validateProxyCIDR($cidr): bool + { + if (! is_string($cidr) || '' === $cidr) { + return false; + } + + $address = $cidr; + $mask = null; + if (false !== strpos($cidr, '/')) { + [$address, $mask] = explode('/', $cidr, 2); + $mask = (int) $mask; + } + + if (false !== strpos($address, ':')) { + // is IPV6 + return filter_var($address, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6) + && ( + $mask === null + || ( + $mask <= 128 + && $mask >= 0 + ) + ); + } + + // is IPV4 + return filter_var($address, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4) + && ( + $mask === null + || ( + $mask <= 32 + && $mask >= 0 + ) + ); + } +} diff --git a/vendor/laminas/laminas-diactoros/src/ServerRequestFilter/IPRange.php b/vendor/laminas/laminas-diactoros/src/ServerRequestFilter/IPRange.php new file mode 100644 index 0000000000000000000000000000000000000000..871dde8421fd6334d361b62530ef7674b905a681 --- /dev/null +++ b/vendor/laminas/laminas-diactoros/src/ServerRequestFilter/IPRange.php @@ -0,0 +1,106 @@ +<?php + +declare(strict_types=1); + +namespace Laminas\Diactoros\ServerRequestFilter; + +/** @internal */ +final class IPRange +{ + /** + * Disable instantiation + */ + private function __construct() + { + } + + /** @psalm-pure */ + public static function matches(string $ip, string $cidr): bool + { + if (false !== strpos($ip, ':')) { + return self::matchesIPv6($ip, $cidr); + } + + return self::matchesIPv4($ip, $cidr); + } + + /** @psalm-pure */ + public static function matchesIPv4(string $ip, string $cidr): bool + { + $mask = 32; + $subnet = $cidr; + + if (false !== strpos($cidr, '/')) { + [$subnet, $mask] = explode('/', $cidr, 2); + $mask = (int) $mask; + } + + if ($mask < 0 || $mask > 32) { + return false; + } + + $ip = ip2long($ip); + $subnet = ip2long($subnet); + if (false === $ip || false === $subnet) { + // Invalid data + return false; + } + + return 0 === substr_compare( + sprintf("%032b", $ip), + sprintf("%032b", $subnet), + 0, + $mask + ); + } + + /** @psalm-pure */ + public static function matchesIPv6(string $ip, string $cidr): bool + { + $mask = 128; + $subnet = $cidr; + + if (false !== strpos($cidr, '/')) { + [$subnet, $mask] = explode('/', $cidr, 2); + $mask = (int) $mask; + } + + if ($mask < 0 || $mask > 128) { + return false; + } + + $ip = inet_pton($ip); + $subnet = inet_pton($subnet); + + if (false == $ip || false == $subnet) { + // Invalid data + return false; + } + + // mask 0: if it's a valid IP, it's valid + if ($mask === 0) { + return (bool) unpack('n*', $ip); + } + + // @see http://stackoverflow.com/questions/7951061/matching-ipv6-address-to-a-cidr-subnet, MW answer + $binMask = str_repeat("f", intval($mask / 4)); + switch ($mask % 4) { + case 0: + break; + case 1: + $binMask .= "8"; + break; + case 2: + $binMask .= "c"; + break; + case 3: + $binMask .= "e"; + break; + } + + $binMask = str_pad($binMask, 32, '0'); + $binMask = pack("H*", $binMask); + + return ($ip & $binMask) === $subnet; + } +} diff --git a/vendor/laminas/laminas-diactoros/src/UploadedFile.php b/vendor/laminas/laminas-diactoros/src/UploadedFile.php index 93980f307b76108d7c3c9bc25051b9945b5a7e50..e918697fba5770820f14391aebff4c4d6372a0e6 100644 --- a/vendor/laminas/laminas-diactoros/src/UploadedFile.php +++ b/vendor/laminas/laminas-diactoros/src/UploadedFile.php @@ -187,6 +187,13 @@ public function moveTo($targetPath) : void case (empty($sapi) || 0 === strpos($sapi, 'cli') || 0 === strpos($sapi, 'phpdbg') || ! $this->file): // Non-SAPI environment, or no filename present $this->writeFile($targetPath); + + if ($this->stream instanceof StreamInterface) { + $this->stream->close(); + } + if (is_string($this->file) && file_exists($this->file)) { + unlink($this->file); + } break; default: // SAPI environment, with file present diff --git a/vendor/laminas/laminas-diactoros/src/functions/marshal_uri_from_sapi.php b/vendor/laminas/laminas-diactoros/src/functions/marshal_uri_from_sapi.php index 778d31bfb670d59b6404ff9ae52ab7c555693def..0092aeff7ac7e8ef9adc9c0e654bc4626c055d31 100644 --- a/vendor/laminas/laminas-diactoros/src/functions/marshal_uri_from_sapi.php +++ b/vendor/laminas/laminas-diactoros/src/functions/marshal_uri_from_sapi.php @@ -22,6 +22,8 @@ * * @param array $server SAPI parameters * @param array $headers HTTP request headers + * @deprecated This function is deprecated as of 2.11.1, and will be removed in + * 3.0.0. As of 2.11.1, it is no longer used internally. */ function marshalUriFromSapi(array $server, array $headers) : Uri { diff --git a/vendor/symfony/http-client-contracts/Test/HttpClientTestCase.php b/vendor/symfony/http-client-contracts/Test/HttpClientTestCase.php index efb57bc1fe06ad034e7540c19bb083ba6001248d..7acd6b79c1a41f67f3e386cba81c47881bf1adfd 100644 --- a/vendor/symfony/http-client-contracts/Test/HttpClientTestCase.php +++ b/vendor/symfony/http-client-contracts/Test/HttpClientTestCase.php @@ -331,11 +331,16 @@ public function test304() $this->assertSame('', $response->getContent(false)); } - public function testRedirects() + /** + * @testWith [[]] + * [["Content-Length: 7"]] + */ + public function testRedirects(array $headers = []) { $client = $this->getHttpClient(__FUNCTION__); $response = $client->request('POST', 'http://localhost:8057/301', [ 'auth_basic' => 'foo:bar', + 'headers' => $headers, 'body' => function () { yield 'foo=bar'; }, diff --git a/vendor/symfony/service-contracts/ServiceSubscriberTrait.php b/vendor/symfony/service-contracts/ServiceSubscriberTrait.php index f7fc2df6a2fd9c06f96aee41db5c3e7e8d99bec0..16e3eb2c19757dc9593f897bf8ef2198f67a78ab 100644 --- a/vendor/symfony/service-contracts/ServiceSubscriberTrait.php +++ b/vendor/symfony/service-contracts/ServiceSubscriberTrait.php @@ -30,12 +30,6 @@ trait ServiceSubscriberTrait */ public static function getSubscribedServices(): array { - static $services; - - if (null !== $services) { - return $services; - } - $services = method_exists(get_parent_class(self::class) ?: '', __FUNCTION__) ? parent::getSubscribedServices() : []; $attributeOptIn = false; diff --git a/vendor/symfony/translation-contracts/Test/TranslatorTest.php b/vendor/symfony/translation-contracts/Test/TranslatorTest.php index 890367657843753631c4beecd0fcb8594ee2f04b..a3e9b20af56e5d06c39f3ba481d80d2db9ba6131 100644 --- a/vendor/symfony/translation-contracts/Test/TranslatorTest.php +++ b/vendor/symfony/translation-contracts/Test/TranslatorTest.php @@ -362,7 +362,7 @@ protected function validateMatrix($nplural, $matrix, $expectSuccess = true) foreach ($matrix as $langCode => $data) { $indexes = array_flip($data); if ($expectSuccess) { - $this->assertEquals($nplural, \count($indexes), "Langcode '$langCode' has '$nplural' plural forms."); + $this->assertCount($nplural, $indexes, "Langcode '$langCode' has '$nplural' plural forms."); } else { $this->assertNotEquals((int) $nplural, \count($indexes), "Langcode '$langCode' has '$nplural' plural forms."); } diff --git a/web/core/MAINTAINERS.txt b/web/core/MAINTAINERS.txt index e8ab8076cf982ffc3d2b8eb4e9346bcf15eec6d6..ab0f5769763e79fa9dce21051bef4f4e9e27473c 100644 --- a/web/core/MAINTAINERS.txt +++ b/web/core/MAINTAINERS.txt @@ -534,6 +534,10 @@ Decoupled Menus Initiative Media Initiative - Janez Urevc 'slashrsm' https://www.drupal.org/u/slashrsm +Project Browser Initiative +- Leslie Glynn 'leslieg' https://www.drupal.org/u/leslieg +- Chris Wells 'chrisfromredfin' https://www.drupal.org/u/chrisfromredfin + Core mentoring coordinators --------------------------- diff --git a/web/core/assets/scaffold/files/default.settings.php b/web/core/assets/scaffold/files/default.settings.php index 72be7750b93a427526891c4d02068fed3c9a74f6..f3dca008fa380e153e86c2a6bb953b4c030184b5 100644 --- a/web/core/assets/scaffold/files/default.settings.php +++ b/web/core/assets/scaffold/files/default.settings.php @@ -490,6 +490,29 @@ */ # $settings['file_public_path'] = 'sites/default/files'; +/** + * Additional public file schemes: + * + * Public schemes are URI schemes that allow download access to all users for + * all files within that scheme. + * + * The "public" scheme is always public, and the "private" scheme is always + * private, but other schemes, such as "https", "s3", "example", or others, + * can be either public or private depending on the site. By default, they're + * private, and access to individual files is controlled via + * hook_file_download(). + * + * Typically, if a scheme should be public, a module makes it public by + * implementing hook_file_download(), and granting access to all users for all + * files. This could be either the same module that provides the stream wrapper + * for the scheme, or a different module that decides to make the scheme + * public. However, in cases where a site needs to make a scheme public, but + * is unable to add code in a module to do so, the scheme may be added to this + * variable, the result of which is that system_file_download() grants public + * access to all files within that scheme. + */ +# $settings['file_additional_public_schemes'] = ['example']; + /** * Private file path: * diff --git a/web/core/assets/vendor/backbone/backbone-min.map b/web/core/assets/vendor/backbone/backbone-min.js.map similarity index 100% rename from web/core/assets/vendor/backbone/backbone-min.map rename to web/core/assets/vendor/backbone/backbone-min.js.map diff --git a/web/core/includes/common.inc b/web/core/includes/common.inc index ed359612c33849ad285c8caf26848ce1b2abbb1b..2bee0e5547e39e9255a5b3c7596b71f80c137a71 100644 --- a/web/core/includes/common.inc +++ b/web/core/includes/common.inc @@ -558,7 +558,9 @@ function drupal_flush_all_caches($kernel = NULL) { // Wipe the Twig PHP Storage cache. \Drupal::service('twig')->invalidate(); - // Rebuild theme data that is stored in state. + // Rebuild profile, profile, theme_engine and theme data. + \Drupal::service('extension.list.profile')->reset(); + \Drupal::service('extension.list.theme_engine')->reset(); \Drupal::service('theme_handler')->refreshInfo(); // In case the active theme gets requested later in the same request we need // to reset the theme manager. diff --git a/web/core/lib/Drupal.php b/web/core/lib/Drupal.php index 9e903214b2016f3de306154c8f386f9cc2992710..48cb4aa4b7d2705b4f5a27b3f22614901a36fa5f 100644 --- a/web/core/lib/Drupal.php +++ b/web/core/lib/Drupal.php @@ -75,7 +75,7 @@ class Drupal { /** * The current system version. */ - const VERSION = '9.4.1'; + const VERSION = '9.4.3'; /** * Core API compatibility. diff --git a/web/core/lib/Drupal/Core/Composer/Composer.php b/web/core/lib/Drupal/Core/Composer/Composer.php index fc7ce25cd4bb6898f252fdaaaa02a1829986f41c..4f7fcda1d3b27e6f65d07892ed85dca5dbc2ec18 100644 --- a/web/core/lib/Drupal/Core/Composer/Composer.php +++ b/web/core/lib/Drupal/Core/Composer/Composer.php @@ -130,13 +130,6 @@ public static function preAutoloadDump(Event $event) { $vendor_dir . '/symfony/http-kernel/TerminableInterface.php', ]); } - if ($repository->findPackage('symfony/http-kernel', $constraint)) { - $autoload['classmap'] = array_merge($autoload['classmap'], [ - $vendor_dir . '/symfony/http-kernel/HttpKernel.php', - $vendor_dir . '/symfony/http-kernel/HttpKernelInterface.php', - $vendor_dir . '/symfony/http-kernel/TerminableInterface.php', - ]); - } if ($repository->findPackage('symfony/dependency-injection', $constraint)) { $autoload['classmap'] = array_merge($autoload['classmap'], [ $vendor_dir . '/symfony/dependency-injection/ContainerAwareInterface.php', diff --git a/web/core/lib/Drupal/Core/DependencyInjection/Compiler/DependencySerializationTraitPass.php b/web/core/lib/Drupal/Core/DependencyInjection/Compiler/DependencySerializationTraitPass.php index 4952283967863dd72b0038d11d54885e33afeb45..a0ba7f0225e37255ea7b0aead8ab6c6a80d0a133 100644 --- a/web/core/lib/Drupal/Core/DependencyInjection/Compiler/DependencySerializationTraitPass.php +++ b/web/core/lib/Drupal/Core/DependencyInjection/Compiler/DependencySerializationTraitPass.php @@ -16,12 +16,34 @@ class DependencySerializationTraitPass implements CompilerPassInterface { * {@inheritdoc} */ public function process(ContainerBuilder $container) { + $decorations = new \SplPriorityQueue(); + $order = PHP_INT_MAX; + foreach ($container->getDefinitions() as $service_id => $definition) { // Only add the property to services that are public (as private services // can not be reloaded through Container::get()) and are objects. if (!$definition->hasTag('parameter_service') && $definition->isPublic()) { $definition->setProperty('_serviceId', $service_id); } + + if ($decorated = $definition->getDecoratedService()) { + $decorations->insert([$service_id, $definition], [$decorated[2], --$order]); + } + } + + foreach ($decorations as list($service_id, $definition)) { + list($inner, $renamedId) = $definition->getDecoratedService(); + if (!$renamedId) { + $renamedId = $service_id . '.inner'; + } + + $original = $container->getDefinition($inner); + if ($original->isPublic()) { + // The old service is renamed. + $original->setProperty('_serviceId', $renamedId); + // The decorating service takes over the old ID. + $definition->setProperty('_serviceId', $inner); + } } } diff --git a/web/core/lib/Drupal/Core/File/FileSystemInterface.php b/web/core/lib/Drupal/Core/File/FileSystemInterface.php index c1781b6944f4943906feefdbd6ae8eefc42edcb5..59d2ee37f0b7477390b815f1ca55380152fad258 100644 --- a/web/core/lib/Drupal/Core/File/FileSystemInterface.php +++ b/web/core/lib/Drupal/Core/File/FileSystemInterface.php @@ -37,14 +37,14 @@ interface FileSystemInterface { * * @see \Drupal\Core\File\FileSystemInterface::INSECURE_EXTENSION_REGEX */ - public const INSECURE_EXTENSIONS = ['phar', 'php', 'pl', 'py', 'cgi', 'asp', 'js']; + public const INSECURE_EXTENSIONS = ['phar', 'php', 'pl', 'py', 'cgi', 'asp', 'js', 'htaccess']; /** * The regex pattern used when checking for insecure file types. * * @see \Drupal\Core\File\FileSystemInterface::INSECURE_EXTENSIONS */ - public const INSECURE_EXTENSION_REGEX = '/\.(phar|php|pl|py|cgi|asp|js)(\.|$)/i'; + public const INSECURE_EXTENSION_REGEX = '/\.(phar|php|pl|py|cgi|asp|js|htaccess)(\.|$)/i'; /** * Moves an uploaded file to a new location. diff --git a/web/core/lib/Drupal/Core/Form/FormBuilder.php b/web/core/lib/Drupal/Core/Form/FormBuilder.php index 4ed0faed77bf6273dee48547466b3d0237f81dc1..98eb3263429675d8b0f7f98dc37d0697c7b183ca 100644 --- a/web/core/lib/Drupal/Core/Form/FormBuilder.php +++ b/web/core/lib/Drupal/Core/Form/FormBuilder.php @@ -1217,7 +1217,12 @@ protected function handleInputElement($form_id, &$element, FormStateInterface &$ // #access=FALSE on an element usually allow access for some users, so forms // submitted with self::submitForm() may bypass access restriction and be // treated as high-privilege users instead. - $process_input = empty($element['#disabled']) && !in_array($element['#type'], ['item', 'value'], TRUE) && (($form_state->isProgrammed() && $form_state->isBypassingProgrammedAccessChecks()) || ($form_state->isProcessingInput() && (!isset($element['#access']) || $element['#access']))); + $process_input = empty($element['#disabled']) && + !in_array($element['#type'], ['item', 'value'], TRUE) && + ( + ($form_state->isProgrammed() && $form_state->isBypassingProgrammedAccessChecks()) || + ($form_state->isProcessingInput() && (!isset($element['#access']) || (($element['#access'] instanceof AccessResultInterface && $element['#access']->isAllowed()) || ($element['#access'] === TRUE)))) + ); // Set the element's #value property. if (!isset($element['#value']) && !array_key_exists('#value', $element)) { diff --git a/web/core/lib/Drupal/Core/Site/Settings.php b/web/core/lib/Drupal/Core/Site/Settings.php index 31d494f8b49df889d2651755ff77816ce0091c5c..5509e2be26ca87007d39e484d38d10c81bbcdc25 100644 --- a/web/core/lib/Drupal/Core/Site/Settings.php +++ b/web/core/lib/Drupal/Core/Site/Settings.php @@ -207,7 +207,7 @@ public static function initialize($app_root, $site_path, &$class_loader) { // the database. Therefore, allow the connection info to specify an // autoload directory for the driver. if (isset($info['autoload'])) { - $class_loader->addPsr4($info['namespace'] . '\\', $info['autoload']); + $class_loader->addPsr4($info['namespace'] . '\\', $app_root . '/' . $info['autoload']); } } } diff --git a/web/core/lib/Drupal/Core/StreamWrapper/PublicStream.php b/web/core/lib/Drupal/Core/StreamWrapper/PublicStream.php index e89e43219eab46b3fca9ec4310fe50dfc5d86d57..1747bf37c5f58ecb19582ddbe7d9e5926b0ba330 100644 --- a/web/core/lib/Drupal/Core/StreamWrapper/PublicStream.php +++ b/web/core/lib/Drupal/Core/StreamWrapper/PublicStream.php @@ -115,4 +115,28 @@ public static function basePath($site_path = NULL) { return Settings::get('file_public_path', $site_path . '/files'); } + /** + * {@inheritdoc} + */ + protected function getLocalPath($uri = NULL) { + $path = parent::getLocalPath($uri); + if (!$path || (strpos($path, 'vfs://') === 0)) { + return $path; + } + + if (Settings::get('sa_core_2022_012_override') === TRUE) { + return $path; + } + + $private_path = Settings::get('file_private_path'); + if ($private_path) { + $private_path = realpath($private_path); + if ($private_path && strpos($path, $private_path) === 0) { + return FALSE; + } + } + + return $path; + } + } diff --git a/web/core/modules/ckeditor5/config/schema/ckeditor5.schema.yml b/web/core/modules/ckeditor5/config/schema/ckeditor5.schema.yml index b7c670a6832ce672f3a171cb8580f7f8f9ba14e9..c58dce3fed5ba9f56b08756678969f0ca529d5ae 100644 --- a/web/core/modules/ckeditor5/config/schema/ckeditor5.schema.yml +++ b/web/core/modules/ckeditor5/config/schema/ckeditor5.schema.yml @@ -127,7 +127,7 @@ ckeditor5.plugin.ckeditor5_list: # Plugin \Drupal\ckeditor5\Plugin\CKEditor5Plugin\Media ckeditor5.plugin.media_media: type: mapping - label: List + label: Media mapping: allow_view_mode_override: type: boolean diff --git a/web/core/modules/config/src/Form/ConfigSingleExportForm.php b/web/core/modules/config/src/Form/ConfigSingleExportForm.php index 22e0b4837f680f0e43dd92fb0a04cdbf906a66ce..dc46b45814d3d74be43605b5741b7da954735f10 100644 --- a/web/core/modules/config/src/Form/ConfigSingleExportForm.php +++ b/web/core/modules/config/src/Form/ConfigSingleExportForm.php @@ -136,7 +136,7 @@ public function buildForm(array $form, FormStateInterface $form_state, $config_t */ public function updateConfigurationType($form, FormStateInterface $form_state) { $form['config_name']['#options'] = $this->findConfiguration($form_state->getValue('config_type')); - unset($form['export']['#value']); + $form['export']['#value'] = NULL; return $form; } diff --git a/web/core/modules/config/tests/config_override_test/src/ConfigOverrider.php b/web/core/modules/config/tests/config_override_test/src/ConfigOverrider.php index c8ffc694b3f23729c518866ebf076b39ca7a763d..8ec572e3aeb55d577c97311eff6eb6fcf194c9bf 100644 --- a/web/core/modules/config/tests/config_override_test/src/ConfigOverrider.php +++ b/web/core/modules/config/tests/config_override_test/src/ConfigOverrider.php @@ -4,6 +4,7 @@ use Drupal\Core\Cache\CacheableMetadata; use Drupal\Core\Config\ConfigFactoryOverrideInterface; +use Drupal\Core\Config\StorageInterface; /** * Tests module overrides for configuration. diff --git a/web/core/modules/field/src/Plugin/migrate/process/d6/FieldInstanceSettings.php b/web/core/modules/field/src/Plugin/migrate/process/d6/FieldInstanceSettings.php index be41a4209ca580bca911d6c253842f248f966b3c..ca5741b177090904fea66d4ebe47d2bcfce515cd 100644 --- a/web/core/modules/field/src/Plugin/migrate/process/d6/FieldInstanceSettings.php +++ b/web/core/modules/field/src/Plugin/migrate/process/d6/FieldInstanceSettings.php @@ -49,7 +49,7 @@ public function transform($value, MigrateExecutableInterface $migrate_executable case 'imagefield_widget': $settings['file_extensions'] = $widget_settings['file_extensions']; $settings['file_directory'] = $widget_settings['file_path']; - $settings['max_filesize'] = $this->convertSizeUnit($widget_settings['max_filesize_per_file']); + $settings['max_filesize'] = $this->convertSizeUnit($widget_settings['max_filesize_per_file'] ?? ''); $settings['alt_field'] = $widget_settings['alt']; $settings['alt_field_required'] = $widget_settings['custom_alt']; $settings['title_field'] = $widget_settings['title']; diff --git a/web/core/modules/field/tests/src/Unit/Plugin/migrate/process/d6/FieldInstanceSettingsTest.php b/web/core/modules/field/tests/src/Unit/Plugin/migrate/process/d6/FieldInstanceSettingsTest.php new file mode 100644 index 0000000000000000000000000000000000000000..27f830a611e5c4ee81f4472bf93e2bc1934a79f3 --- /dev/null +++ b/web/core/modules/field/tests/src/Unit/Plugin/migrate/process/d6/FieldInstanceSettingsTest.php @@ -0,0 +1,81 @@ +<?php + +namespace Drupal\Tests\field\Unit\Plugin\migrate\process\d6; + +use Drupal\field\Plugin\migrate\process\d6\FieldInstanceSettings; +use Drupal\migrate\Plugin\MigrationInterface; +use Drupal\migrate\MigrateExecutableInterface; +use Drupal\migrate\Row; +use Drupal\Tests\UnitTestCase; + +// cspell:ignore imagefield + +/** + * @coversDefaultClass \Drupal\field\Plugin\migrate\process\d6\FieldInstanceSettings + * @group field + */ +class FieldInstanceSettingsTest extends UnitTestCase { + + /** + * @covers ::getSettings + * + * @dataProvider getSettingsProvider + */ + public function testGetSettings($field_type, $instance_settings, $expected) { + $instance_settings = unserialize($instance_settings); + $migration = $this->createMock(MigrationInterface::class); + $plugin = new FieldInstanceSettings([], 'd6_field_field_settings', [], $migration); + + $executable = $this->createMock(MigrateExecutableInterface::class); + $row = $this->getMockBuilder(Row::class) + ->disableOriginalConstructor() + ->getMock(); + + $result = $plugin->transform([ + $field_type, + $instance_settings, + NULL, + ], $executable, $row, 'foo'); + $this->assertSame($expected, $result); + } + + /** + * Provides field settings for testGetSettings(). + */ + public function getSettingsProvider() { + return [ + 'imagefield size set' => [ + 'imagefield_widget', + 'a:14:{s:15:"file_extensions";s:11:"gif jpg png";s:9:"file_path";N;s:18:"progress_indicator";N;s:21:"max_filesize_per_file";s:3:"10M";s:21:"max_filesize_per_node";N;s:14:"max_resolution";N;s:14:"min_resolution";N;s:3:"alt";N;s:10:"custom_alt";i:1;s:5:"title";N;s:12:"custom_title";i:1;s:10:"title_type";N;s:13:"default_image";N;s:17:"use_default_image";N;}', + [ + 'file_extensions' => 'gif jpg png', + 'file_directory' => NULL, + 'max_filesize' => '10MB', + 'alt_field' => NULL, + 'alt_field_required' => 1, + 'title_field' => NULL, + 'title_field_required' => 1, + 'max_resolution' => '', + 'min_resolution' => '', + ], + ], + 'imagefield size NULL' => [ + 'imagefield_widget', + 'a:14:{s:15:"file_extensions";s:11:"gif jpg png";s:9:"file_path";N;s:18:"progress_indicator";N;s:21:"max_filesize_per_file";N;s:21:"max_filesize_per_node";N;s:14:"max_resolution";N;s:14:"min_resolution";N;s:3:"alt";N;s:10:"custom_alt";i:1;s:5:"title";N;s:12:"custom_title";i:1;s:10:"title_type";N;s:13:"default_image";N;s:17:"use_default_image";N;}', + [ + 'file_extensions' => 'gif jpg png', + 'file_directory' => NULL, + 'max_filesize' => '', + 'alt_field' => NULL, + 'alt_field_required' => 1, + 'title_field' => NULL, + 'title_field_required' => 1, + 'max_resolution' => '', + 'min_resolution' => '', + ], + ], + + ]; + } + +} diff --git a/web/core/modules/hal/tests/src/Functional/quickedit/QuickEditLayoutBuilderEntityViewDisplayHalJsonAnonTest.php b/web/core/modules/hal/tests/src/Functional/quickedit/QuickEditLayoutBuilderEntityViewDisplayHalJsonAnonTest.php new file mode 100644 index 0000000000000000000000000000000000000000..128c50ebe0801c8553a2e824e13625422d59b6fb --- /dev/null +++ b/web/core/modules/hal/tests/src/Functional/quickedit/QuickEditLayoutBuilderEntityViewDisplayHalJsonAnonTest.php @@ -0,0 +1,18 @@ +<?php + +namespace Drupal\Tests\hal\Functional\quickedit; + +use Drupal\Tests\hal\Functional\layout_builder\LayoutBuilderEntityViewDisplayHalJsonAnonTest; + +/** + * @group hal + * @group legacy + */ +class QuickEditLayoutBuilderEntityViewDisplayHalJsonAnonTest extends LayoutBuilderEntityViewDisplayHalJsonAnonTest { + + /** + * {@inheritdoc} + */ + protected static $modules = ['quickedit']; + +} diff --git a/web/core/modules/hal/tests/src/Functional/quickedit/QuickEditLayoutBuilderEntityViewDisplayHalJsonBasicAuthTest.php b/web/core/modules/hal/tests/src/Functional/quickedit/QuickEditLayoutBuilderEntityViewDisplayHalJsonBasicAuthTest.php new file mode 100644 index 0000000000000000000000000000000000000000..7ec69ae947ba9ad841df96c29c1d98877d8dceec --- /dev/null +++ b/web/core/modules/hal/tests/src/Functional/quickedit/QuickEditLayoutBuilderEntityViewDisplayHalJsonBasicAuthTest.php @@ -0,0 +1,18 @@ +<?php + +namespace Drupal\Tests\hal\Functional\quickedit; + +use Drupal\Tests\hal\Functional\layout_builder\LayoutBuilderEntityViewDisplayHalJsonBasicAuthTest; + +/** + * @group hal + * @group legacy + */ +class QuickEditLayoutBuilderEntityViewDisplayHalJsonBasicAuthTest extends LayoutBuilderEntityViewDisplayHalJsonBasicAuthTest { + + /** + * {@inheritdoc} + */ + protected static $modules = ['quickedit']; + +} diff --git a/web/core/modules/hal/tests/src/Functional/quickedit/QuickEditLayoutBuilderEntityViewDisplayHalJsonCookieTest.php b/web/core/modules/hal/tests/src/Functional/quickedit/QuickEditLayoutBuilderEntityViewDisplayHalJsonCookieTest.php new file mode 100644 index 0000000000000000000000000000000000000000..8e9520663a1c952c189177fa7401d3315978ad28 --- /dev/null +++ b/web/core/modules/hal/tests/src/Functional/quickedit/QuickEditLayoutBuilderEntityViewDisplayHalJsonCookieTest.php @@ -0,0 +1,18 @@ +<?php + +namespace Drupal\Tests\hal\Functional\quickedit; + +use Drupal\Tests\hal\Functional\layout_builder\LayoutBuilderEntityViewDisplayHalJsonCookieTest; + +/** + * @group hal + * @group legacy + */ +class QuickEditLayoutBuilderEntityViewDisplayHalJsonCookieTest extends LayoutBuilderEntityViewDisplayHalJsonCookieTest { + + /** + * {@inheritdoc} + */ + protected static $modules = ['quickedit']; + +} diff --git a/web/core/modules/image/src/Controller/ImageStyleDownloadController.php b/web/core/modules/image/src/Controller/ImageStyleDownloadController.php index 6ded44fab6b47f63cea902288de181bc6fac99b2..c943452b5b8c2b7ff64d8d3e13097cb61ef51c77 100644 --- a/web/core/modules/image/src/Controller/ImageStyleDownloadController.php +++ b/web/core/modules/image/src/Controller/ImageStyleDownloadController.php @@ -6,6 +6,7 @@ use Drupal\Core\File\FileSystemInterface; use Drupal\Core\Image\ImageFactory; use Drupal\Core\Lock\LockBackendInterface; +use Drupal\Core\Site\Settings; use Drupal\Core\StreamWrapper\StreamWrapperManager; use Drupal\Core\StreamWrapper\StreamWrapperManagerInterface; use Drupal\image\ImageStyleInterface; @@ -114,21 +115,25 @@ public function deliver(Request $request, $scheme, ImageStyleInterface $image_st $target = $request->query->get('file'); $image_uri = $scheme . '://' . $target; - // Check that the style is defined, the scheme is valid, and the image - // derivative token is valid. Sites which require image derivatives to be - // generated without a token can set the + // Check that the style is defined and the scheme is valid. + $valid = !empty($image_style) && $this->streamWrapperManager->isValidScheme($scheme); + + // Also validate the derivative token. Sites which require image + // derivatives to be generated without a token can set the // 'image.settings:allow_insecure_derivatives' configuration to TRUE to - // bypass the latter check, but this will increase the site's vulnerability + // bypass this check, but this will increase the site's vulnerability // to denial-of-service attacks. To prevent this variable from leaving the // site vulnerable to the most serious attacks, a token is always required // when a derivative of a style is requested. // The $target variable for a derivative of a style has // styles/<style_name>/... as structure, so we check if the $target variable // starts with styles/. - $valid = !empty($image_style) && $this->streamWrapperManager->isValidScheme($scheme); + $token = $request->query->get(IMAGE_DERIVATIVE_TOKEN, ''); + $token_is_valid = hash_equals($image_style->getPathToken($image_uri), $token); if (!$this->config('image.settings')->get('allow_insecure_derivatives') || strpos(ltrim($target, '\/'), 'styles/') === 0) { - $valid &= hash_equals($image_style->getPathToken($image_uri), $request->query->get(IMAGE_DERIVATIVE_TOKEN, '')); + $valid = $valid && $token_is_valid; } + if (!$valid) { // Return a 404 (Page Not Found) rather than a 403 (Access Denied) as the // image token is for DDoS protection rather than access checking. 404s @@ -138,11 +143,23 @@ public function deliver(Request $request, $scheme, ImageStyleInterface $image_st } $derivative_uri = $image_style->buildUri($image_uri); + $derivative_scheme = $this->streamWrapperManager->getScheme($derivative_uri); + + if ($token_is_valid) { + $is_public = ($scheme !== 'private'); + } + else { + $core_schemes = ['public', 'private', 'temporary']; + $additional_public_schemes = array_diff(Settings::get('file_additional_public_schemes', []), $core_schemes); + $public_schemes = array_merge(['public'], $additional_public_schemes); + $is_public = in_array($derivative_scheme, $public_schemes, TRUE); + } + $headers = []; - // If using the private scheme, let other modules provide headers and + // If not using a public scheme, let other modules provide headers and // control access to the file. - if ($scheme == 'private') { + if (!$is_public) { $headers = $this->moduleHandler()->invokeAll('file_download', [$image_uri]); if (in_array(-1, $headers) || empty($headers)) { throw new AccessDeniedHttpException(); @@ -150,14 +167,14 @@ public function deliver(Request $request, $scheme, ImageStyleInterface $image_st } // Don't try to generate file if source is missing. - if (!file_exists($image_uri)) { + if (!$this->sourceImageExists($image_uri, $token_is_valid)) { // If the image style converted the extension, it has been added to the // original file, resulting in filenames like image.png.jpeg. So to find // the actual source image, we remove the extension and check if that // image exists. $path_info = pathinfo(StreamWrapperManager::getTarget($image_uri)); $converted_image_uri = sprintf('%s://%s%s%s', $this->streamWrapperManager->getScheme($derivative_uri), $path_info['dirname'], DIRECTORY_SEPARATOR, $path_info['filename']); - if (!file_exists($converted_image_uri)) { + if (!$this->sourceImageExists($converted_image_uri, $token_is_valid)) { $this->logger->notice('Source image at %source_image_path not found while trying to generate derivative image at %derivative_path.', ['%source_image_path' => $image_uri, '%derivative_path' => $derivative_uri]); return new Response($this->t('Error generating image, missing source file.'), 404); } @@ -196,9 +213,9 @@ public function deliver(Request $request, $scheme, ImageStyleInterface $image_st ]; // \Drupal\Core\EventSubscriber\FinishResponseSubscriber::onRespond() // sets response as not cacheable if the Cache-Control header is not - // already modified. We pass in FALSE for non-private schemes for the - // $public parameter to make sure we don't change the headers. - return new BinaryFileResponse($uri, 200, $headers, $scheme !== 'private'); + // already modified. When $is_public is TRUE, the following sets the + // Cache-Control header to "public". + return new BinaryFileResponse($uri, 200, $headers, $is_public); } else { $this->logger->notice('Unable to generate the derived image located at %path.', ['%path' => $derivative_uri]); @@ -206,4 +223,43 @@ public function deliver(Request $request, $scheme, ImageStyleInterface $image_st } } + /** + * Checks whether the provided source image exists. + * + * @param string $image_uri + * The URI for the source image. + * @param bool $token_is_valid + * Whether a valid image token was supplied. + * + * @return bool + * Whether the source image exists. + */ + private function sourceImageExists(string $image_uri, bool $token_is_valid): bool { + $exists = file_exists($image_uri); + + // If the file doesn't exist, we can stop here. + if (!$exists) { + return FALSE; + } + + if ($token_is_valid) { + return TRUE; + } + + if (StreamWrapperManager::getScheme($image_uri) !== 'public') { + return TRUE; + } + + $image_path = $this->fileSystem->realpath($image_uri); + $private_path = Settings::get('file_private_path'); + if ($private_path) { + $private_path = realpath($private_path); + if ($private_path && strpos($image_path, $private_path) === 0) { + return FALSE; + } + } + + return TRUE; + } + } diff --git a/web/core/modules/jsonapi/src/Normalizer/ResourceObjectNormalizer.php b/web/core/modules/jsonapi/src/Normalizer/ResourceObjectNormalizer.php index e4988c9096e98ed40d79f30d0db0ba0be187690e..340fcb21bd92f1663bd8565da249d98324825ca9 100644 --- a/web/core/modules/jsonapi/src/Normalizer/ResourceObjectNormalizer.php +++ b/web/core/modules/jsonapi/src/Normalizer/ResourceObjectNormalizer.php @@ -192,7 +192,7 @@ protected function serializeField($field, array $context, $format) { // @todo Replace this workaround after https://www.drupal.org/node/3043245 // or remove the need for this in https://www.drupal.org/node/2942975. // See \Drupal\layout_builder\Normalizer\LayoutEntityDisplayNormalizer. - if ($context['resource_object']->getResourceType()->getDeserializationTargetClass() === 'Drupal\layout_builder\Entity\LayoutBuilderEntityViewDisplay' && $context['resource_object']->getField('third_party_settings') === $field) { + if (is_a($context['resource_object']->getResourceType()->getDeserializationTargetClass(), 'Drupal\layout_builder\Entity\LayoutBuilderEntityViewDisplay', TRUE) && $context['resource_object']->getField('third_party_settings') === $field) { unset($field['layout_builder']['sections']); } diff --git a/web/core/modules/layout_builder/layout_builder.module b/web/core/modules/layout_builder/layout_builder.module index 6e8d0a25f93a20a25303b4cfbb3f6f1f63c55a8f..1646139aa7bf8aed43d3d91c698a6311746a7215 100644 --- a/web/core/modules/layout_builder/layout_builder.module +++ b/web/core/modules/layout_builder/layout_builder.module @@ -26,7 +26,6 @@ use Drupal\Core\Session\AccountInterface; use Drupal\Core\Access\AccessResult; use Drupal\layout_builder\Plugin\SectionStorage\OverridesSectionStorage; -use Drupal\layout_builder\QuickEditIntegration; /** * Implements hook_help(). @@ -162,12 +161,6 @@ function layout_builder_entity_view_alter(array &$build, EntityInterface $entity if ($display instanceof LayoutBuilderEntityViewDisplay && strpos($route_name, 'layout_builder.') === 0) { unset($build['#contextual_links']); } - - if (\Drupal::moduleHandler()->moduleExists('quickedit')) { - /** @var \Drupal\layout_builder\QuickEditIntegration $quick_edit_integration */ - $quick_edit_integration = \Drupal::classResolver(QuickEditIntegration::class); - $quick_edit_integration->entityViewAlter($build, $entity, $display); - } } /** @@ -351,15 +344,6 @@ function layout_builder_system_breadcrumb_alter(Breadcrumb &$breadcrumb, RouteMa } } -/** - * Implements hook_quickedit_render_field(). - */ -function layout_builder_quickedit_render_field(EntityInterface $entity, $field_name, $view_mode_id, $langcode) { - /** @var \Drupal\layout_builder\QuickEditIntegration $quick_edit_integration */ - $quick_edit_integration = \Drupal::classResolver(QuickEditIntegration::class); - return $quick_edit_integration->quickEditRenderField($entity, $field_name, $view_mode_id, $langcode); -} - /** * Implements hook_entity_translation_create(). */ diff --git a/web/core/modules/layout_builder/src/Entity/LayoutBuilderEntityViewDisplay.php b/web/core/modules/layout_builder/src/Entity/LayoutBuilderEntityViewDisplay.php index d543fe1619557edbaf532c41c700706515218e93..c63b96ff01d50d12991ae7f893fbd07436fed4fc 100644 --- a/web/core/modules/layout_builder/src/Entity/LayoutBuilderEntityViewDisplay.php +++ b/web/core/modules/layout_builder/src/Entity/LayoutBuilderEntityViewDisplay.php @@ -18,7 +18,6 @@ use Drupal\field\Entity\FieldStorageConfig; use Drupal\layout_builder\LayoutEntityHelperTrait; use Drupal\layout_builder\Plugin\SectionStorage\OverridesSectionStorage; -use Drupal\layout_builder\QuickEditIntegration; use Drupal\layout_builder\Section; use Drupal\layout_builder\SectionComponent; use Drupal\layout_builder\SectionListTrait; @@ -473,7 +472,7 @@ private function sectionStorageManager() { * {@inheritdoc} */ public function getComponent($name) { - if ($this->isLayoutBuilderEnabled() && $section_component = $this->getQuickEditSectionComponent() ?: $this->getSectionComponentForFieldName($name)) { + if ($this->isLayoutBuilderEnabled() && $section_component = $this->getSectionComponentForFieldName($name)) { $plugin = $section_component->getPlugin(); if ($plugin instanceof ConfigurableInterface) { $configuration = $plugin->getConfiguration(); @@ -485,43 +484,6 @@ public function getComponent($name) { return parent::getComponent($name); } - /** - * Returns the Quick Edit formatter settings. - * - * @return \Drupal\layout_builder\SectionComponent|null - * The section component if it is available. - * - * @see \Drupal\layout_builder\QuickEditIntegration::entityViewAlter() - * @see \Drupal\quickedit\MetadataGenerator::generateFieldMetadata() - */ - private function getQuickEditSectionComponent() { - // To determine the Quick Edit view_mode ID we need an originalMode set. - if ($original_mode = $this->getOriginalMode()) { - $parts = explode('-', $original_mode); - // The Quick Edit view mode ID is created by - // \Drupal\layout_builder\QuickEditIntegration::entityViewAlter() - // concatenating together the information we need to retrieve the Layout - // Builder component. It follows the structure prescribed by the - // documentation of hook_quickedit_render_field(). - if (count($parts) === 6 && $parts[0] === 'layout_builder') { - [, $delta, $component_uuid, $entity_id] = QuickEditIntegration::deconstructViewModeId($original_mode); - $entity = $this->entityTypeManager()->getStorage($this->getTargetEntityTypeId())->load($entity_id); - $sections = $this->getEntitySections($entity); - if (isset($sections[$delta])) { - $component = $sections[$delta]->getComponent($component_uuid); - $plugin = $component->getPlugin(); - // We only care about FieldBlock because these are only components - // that provide Quick Edit integration: Quick Edit enables in-place - // editing of fields of entities, not of anything else. - if ($plugin instanceof DerivativeInspectionInterface && $plugin->getBaseId() === 'field_block') { - return $component; - } - } - } - } - return NULL; - } - /** * Gets the component for a given field name if any. * diff --git a/web/core/modules/layout_builder/src/InlineBlockEntityOperations.php b/web/core/modules/layout_builder/src/InlineBlockEntityOperations.php index ad255cd6fecf9906252463f23f142216215959c7..5b11bbe674833d785c7e5784dfbd18eea73d6a21 100644 --- a/web/core/modules/layout_builder/src/InlineBlockEntityOperations.php +++ b/web/core/modules/layout_builder/src/InlineBlockEntityOperations.php @@ -44,18 +44,12 @@ class InlineBlockEntityOperations implements ContainerInjectionInterface { /** * Constructs a new EntityOperations object. * - * @todo This constructor has one optional parameter, $section_storage_manager - * and one totally unused $database parameter. Deprecate the current - * constructor signature in https://www.drupal.org/node/3031492 after the - * general policy for constructor backwards compatibility is determined in - * https://www.drupal.org/node/3030640. - * * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entityTypeManager * The entity type manager service. * @param \Drupal\layout_builder\InlineBlockUsageInterface $usage * Inline block usage tracking service. * @param \Drupal\layout_builder\SectionStorage\SectionStorageManagerInterface $section_storage_manager - * (optional) The section storage manager. + * The section storage manager. */ public function __construct(EntityTypeManagerInterface $entityTypeManager, InlineBlockUsageInterface $usage, SectionStorageManagerInterface $section_storage_manager) { $this->entityTypeManager = $entityTypeManager; diff --git a/web/core/modules/layout_builder/src/QuickEditIntegration.php b/web/core/modules/layout_builder/src/QuickEditIntegration.php index c087f90971f5e7759bd0ff91c1a10317685391f3..90c082ae8802a72979f17f0b78d99109f0d01208 100644 --- a/web/core/modules/layout_builder/src/QuickEditIntegration.php +++ b/web/core/modules/layout_builder/src/QuickEditIntegration.php @@ -2,21 +2,9 @@ namespace Drupal\layout_builder; -use Drupal\Component\Utility\NestedArray; -use Drupal\Core\Cache\CacheableMetadata; -use Drupal\Core\DependencyInjection\ContainerInjectionInterface; -use Drupal\Core\Entity\Display\EntityViewDisplayInterface; -use Drupal\Core\Entity\EntityInterface; -use Drupal\Core\Entity\EntityTypeManagerInterface; -use Drupal\Core\Entity\FieldableEntityInterface; -use Drupal\Core\Logger\LoggerChannelTrait; -use Drupal\Core\Plugin\Context\Context; -use Drupal\Core\Plugin\Context\ContextDefinition; -use Drupal\Core\Plugin\Context\EntityContext; -use Drupal\Core\Render\Element; -use Drupal\Core\Session\AccountInterface; -use Drupal\layout_builder\SectionStorage\SectionStorageManagerInterface; -use Symfony\Component\DependencyInjection\ContainerInterface; +@trigger_error(__NAMESPACE__ . '\QuickEditIntegration is deprecated in drupal:9.4.2 and is removed from drupal:10.0.0. Instead, use \Drupal\quickedit\LayoutBuilderIntegration. See https://www.drupal.org/node/3265518', E_USER_DEPRECATED); + +use Drupal\quickedit\LayoutBuilderIntegration; /** * Helper methods for Quick Edit module integration. @@ -24,298 +12,4 @@ * @internal * This is an internal utility class wrapping hook implementations. */ -class QuickEditIntegration implements ContainerInjectionInterface { - - use LoggerChannelTrait; - - /** - * The section storage manager. - * - * @var \Drupal\layout_builder\SectionStorage\SectionStorageManagerInterface - */ - protected $sectionStorageManager; - - /** - * The current user. - * - * @var \Drupal\Core\Session\AccountInterface - */ - protected $currentUser; - - /** - * The entity type manager. - * - * @var \Drupal\Core\Entity\EntityTypeManagerInterface - */ - protected $entityTypeManager; - - /** - * Constructs a new QuickEditIntegration object. - * - * @param \Drupal\layout_builder\SectionStorage\SectionStorageManagerInterface $section_storage_manager - * The section storage manager. - * @param \Drupal\Core\Session\AccountInterface $current_user - * The current user. - * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager - * The entity type manager. - */ - public function __construct(SectionStorageManagerInterface $section_storage_manager, AccountInterface $current_user, EntityTypeManagerInterface $entity_type_manager) { - $this->sectionStorageManager = $section_storage_manager; - $this->currentUser = $current_user; - $this->entityTypeManager = $entity_type_manager; - } - - /** - * {@inheritdoc} - */ - public static function create(ContainerInterface $container) { - return new static( - $container->get('plugin.manager.layout_builder.section_storage'), - $container->get('current_user'), - $container->get('entity_type.manager') - ); - } - - /** - * Alters the entity view build for Quick Edit compatibility. - * - * When rendering fields outside of normal view modes, Quick Edit requires - * that modules identify themselves with a view mode ID in the format - * [module_name]-[information the module needs to rerender], as prescribed by - * hook_quickedit_render_field(). - * - * @param array $build - * The built entity render array. - * @param \Drupal\Core\Entity\EntityInterface $entity - * The entity. - * @param \Drupal\Core\Entity\Display\EntityViewDisplayInterface $display - * The entity view display. - * - * @see hook_quickedit_render_field() - * @see layout_builder_quickedit_render_field() - */ - public function entityViewAlter(array &$build, EntityInterface $entity, EntityViewDisplayInterface $display) { - if (!$entity instanceof FieldableEntityInterface || !isset($build['_layout_builder'])) { - return; - } - - $build['#cache']['contexts'][] = 'user.permissions'; - if (!$this->currentUser->hasPermission('access in-place editing')) { - return; - } - - $cacheable_metadata = CacheableMetadata::createFromRenderArray($build); - $section_list = $this->sectionStorageManager->findByContext( - [ - 'display' => EntityContext::fromEntity($display), - 'entity' => EntityContext::fromEntity($entity), - 'view_mode' => new Context(new ContextDefinition('string'), $display->getMode()), - ], - $cacheable_metadata - ); - $cacheable_metadata->applyTo($build); - - if (empty($section_list)) { - return; - } - - // Create a hash of the sections and use it in the unique Quick Edit view - // mode ID. Any changes to the sections will result in a different hash, - // forcing Quick Edit's JavaScript to recognize any changes and retrieve - // up-to-date metadata. - $sections_hash = hash('sha256', serialize($section_list->getSections())); - - // Track each component by their plugin ID, delta, region, and UUID. - $plugin_ids_to_update = []; - foreach (Element::children($build['_layout_builder']) as $delta) { - $section = $build['_layout_builder'][$delta]; - - if (!Element::isEmpty($section)) { - /** @var \Drupal\Core\Layout\LayoutDefinition $layout */ - $layout = $section['#layout']; - $regions = $layout->getRegionNames(); - - foreach ($regions as $region) { - if (isset($section[$region])) { - foreach ($section[$region] as $uuid => $component) { - if (isset($component['#plugin_id']) && $this->supportQuickEditOnComponent($component, $entity)) { - $plugin_ids_to_update[$component['#plugin_id']][$delta][$region][$uuid] = $uuid; - } - } - } - } - } - } - - // @todo Remove when https://www.drupal.org/node/3041850 is resolved. - $plugin_ids_to_update = array_filter($plugin_ids_to_update, function ($info) { - // Delta, region, and UUID each count as one. - return count($info, COUNT_RECURSIVE) === 3; - }); - - $plugin_ids_to_update = NestedArray::mergeDeepArray($plugin_ids_to_update, TRUE); - foreach ($plugin_ids_to_update as $delta => $regions) { - foreach ($regions as $region => $uuids) { - foreach ($uuids as $uuid => $component) { - $build['_layout_builder'][$delta][$region][$uuid]['content']['#view_mode'] = static::getViewModeId($entity, $display, $delta, $uuid, $sections_hash); - } - } - } - // Alter the Quick Edit view mode ID of all fields outside of the Layout - // Builder sections to force Quick Edit to request to the field metadata. - // @todo Remove this logic in https://www.drupal.org/project/node/2966136. - foreach (Element::children($build) as $field_name) { - if ($field_name !== '_layout_builder') { - $field_build = &$build[$field_name]; - if (isset($field_build['#view_mode'])) { - $field_build['#view_mode'] = "layout_builder-{$display->getMode()}-non_component-$sections_hash"; - } - } - } - } - - /** - * Generates a Quick Edit view mode ID. - * - * @param \Drupal\Core\Entity\EntityInterface $entity - * The entity. - * @param \Drupal\Core\Entity\Display\EntityViewDisplayInterface $display - * The entity view display. - * @param int $delta - * The delta. - * @param string $component_uuid - * The component UUID. - * @param string $sections_hash - * The hash of the sections; must change whenever the sections change. - * - * @return string - * The Quick Edit view mode ID. - * - * @see \Drupal\layout_builder\QuickEditIntegration::deconstructViewModeId() - */ - private static function getViewModeId(EntityInterface $entity, EntityViewDisplayInterface $display, $delta, $component_uuid, $sections_hash) { - return implode('-', [ - 'layout_builder', - $display->getMode(), - $delta, - // Replace the dashes in the component UUID because we need to - // use dashes to join the parts. - str_replace('-', '_', $component_uuid), - $entity->id(), - $sections_hash, - ]); - } - - /** - * Deconstructs the Quick Edit view mode ID into its constituent parts. - * - * @param string $quick_edit_view_mode_id - * The Quick Edit view mode ID. - * - * @return array - * An array containing the entity view mode ID, the delta, the component - * UUID, and the entity ID. - * - * @see \Drupal\layout_builder\QuickEditIntegration::getViewModeId() - */ - public static function deconstructViewModeId($quick_edit_view_mode_id) { - [, $entity_view_mode_id, $delta, $component_uuid, $entity_id] = explode('-', $quick_edit_view_mode_id, 7); - return [ - $entity_view_mode_id, - // @todo Explicitly cast delta to an integer, remove this in - // https://www.drupal.org/project/drupal/issues/2984509. - (int) $delta, - // Replace the underscores with dash to get back the component UUID. - str_replace('_', '-', $component_uuid), - $entity_id, - ]; - } - - /** - * Re-renders a field rendered by Layout Builder, edited with Quick Edit. - * - * @param \Drupal\Core\Entity\FieldableEntityInterface $entity - * The entity. - * @param string $field_name - * The field name. - * @param string $quick_edit_view_mode_id - * The Quick Edit view mode ID. - * @param string $langcode - * The language code. - * - * @return array - * The re-rendered field. - */ - public function quickEditRenderField(FieldableEntityInterface $entity, $field_name, $quick_edit_view_mode_id, $langcode) { - [$entity_view_mode, $delta, $component_uuid] = static::deconstructViewModeId($quick_edit_view_mode_id); - - $entity_build = $this->entityTypeManager->getViewBuilder($entity->getEntityTypeId())->view($entity, $entity_view_mode, $langcode); - $this->buildEntityView($entity_build); - - if (isset($entity_build['_layout_builder'][$delta])) { - foreach (Element::children($entity_build['_layout_builder'][$delta]) as $region) { - if (isset($entity_build['_layout_builder'][$delta][$region][$component_uuid])) { - return $entity_build['_layout_builder'][$delta][$region][$component_uuid]['content']; - } - } - } - - $this->getLogger('layout_builder')->warning('The field "%field" failed to render.', ['%field' => $field_name]); - return []; - } - - /** - * {@inheritdoc} - * - * @todo Replace this hardcoded processing when - * https://www.drupal.org/project/drupal/issues/3041635 is resolved. - * - * @see \Drupal\Tests\EntityViewTrait::buildEntityView() - */ - private function buildEntityView(array &$elements) { - // If the default values for this element have not been loaded yet, - // populate them. - if (isset($elements['#type']) && empty($elements['#defaults_loaded'])) { - $elements += \Drupal::service('element_info')->getInfo($elements['#type']); - } - - // Make any final changes to the element before it is rendered. This means - // that the $element or the children can be altered or corrected before - // the element is rendered into the final text. - if (isset($elements['#pre_render'])) { - foreach ($elements['#pre_render'] as $callable) { - $elements = call_user_func($callable, $elements); - } - } - - // And recurse. - $children = Element::children($elements, TRUE); - foreach ($children as $key) { - $this->buildEntityView($elements[$key]); - } - } - - /** - * Determines whether a component has Quick Edit support. - * - * Only field_block components for display configurable fields should be - * supported. - * - * @param array $component - * The component render array. - * @param \Drupal\Core\Entity\FieldableEntityInterface $entity - * The entity being displayed. - * - * @return bool - * Whether Quick Edit is supported on the component. - * - * @see \Drupal\layout_builder\Plugin\Block\FieldBlock - */ - private function supportQuickEditOnComponent(array $component, FieldableEntityInterface $entity) { - if (isset($component['content']['#field_name'], $component['#base_plugin_id']) && $component['#base_plugin_id'] === 'field_block' && $entity->hasField($component['content']['#field_name'])) { - return $entity->getFieldDefinition($component['content']['#field_name'])->isDisplayConfigurable('view'); - } - return FALSE; - } - -} +class QuickEditIntegration extends LayoutBuilderIntegration {} diff --git a/web/core/modules/media/src/Controller/OEmbedIframeController.php b/web/core/modules/media/src/Controller/OEmbedIframeController.php index 5e7b12ff3766092d54e0abe0a19f3e76ef2a4a15..9da8f90502305f4e364d343db9a69d071dcdf554 100644 --- a/web/core/modules/media/src/Controller/OEmbedIframeController.php +++ b/web/core/modules/media/src/Controller/OEmbedIframeController.php @@ -116,10 +116,23 @@ public static function create(ContainerInterface $container) { * The response object. * * @throws \Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException - * Will be thrown if the 'hash' parameter does not match the expected hash - * of the 'url' parameter. + * Will be thrown if either + * - the 'hash' parameter does not match the expected hash of the 'url' + * parameter; + * - the iframe_domain is set in media.settings and does not match the host + * in the request. */ public function render(Request $request) { + // @todo Move domain check logic to a separate method. + $allowed_domain = \Drupal::config('media.settings')->get('iframe_domain'); + if ($allowed_domain) { + $allowed_host = parse_url($allowed_domain, PHP_URL_HOST); + $host = parse_url($request->getSchemeAndHttpHost(), PHP_URL_HOST); + if ($allowed_host !== $host) { + throw new AccessDeniedHttpException('This resource is not available'); + } + } + $url = $request->query->get('url'); $max_width = $request->query->getInt('max_width'); $max_height = $request->query->getInt('max_height'); diff --git a/web/core/modules/migrate/tests/src/Functional/process/DownloadFunctionalTest.php b/web/core/modules/migrate/tests/src/Functional/process/DownloadFunctionalTest.php index 26f2f3527fcbc5cb4b62fdcf095084ea558b5aba..51371ff69c839614dd647618700e46549e619cb1 100644 --- a/web/core/modules/migrate/tests/src/Functional/process/DownloadFunctionalTest.php +++ b/web/core/modules/migrate/tests/src/Functional/process/DownloadFunctionalTest.php @@ -76,8 +76,11 @@ public function testExceptionThrow() { $this->assertCount(1, $messages); $message = reset($messages); + // Assert critical parts of the error message, but not the exact message, + // since it depends on Guzzle's internal implementation of PSR-7. $id = $migration->getPluginId(); - $this->assertEquals("$id:uri:download: Client error: `GET $invalid_url` resulted in a `404 Not Found` response ($invalid_url)", $message->message); + $this->assertStringContainsString("$id:uri:download:", $message->message); + $this->assertStringContainsString($invalid_url, $message->message); $this->assertEquals(MigrationInterface::MESSAGE_ERROR, $message->level); // Check that the second row was migrated successfully. diff --git a/web/core/modules/node/src/Plugin/views/argument/Vid.php b/web/core/modules/node/src/Plugin/views/argument/Vid.php index 84c31fd1cd3d593aab6e1f53a74d469a0471a5a3..c5a35fc3143f2d0b617df30752edf435bf7bedb9 100644 --- a/web/core/modules/node/src/Plugin/views/argument/Vid.php +++ b/web/core/modules/node/src/Plugin/views/argument/Vid.php @@ -75,6 +75,7 @@ public function titleQuery() { ->accessCheck(FALSE) ->allRevisions() ->groupBy('title') + ->condition('vid', $this->value, 'IN') ->execute(); foreach ($results as $result) { diff --git a/web/core/modules/node/tests/modules/node_test_views/test_views/views.view.test_node_revision_id_argument.yml b/web/core/modules/node/tests/modules/node_test_views/test_views/views.view.test_node_revision_id_argument.yml index e2ac01afd90bbc2d3f463b54bd9942ccea8bf8ba..bf13bdfad00dd50557d8c19be92a166217a6891b 100644 --- a/web/core/modules/node/tests/modules/node_test_views/test_views/views.view.test_node_revision_id_argument.yml +++ b/web/core/modules/node/tests/modules/node_test_views/test_views/views.view.test_node_revision_id_argument.yml @@ -13,45 +13,12 @@ base_table: node_field_data base_field: nid display: default: - display_plugin: default id: default display_title: Default + display_plugin: default 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: - items_per_page: null - offset: 0 - style: - type: default - row: - type: fields + title: test_node_revision_id_argument fields: title: id: title @@ -60,6 +27,9 @@ display: relationship: none group_type: group admin_label: '' + entity_type: node + entity_field: title + plugin_id: field label: '' exclude: false alter: @@ -115,16 +85,30 @@ display: multi_type: separator separator: ', ' field_api_classes: false - entity_type: node - entity_field: title - plugin_id: field - filters: { } - sorts: { } - title: test_node_revision_id_argument - header: { } - footer: { } + pager: + type: none + options: + offset: 0 + items_per_page: null + 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 + access: + type: perm + options: + perm: 'access content' + cache: + type: tag + options: { } empty: { } - relationships: { } + sorts: { } arguments: vid: id: vid @@ -133,13 +117,16 @@ display: relationship: none group_type: group admin_label: '' + entity_type: node + entity_field: vid + plugin_id: node_vid default_action: ignore exception: value: all title_enable: false title: All - title_enable: false - title: '' + title_enable: true + title: '{{ arguments.vid }}' default_argument_type: fixed default_argument_options: argument: '' @@ -147,8 +134,8 @@ display: summary_options: base_path: '' count: true - items_per_page: 25 override: false + items_per_page: 25 summary: sort_order: asc number_of_records: 0 @@ -160,38 +147,51 @@ display: validate_options: { } break_phrase: false not: false - entity_type: node - entity_field: vid - plugin_id: node_vid - display_extenders: { } + filters: { } filter_groups: operator: AND groups: { } + style: + type: default + row: + type: fields + query: + type: views_query + options: + query_comment: '' + disable_sql_rewrite: false + distinct: false + replica: false + query_tags: { } + relationships: { } + header: { } + footer: { } + display_extenders: { } cache_metadata: + max-age: -1 contexts: - 'languages:language_content' - 'languages:language_interface' - url - 'user.node_grants:view' - user.permissions - cacheable: false - max-age: -1 tags: { } + cacheable: false page_1: - display_plugin: page id: page_1 display_title: Page + display_plugin: page position: 1 display_options: display_extenders: { } path: test-revision-vid-argument cache_metadata: + max-age: -1 contexts: - 'languages:language_content' - 'languages:language_interface' - url - 'user.node_grants:view' - user.permissions - cacheable: false - max-age: -1 tags: { } + cacheable: false diff --git a/web/core/modules/node/tests/src/Kernel/Views/ArgumentNodeRevisionIdTest.php b/web/core/modules/node/tests/src/Kernel/Views/ArgumentNodeRevisionIdTest.php index 9d3898544e5e9f07d813ecb653512db83ea8e2cc..62dbe92be9b659f2dc36e6b69de3e47b825afb4b 100644 --- a/web/core/modules/node/tests/src/Kernel/Views/ArgumentNodeRevisionIdTest.php +++ b/web/core/modules/node/tests/src/Kernel/Views/ArgumentNodeRevisionIdTest.php @@ -46,13 +46,16 @@ public function testNodeRevisionRelationship() { NodeType::create(['type' => 'page', 'name' => 'page'])->save(); $node = Node::create(['type' => 'page', 'title' => 'test1', 'uid' => 1]); $node->save(); + $first_revision_id = $node->getRevisionId(); $node->setNewRevision(); $node->setTitle('test2'); $node->save(); + $second_revision_id = $node->getRevisionId(); $view_nid = Views::getView('test_node_revision_id_argument'); - $this->executeView($view_nid, [$node->getRevisionId()]); + $this->executeView($view_nid, [$second_revision_id]); $this->assertIdenticalResultset($view_nid, [['title' => 'test2']]); + $this->assertSame('test2', $view_nid->getTitle()); } /** diff --git a/web/core/modules/quickedit/quickedit.module b/web/core/modules/quickedit/quickedit.module index 028fe20143516ecaf3741e6e330fa5fe03d42f1d..219b975ebcbf2e8eaa96ed4526e78cfc8b58887c 100644 --- a/web/core/modules/quickedit/quickedit.module +++ b/web/core/modules/quickedit/quickedit.module @@ -16,6 +16,8 @@ use Drupal\Core\Entity\Display\EntityViewDisplayInterface; use Drupal\Core\Entity\RevisionableInterface; use Drupal\Core\Routing\RouteMatchInterface; +use Drupal\quickedit\Entity\QuickEditLayoutBuilderEntityViewDisplay; +use Drupal\quickedit\LayoutBuilderIntegration; /** * Implements hook_help(). @@ -174,10 +176,28 @@ function quickedit_preprocess_field(&$variables) { } } +/** + * Implements hook_entity_type_alter(). + */ +function quickedit_entity_type_alter(array &$entity_types) { + if (\Drupal::moduleHandler()->moduleExists('layout_builder')) { + /** @var \Drupal\Core\Entity\EntityTypeInterface[] $entity_types */ + if ($entity_types['entity_view_display']->getClass() === 'Drupal\layout_builder\Entity\LayoutBuilderEntityViewDisplay\LayoutBuilderEntityViewDisplay') { + $entity_types['entity_view_display']->setClass(QuickEditLayoutBuilderEntityViewDisplay::class); + } + } +} + /** * Implements hook_entity_view_alter(). */ function quickedit_entity_view_alter(&$build, EntityInterface $entity, EntityViewDisplayInterface $display) { + if (\Drupal::moduleHandler()->moduleExists('layout_builder')) { + /** @var \Drupal\quickedit\LayoutBuilderIntegration $layout_builder_integration */ + $layout_builder_integration = \Drupal::classResolver(LayoutBuilderIntegration::class); + $layout_builder_integration->entityViewAlter($build, $entity, $display); + } + if (isset($build['#embed'])) { return; } @@ -189,3 +209,12 @@ function quickedit_entity_view_alter(&$build, EntityInterface $entity, EntityVie $build['#attributes']['data-quickedit-entity-id'] = $entity->getEntityTypeId() . '/' . $entity->id(); } + +/** + * Implements hook_quickedit_render_field(). + */ +function layout_builder_quickedit_render_field(EntityInterface $entity, $field_name, $view_mode_id, $langcode) { + /** @var \Drupal\quickedit\LayoutBuilderIntegration $layout_builder_integration */ + $layout_builder_integration = \Drupal::classResolver(LayoutBuilderIntegration::class); + return $layout_builder_integration->quickEditRenderField($entity, $field_name, $view_mode_id, $langcode); +} diff --git a/web/core/modules/quickedit/src/Entity/QuickEditLayoutBuilderEntityViewDisplay.php b/web/core/modules/quickedit/src/Entity/QuickEditLayoutBuilderEntityViewDisplay.php new file mode 100644 index 0000000000000000000000000000000000000000..3dd4eb9b106271d1c3a80b81c20d59bc262b262b --- /dev/null +++ b/web/core/modules/quickedit/src/Entity/QuickEditLayoutBuilderEntityViewDisplay.php @@ -0,0 +1,68 @@ +<?php + +namespace Drupal\quickedit\Entity; + +use Drupal\Component\Plugin\ConfigurableInterface; +use Drupal\Component\Plugin\DerivativeInspectionInterface; +use Drupal\layout_builder\Entity\LayoutBuilderEntityViewDisplay; +use Drupal\quickedit\LayoutBuilderIntegration; + +/** + * Provides an entity view display entity that has a layout with quickedit. + */ +class QuickEditLayoutBuilderEntityViewDisplay extends LayoutBuilderEntityViewDisplay { + + /** + * {@inheritdoc} + */ + public function getComponent($name) { + if ($this->isLayoutBuilderEnabled() && $section_component = $this->getQuickEditSectionComponent()) { + $plugin = $section_component->getPlugin(); + if ($plugin instanceof ConfigurableInterface) { + $configuration = $plugin->getConfiguration(); + if (isset($configuration['formatter'])) { + return $configuration['formatter']; + } + } + } + return parent::getComponent($name); + } + + /** + * Returns the Quick Edit formatter settings. + * + * @return \Drupal\layout_builder\SectionComponent|null + * The section component if it is available. + * + * @see \Drupal\quickedit\LayoutBuilderIntegration::entityViewAlter() + * @see \Drupal\quickedit\MetadataGenerator::generateFieldMetadata() + */ + private function getQuickEditSectionComponent() { + // To determine the Quick Edit view_mode ID we need an originalMode set. + if ($original_mode = $this->getOriginalMode()) { + $parts = explode('-', $original_mode); + // The Quick Edit view mode ID is created by + // \Drupal\quickedit\LayoutBuilderIntegration::entityViewAlter() + // concatenating together the information we need to retrieve the Layout + // Builder component. It follows the structure prescribed by the + // documentation of hook_quickedit_render_field(). + if (count($parts) === 6 && $parts[0] === 'layout_builder') { + [, $delta, $component_uuid, $entity_id] = LayoutBuilderIntegration::deconstructViewModeId($original_mode); + $entity = $this->entityTypeManager()->getStorage($this->getTargetEntityTypeId())->load($entity_id); + $sections = $this->getEntitySections($entity); + if (isset($sections[$delta])) { + $component = $sections[$delta]->getComponent($component_uuid); + $plugin = $component->getPlugin(); + // We only care about FieldBlock because these are only components + // that provide Quick Edit integration: Quick Edit enables in-place + // editing of fields of entities, not of anything else. + if ($plugin instanceof DerivativeInspectionInterface && $plugin->getBaseId() === 'field_block') { + return $component; + } + } + } + } + return NULL; + } + +} diff --git a/web/core/modules/quickedit/src/LayoutBuilderIntegration.php b/web/core/modules/quickedit/src/LayoutBuilderIntegration.php new file mode 100644 index 0000000000000000000000000000000000000000..49e229b98540c4cd7f4a8bf5ee03cbbeb24e3d83 --- /dev/null +++ b/web/core/modules/quickedit/src/LayoutBuilderIntegration.php @@ -0,0 +1,321 @@ +<?php + +namespace Drupal\quickedit; + +use Drupal\Component\Utility\NestedArray; +use Drupal\Core\Cache\CacheableMetadata; +use Drupal\Core\DependencyInjection\ContainerInjectionInterface; +use Drupal\Core\Entity\Display\EntityViewDisplayInterface; +use Drupal\Core\Entity\EntityInterface; +use Drupal\Core\Entity\EntityTypeManagerInterface; +use Drupal\Core\Entity\FieldableEntityInterface; +use Drupal\Core\Logger\LoggerChannelTrait; +use Drupal\Core\Plugin\Context\Context; +use Drupal\Core\Plugin\Context\ContextDefinition; +use Drupal\Core\Plugin\Context\EntityContext; +use Drupal\Core\Render\Element; +use Drupal\Core\Session\AccountInterface; +use Drupal\layout_builder\SectionStorage\SectionStorageManagerInterface; +use Symfony\Component\DependencyInjection\ContainerInterface; + +/** + * Helper methods for Layout Builder module integration. + * + * @internal + * This is an internal utility class wrapping hook implementations. + */ +class LayoutBuilderIntegration implements ContainerInjectionInterface { + + use LoggerChannelTrait; + + /** + * The section storage manager. + * + * @var \Drupal\layout_builder\SectionStorage\SectionStorageManagerInterface + */ + protected $sectionStorageManager; + + /** + * The current user. + * + * @var \Drupal\Core\Session\AccountInterface + */ + protected $currentUser; + + /** + * The entity type manager. + * + * @var \Drupal\Core\Entity\EntityTypeManagerInterface + */ + protected $entityTypeManager; + + /** + * Constructs a new LayoutBuilderIntegration object. + * + * @param \Drupal\layout_builder\SectionStorage\SectionStorageManagerInterface $section_storage_manager + * The section storage manager. + * @param \Drupal\Core\Session\AccountInterface $current_user + * The current user. + * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager + * The entity type manager. + */ + public function __construct(SectionStorageManagerInterface $section_storage_manager, AccountInterface $current_user, EntityTypeManagerInterface $entity_type_manager) { + $this->sectionStorageManager = $section_storage_manager; + $this->currentUser = $current_user; + $this->entityTypeManager = $entity_type_manager; + } + + /** + * {@inheritdoc} + */ + public static function create(ContainerInterface $container) { + return new static( + $container->get('plugin.manager.layout_builder.section_storage'), + $container->get('current_user'), + $container->get('entity_type.manager') + ); + } + + /** + * Alters the entity view build for Layout Builder compatibility. + * + * When rendering fields outside of normal view modes, Quick Edit requires + * that modules identify themselves with a view mode ID in the format + * [module_name]-[information the module needs to rerender], as prescribed by + * hook_quickedit_render_field(). + * + * @param array $build + * The built entity render array. + * @param \Drupal\Core\Entity\EntityInterface $entity + * The entity. + * @param \Drupal\Core\Entity\Display\EntityViewDisplayInterface $display + * The entity view display. + * + * @see hook_quickedit_render_field() + * @see layout_builder_quickedit_render_field() + */ + public function entityViewAlter(array &$build, EntityInterface $entity, EntityViewDisplayInterface $display) { + if (!$entity instanceof FieldableEntityInterface || !isset($build['_layout_builder'])) { + return; + } + + $build['#cache']['contexts'][] = 'user.permissions'; + if (!$this->currentUser->hasPermission('access in-place editing')) { + return; + } + + $cacheable_metadata = CacheableMetadata::createFromRenderArray($build); + $section_list = $this->sectionStorageManager->findByContext( + [ + 'display' => EntityContext::fromEntity($display), + 'entity' => EntityContext::fromEntity($entity), + 'view_mode' => new Context(new ContextDefinition('string'), $display->getMode()), + ], + $cacheable_metadata + ); + $cacheable_metadata->applyTo($build); + + if (empty($section_list)) { + return; + } + + // Create a hash of the sections and use it in the unique Quick Edit view + // mode ID. Any changes to the sections will result in a different hash, + // forcing Quick Edit's JavaScript to recognize any changes and retrieve + // up-to-date metadata. + $sections_hash = hash('sha256', serialize($section_list->getSections())); + + // Track each component by their plugin ID, delta, region, and UUID. + $plugin_ids_to_update = []; + foreach (Element::children($build['_layout_builder']) as $delta) { + $section = $build['_layout_builder'][$delta]; + + if (!Element::isEmpty($section)) { + /** @var \Drupal\Core\Layout\LayoutDefinition $layout */ + $layout = $section['#layout']; + $regions = $layout->getRegionNames(); + + foreach ($regions as $region) { + if (isset($section[$region])) { + foreach ($section[$region] as $uuid => $component) { + if (isset($component['#plugin_id']) && $this->supportQuickEditOnComponent($component, $entity)) { + $plugin_ids_to_update[$component['#plugin_id']][$delta][$region][$uuid] = $uuid; + } + } + } + } + } + } + + // @todo Remove when https://www.drupal.org/node/3041850 is resolved. + $plugin_ids_to_update = array_filter($plugin_ids_to_update, function ($info) { + // Delta, region, and UUID each count as one. + return count($info, COUNT_RECURSIVE) === 3; + }); + + $plugin_ids_to_update = NestedArray::mergeDeepArray($plugin_ids_to_update, TRUE); + foreach ($plugin_ids_to_update as $delta => $regions) { + foreach ($regions as $region => $uuids) { + foreach ($uuids as $uuid => $component) { + $build['_layout_builder'][$delta][$region][$uuid]['content']['#view_mode'] = static::getViewModeId($entity, $display, $delta, $uuid, $sections_hash); + } + } + } + // Alter the Quick Edit view mode ID of all fields outside of the Layout + // Builder sections to force Quick Edit to request to the field metadata. + // @todo Remove this logic in https://www.drupal.org/project/node/2966136. + foreach (Element::children($build) as $field_name) { + if ($field_name !== '_layout_builder') { + $field_build = &$build[$field_name]; + if (isset($field_build['#view_mode'])) { + $field_build['#view_mode'] = "layout_builder-{$display->getMode()}-non_component-$sections_hash"; + } + } + } + } + + /** + * Generates a Quick Edit view mode ID. + * + * @param \Drupal\Core\Entity\EntityInterface $entity + * The entity. + * @param \Drupal\Core\Entity\Display\EntityViewDisplayInterface $display + * The entity view display. + * @param int $delta + * The delta. + * @param string $component_uuid + * The component UUID. + * @param string $sections_hash + * The hash of the sections; must change whenever the sections change. + * + * @return string + * The Quick Edit view mode ID. + * + * @see \Drupal\quickedit\LayoutBuilderIntegration::deconstructViewModeId() + */ + private static function getViewModeId(EntityInterface $entity, EntityViewDisplayInterface $display, $delta, $component_uuid, $sections_hash) { + return implode('-', [ + 'layout_builder', + $display->getMode(), + $delta, + // Replace the dashes in the component UUID because we need to + // use dashes to join the parts. + str_replace('-', '_', $component_uuid), + $entity->id(), + $sections_hash, + ]); + } + + /** + * Deconstructs the Quick Edit view mode ID into its constituent parts. + * + * @param string $quick_edit_view_mode_id + * The Quick Edit view mode ID. + * + * @return array + * An array containing the entity view mode ID, the delta, the component + * UUID, and the entity ID. + * + * @see \Drupal\quickedit\LayoutBuilderIntegration::getViewModeId() + */ + public static function deconstructViewModeId($quick_edit_view_mode_id) { + [, $entity_view_mode_id, $delta, $component_uuid, $entity_id] = explode('-', $quick_edit_view_mode_id, 7); + return [ + $entity_view_mode_id, + // @todo Explicitly cast delta to an integer, remove this in + // https://www.drupal.org/project/drupal/issues/2984509. + (int) $delta, + // Replace the underscores with dash to get back the component UUID. + str_replace('_', '-', $component_uuid), + $entity_id, + ]; + } + + /** + * Re-renders a field rendered by Layout Builder, edited with Quick Edit. + * + * @param \Drupal\Core\Entity\FieldableEntityInterface $entity + * The entity. + * @param string $field_name + * The field name. + * @param string $quick_edit_view_mode_id + * The Quick Edit view mode ID. + * @param string $langcode + * The language code. + * + * @return array + * The re-rendered field. + */ + public function quickEditRenderField(FieldableEntityInterface $entity, $field_name, $quick_edit_view_mode_id, $langcode) { + [$entity_view_mode, $delta, $component_uuid] = static::deconstructViewModeId($quick_edit_view_mode_id); + + $entity_build = $this->entityTypeManager->getViewBuilder($entity->getEntityTypeId())->view($entity, $entity_view_mode, $langcode); + $this->buildEntityView($entity_build); + + if (isset($entity_build['_layout_builder'][$delta])) { + foreach (Element::children($entity_build['_layout_builder'][$delta]) as $region) { + if (isset($entity_build['_layout_builder'][$delta][$region][$component_uuid])) { + return $entity_build['_layout_builder'][$delta][$region][$component_uuid]['content']; + } + } + } + + $this->getLogger('layout_builder')->warning('The field "%field" failed to render.', ['%field' => $field_name]); + return []; + } + + /** + * {@inheritdoc} + * + * @todo Replace this hardcoded processing when + * https://www.drupal.org/project/drupal/issues/3041635 is resolved. + * + * @see \Drupal\Tests\EntityViewTrait::buildEntityView() + */ + private function buildEntityView(array &$elements) { + // If the default values for this element have not been loaded yet, + // populate them. + if (isset($elements['#type']) && empty($elements['#defaults_loaded'])) { + $elements += \Drupal::service('element_info')->getInfo($elements['#type']); + } + + // Make any final changes to the element before it is rendered. This means + // that the $element or the children can be altered or corrected before + // the element is rendered into the final text. + if (isset($elements['#pre_render'])) { + foreach ($elements['#pre_render'] as $callable) { + $elements = call_user_func($callable, $elements); + } + } + + // And recurse. + $children = Element::children($elements, TRUE); + foreach ($children as $key) { + $this->buildEntityView($elements[$key]); + } + } + + /** + * Determines whether a component has Quick Edit support. + * + * Only field_block components for display configurable fields should be + * supported. + * + * @param array $component + * The component render array. + * @param \Drupal\Core\Entity\FieldableEntityInterface $entity + * The entity being displayed. + * + * @return bool + * Whether Quick Edit is supported on the component. + * + * @see \Drupal\layout_builder\Plugin\Block\FieldBlock + */ + private function supportQuickEditOnComponent(array $component, FieldableEntityInterface $entity) { + if (isset($component['content']['#field_name'], $component['#base_plugin_id']) && $component['#base_plugin_id'] === 'field_block' && $entity->hasField($component['content']['#field_name'])) { + return $entity->getFieldDefinition($component['content']['#field_name'])->isDisplayConfigurable('view'); + } + return FALSE; + } + +} diff --git a/web/core/modules/quickedit/tests/src/Functional/Jsonapi/QuickEditLayoutBuilderEntityViewDisplayTest.php b/web/core/modules/quickedit/tests/src/Functional/Jsonapi/QuickEditLayoutBuilderEntityViewDisplayTest.php new file mode 100644 index 0000000000000000000000000000000000000000..0e1509b2a73b10afbc34c188ad65219de619035e --- /dev/null +++ b/web/core/modules/quickedit/tests/src/Functional/Jsonapi/QuickEditLayoutBuilderEntityViewDisplayTest.php @@ -0,0 +1,21 @@ +<?php + +namespace Drupal\Tests\quickedit\Functional\Jsonapi; + +use Drupal\Tests\layout_builder\Functional\Jsonapi\LayoutBuilderEntityViewDisplayTest; + +/** + * JSON:API integration test for the "EntityViewDisplay" config entity type. + * + * @group jsonapi + * @group layout_builder + * @group quickedit + */ +class QuickEditLayoutBuilderEntityViewDisplayTest extends LayoutBuilderEntityViewDisplayTest { + + /** + * {@inheritdoc} + */ + protected static $modules = ['quickedit']; + +} diff --git a/web/core/modules/quickedit/tests/src/Functional/Rest/QuickEditLayoutBuilderEntityViewDisplayJsonAnonTest.php b/web/core/modules/quickedit/tests/src/Functional/Rest/QuickEditLayoutBuilderEntityViewDisplayJsonAnonTest.php new file mode 100644 index 0000000000000000000000000000000000000000..c138148ae92558b19827dcd9b0160c4a6cf03298 --- /dev/null +++ b/web/core/modules/quickedit/tests/src/Functional/Rest/QuickEditLayoutBuilderEntityViewDisplayJsonAnonTest.php @@ -0,0 +1,19 @@ +<?php + +namespace Drupal\Tests\quickedit\Functional\Rest; + +use Drupal\Tests\layout_builder\Functional\Rest\LayoutBuilderEntityViewDisplayJsonAnonTest; + +/** + * @group quickedit + * @group layout_builder + * @group rest + */ +class QuickEditLayoutBuilderEntityViewDisplayJsonAnonTest extends LayoutBuilderEntityViewDisplayJsonAnonTest { + + /** + * {@inheritdoc} + */ + protected static $modules = ['quickedit']; + +} diff --git a/web/core/modules/quickedit/tests/src/Functional/Rest/QuickEditLayoutBuilderEntityViewDisplayJsonBasicAuthTest.php b/web/core/modules/quickedit/tests/src/Functional/Rest/QuickEditLayoutBuilderEntityViewDisplayJsonBasicAuthTest.php new file mode 100644 index 0000000000000000000000000000000000000000..a3acf46eead6f7ea403aa04351585031697f7b7a --- /dev/null +++ b/web/core/modules/quickedit/tests/src/Functional/Rest/QuickEditLayoutBuilderEntityViewDisplayJsonBasicAuthTest.php @@ -0,0 +1,19 @@ +<?php + +namespace Drupal\Tests\quickedit\Functional\Rest; + +use Drupal\Tests\layout_builder\Functional\Rest\LayoutBuilderEntityViewDisplayJsonBasicAuthTest; + +/** + * @group quickedit + * @group layout_builder + * @group rest + */ +class QuickEditLayoutBuilderEntityViewDisplayJsonBasicAuthTest extends LayoutBuilderEntityViewDisplayJsonBasicAuthTest { + + /** + * {@inheritdoc} + */ + protected static $modules = ['quickedit']; + +} diff --git a/web/core/modules/quickedit/tests/src/Functional/Rest/QuickEditLayoutBuilderEntityViewDisplayJsonCookieTest.php b/web/core/modules/quickedit/tests/src/Functional/Rest/QuickEditLayoutBuilderEntityViewDisplayJsonCookieTest.php new file mode 100644 index 0000000000000000000000000000000000000000..ffd07b021d4061e166cf9c103145fefd322549d4 --- /dev/null +++ b/web/core/modules/quickedit/tests/src/Functional/Rest/QuickEditLayoutBuilderEntityViewDisplayJsonCookieTest.php @@ -0,0 +1,19 @@ +<?php + +namespace Drupal\Tests\quickedit\Functional\Rest; + +use Drupal\Tests\layout_builder\Functional\Rest\LayoutBuilderEntityViewDisplayJsonCookieTest; + +/** + * @group quickedit + * @group layout_builder + * @group rest + */ +class QuickEditLayoutBuilderEntityViewDisplayJsonCookieTest extends LayoutBuilderEntityViewDisplayJsonCookieTest { + + /** + * {@inheritdoc} + */ + protected static $modules = ['quickedit']; + +} diff --git a/web/core/modules/quickedit/tests/src/Functional/Rest/QuickEditLayoutBuilderEntityViewDisplayXmlAnonTest.php b/web/core/modules/quickedit/tests/src/Functional/Rest/QuickEditLayoutBuilderEntityViewDisplayXmlAnonTest.php new file mode 100644 index 0000000000000000000000000000000000000000..87c6a72639f0e5b22a657d7286765056dd37bba2 --- /dev/null +++ b/web/core/modules/quickedit/tests/src/Functional/Rest/QuickEditLayoutBuilderEntityViewDisplayXmlAnonTest.php @@ -0,0 +1,19 @@ +<?php + +namespace Drupal\Tests\quickedit\Functional\Rest; + +use Drupal\Tests\layout_builder\Functional\Rest\LayoutBuilderEntityViewDisplayXmlAnonTest; + +/** + * @group quickedit + * @group layout_builder + * @group rest + */ +class QuickEditLayoutBuilderEntityViewDisplayXmlAnonTest extends LayoutBuilderEntityViewDisplayXmlAnonTest { + + /** + * {@inheritdoc} + */ + protected static $modules = ['quickedit']; + +} diff --git a/web/core/modules/quickedit/tests/src/Functional/Rest/QuickEditLayoutBuilderEntityViewDisplayXmlBasicAuthTest.php b/web/core/modules/quickedit/tests/src/Functional/Rest/QuickEditLayoutBuilderEntityViewDisplayXmlBasicAuthTest.php new file mode 100644 index 0000000000000000000000000000000000000000..8640666302a51e72e9807ac439d4d2217f43d2eb --- /dev/null +++ b/web/core/modules/quickedit/tests/src/Functional/Rest/QuickEditLayoutBuilderEntityViewDisplayXmlBasicAuthTest.php @@ -0,0 +1,19 @@ +<?php + +namespace Drupal\Tests\quickedit\Functional\Rest; + +use Drupal\Tests\layout_builder\Functional\Rest\LayoutBuilderEntityViewDisplayXmlBasicAuthTest; + +/** + * @group quickedit + * @group layout_builder + * @group rest + */ +class QuickEditLayoutBuilderEntityViewDisplayXmlBasicAuthTest extends LayoutBuilderEntityViewDisplayXmlBasicAuthTest { + + /** + * {@inheritdoc} + */ + protected static $modules = ['quickedit']; + +} diff --git a/web/core/modules/quickedit/tests/src/Functional/Rest/QuickEditLayoutBuilderEntityViewDisplayXmlCookieTest.php b/web/core/modules/quickedit/tests/src/Functional/Rest/QuickEditLayoutBuilderEntityViewDisplayXmlCookieTest.php new file mode 100644 index 0000000000000000000000000000000000000000..699efe177ecf8f8badc5d0c0c7e7e0e375b7396b --- /dev/null +++ b/web/core/modules/quickedit/tests/src/Functional/Rest/QuickEditLayoutBuilderEntityViewDisplayXmlCookieTest.php @@ -0,0 +1,19 @@ +<?php + +namespace Drupal\Tests\quickedit\Functional\Rest; + +use Drupal\Tests\layout_builder\Functional\Rest\LayoutBuilderEntityViewDisplayXmlCookieTest; + +/** + * @group quickedit + * @group layout_builder + * @group rest + */ +class QuickEditLayoutBuilderEntityViewDisplayXmlCookieTest extends LayoutBuilderEntityViewDisplayXmlCookieTest { + + /** + * {@inheritdoc} + */ + protected static $modules = ['quickedit']; + +} diff --git a/web/core/modules/quickedit/tests/src/FunctionalJavascript/QuickEditIntegrationTest.php b/web/core/modules/quickedit/tests/src/FunctionalJavascript/LayoutBuilderIntegrationTest.php similarity index 99% rename from web/core/modules/quickedit/tests/src/FunctionalJavascript/QuickEditIntegrationTest.php rename to web/core/modules/quickedit/tests/src/FunctionalJavascript/LayoutBuilderIntegrationTest.php index c78ec364e24976826d1df69dd96f17245b07307d..ab8f1f0a1b20e8a4ba1c9b8e01ad7afb4f26b858 100644 --- a/web/core/modules/quickedit/tests/src/FunctionalJavascript/QuickEditIntegrationTest.php +++ b/web/core/modules/quickedit/tests/src/FunctionalJavascript/LayoutBuilderIntegrationTest.php @@ -14,7 +14,7 @@ /** * @group quickedit */ -class QuickEditIntegrationTest extends QuickEditJavascriptTestBase { +class LayoutBuilderIntegrationTest extends QuickEditJavascriptTestBase { use EntityReferenceTestTrait; diff --git a/web/core/modules/system/src/EventSubscriber/SecurityFileUploadEventSubscriber.php b/web/core/modules/system/src/EventSubscriber/SecurityFileUploadEventSubscriber.php index 4aeeb574d35e690836bd4705100e61687e50dfce..4bf03463d6d2e66e4a7b8404f300a25d29b77178 100644 --- a/web/core/modules/system/src/EventSubscriber/SecurityFileUploadEventSubscriber.php +++ b/web/core/modules/system/src/EventSubscriber/SecurityFileUploadEventSubscriber.php @@ -63,6 +63,15 @@ public function sanitizeName(FileUploadSanitizeNameEvent $event): void { $filename = array_shift($filename_parts); // Remove final extension. $final_extension = (string) array_pop($filename_parts); + // Check if we're dealing with a dot file that is also an insecure extension + // e.g. .htaccess. In this scenario there is only one 'part' and the + // extension becomes the filename. We use the original filename from the + // event rather than the trimmed version above. + $insecure_uploads = $this->config->get('allow_insecure_uploads'); + if (!$insecure_uploads && $final_extension === '' && str_contains($event->getFilename(), '.') && in_array(strtolower($filename), FileSystemInterface::INSECURE_EXTENSIONS, TRUE)) { + $final_extension = $filename; + $filename = ''; + } $extensions = $event->getAllowedExtensions(); if (!empty($extensions) && !in_array(strtolower($final_extension), $extensions, TRUE)) { @@ -76,7 +85,7 @@ public function sanitizeName(FileUploadSanitizeNameEvent $event): void { return; } - if (!$this->config->get('allow_insecure_uploads') && in_array(strtolower($final_extension), FileSystemInterface::INSECURE_EXTENSIONS, TRUE)) { + if (!$insecure_uploads && in_array(strtolower($final_extension), FileSystemInterface::INSECURE_EXTENSIONS, TRUE)) { if (empty($extensions) || in_array('txt', $extensions, TRUE)) { // Add .txt to potentially executable files prior to munging to help prevent // exploits. This results in a filenames like filename.php being changed to diff --git a/web/core/modules/system/system.module b/web/core/modules/system/system.module index a1b51cc7c0dfb06963a7dd68e8b4a88ac762b58c..deba8f16a016a6ab77d3f8d18261d932119827ed 100644 --- a/web/core/modules/system/system.module +++ b/web/core/modules/system/system.module @@ -27,6 +27,8 @@ use Drupal\Core\Queue\QueueGarbageCollectionInterface; use Drupal\Core\Routing\RouteMatchInterface; use Drupal\Core\Routing\StackedRouteMatchInterface; +use Drupal\Core\Site\Settings; +use Drupal\Core\StreamWrapper\StreamWrapperManager; use Drupal\Core\Url; use GuzzleHttp\Exception\TransferException; use Symfony\Component\HttpFoundation\RedirectResponse; @@ -1385,3 +1387,21 @@ function system_page_top() { } } } + +/** + * Implements hook_file_download(). + */ +function system_file_download($uri) { + $core_schemes = ['public', 'private', 'temporary']; + $additional_public_schemes = array_diff(Settings::get('file_additional_public_schemes', []), $core_schemes); + if ($additional_public_schemes) { + $scheme = StreamWrapperManager::getScheme($uri); + if (in_array($scheme, $additional_public_schemes, TRUE)) { + return [ + // Returning any header grants access, and setting the 'Cache-Control' + // header is appropriate for public files. + 'Cache-Control' => 'public', + ]; + } + } +} diff --git a/web/core/modules/system/tests/modules/decorated_service_test/decorated_service_test.info.yml b/web/core/modules/system/tests/modules/decorated_service_test/decorated_service_test.info.yml new file mode 100644 index 0000000000000000000000000000000000000000..08d66bdb6904a2b4c419145e5a85250b32dd36ce --- /dev/null +++ b/web/core/modules/system/tests/modules/decorated_service_test/decorated_service_test.info.yml @@ -0,0 +1,5 @@ +name: 'Decorated Service Test' +type: module +description: 'Support module for decorated service test.' +package: Testing +version: VERSION diff --git a/web/core/modules/system/tests/modules/decorated_service_test/decorated_service_test.services.yml b/web/core/modules/system/tests/modules/decorated_service_test/decorated_service_test.services.yml new file mode 100644 index 0000000000000000000000000000000000000000..a00c56c7d0cc06607b6b1258c56479a9328fa162 --- /dev/null +++ b/web/core/modules/system/tests/modules/decorated_service_test/decorated_service_test.services.yml @@ -0,0 +1,17 @@ +services: + test_service: + class: 'Drupal\decorated_service_test\TestService' + test_service_decorator: + class: 'Drupal\decorated_service_test\TestServiceDecorator' + public: false + decorates: test_service + test_service2: + class: 'Drupal\decorated_service_test\TestService' + test_service2_decorator: + class: 'Drupal\decorated_service_test\TestServiceDecorator' + public: false + decorates: test_service2 + test_service2_decorator2: + class: 'Drupal\decorated_service_test\TestServiceDecorator' + public: false + decorates: test_service2 diff --git a/web/core/modules/system/tests/modules/decorated_service_test/src/TestService.php b/web/core/modules/system/tests/modules/decorated_service_test/src/TestService.php new file mode 100644 index 0000000000000000000000000000000000000000..8e708019ffaedc11d753f5fc37ab98b298e6339e --- /dev/null +++ b/web/core/modules/system/tests/modules/decorated_service_test/src/TestService.php @@ -0,0 +1,7 @@ +<?php + +namespace Drupal\decorated_service_test; + +class TestService { + +} diff --git a/web/core/modules/system/tests/modules/decorated_service_test/src/TestServiceDecorator.php b/web/core/modules/system/tests/modules/decorated_service_test/src/TestServiceDecorator.php new file mode 100644 index 0000000000000000000000000000000000000000..30dcb023bd95c34e0c9a5aa375aa19f178d2a826 --- /dev/null +++ b/web/core/modules/system/tests/modules/decorated_service_test/src/TestServiceDecorator.php @@ -0,0 +1,7 @@ +<?php + +namespace Drupal\decorated_service_test; + +class TestServiceDecorator extends TestService { + +} diff --git a/web/core/modules/system/tests/src/Kernel/DecoratedServiceTest.php b/web/core/modules/system/tests/src/Kernel/DecoratedServiceTest.php new file mode 100644 index 0000000000000000000000000000000000000000..854662df18bb9804472ec6c5295b422175079b5b --- /dev/null +++ b/web/core/modules/system/tests/src/Kernel/DecoratedServiceTest.php @@ -0,0 +1,34 @@ +<?php + +namespace Drupal\Tests\system\Kernel; + +use Drupal\decorated_service_test\TestServiceDecorator; +use Drupal\KernelTests\KernelTestBase; + +/** + * Test handling of decorated services in DependencySerializationTraitPass. + * + * @group system + */ +class DecoratedServiceTest extends KernelTestBase { + + protected static $modules = [ + 'decorated_service_test', + ]; + + /** + * Check that decorated services keep their original service ID. + */ + public function testDecoratedServiceId() { + // Service decorated once. + $test_service = $this->container->get('test_service'); + $this->assertEquals('test_service', $test_service->_serviceId); + $this->assertInstanceOf(TestServiceDecorator::class, $test_service); + + // Service decorated twice. + $test_service2 = $this->container->get('test_service2'); + $this->assertEquals('test_service2', $test_service2->_serviceId); + $this->assertInstanceOf(TestServiceDecorator::class, $test_service2); + } + +} diff --git a/web/core/modules/system/tests/src/Unit/Event/SecurityFileUploadEventSubscriberTest.php b/web/core/modules/system/tests/src/Unit/Event/SecurityFileUploadEventSubscriberTest.php index f51f750b42b87f065bddbb43331c4c470b75a62d..ffeaa0de152a5b1ed47fd9937c62865d3c92e4d9 100644 --- a/web/core/modules/system/tests/src/Unit/Event/SecurityFileUploadEventSubscriberTest.php +++ b/web/core/modules/system/tests/src/Unit/Event/SecurityFileUploadEventSubscriberTest.php @@ -84,7 +84,8 @@ public function provideFilenames() { 'filename is munged' => ['foo.phar.png.php.jpg', 'jpg png', 'foo.phar_.png_.php_.jpg'], 'filename is munged regardless of case' => ['FOO.pHAR.PNG.PhP.jpg', 'jpg png', 'FOO.pHAR_.PNG_.PhP_.jpg'], 'null bytes are removed' => ['foo' . chr(0) . '.txt' . chr(0), '', 'foo.txt'], - 'dot files are renamed' => ['.htaccess', '', 'htaccess'], + 'dot files are renamed' => ['.git', '', 'git'], + 'htaccess files are renamed even if allowed' => ['.htaccess', 'htaccess txt', '.htaccess_.txt', '.htaccess'], ]; } diff --git a/web/core/modules/views/src/ViewExecutable.php b/web/core/modules/views/src/ViewExecutable.php index 3da94957027fa190e5aeb5be81af580bc1311011..5a7c6307b455737b71403e1dc2e48a60456c4c7d 100644 --- a/web/core/modules/views/src/ViewExecutable.php +++ b/web/core/modules/views/src/ViewExecutable.php @@ -2492,8 +2492,6 @@ public function __sleep() { // state during unserialization. $this->serializationData = [ 'storage' => $this->storage->id(), - 'views_data' => $this->viewsData->_serviceId, - 'route_provider' => $this->routeProvider->_serviceId, 'current_display' => $this->current_display, 'args' => $this->args, 'current_page' => $this->current_page, @@ -2520,8 +2518,8 @@ public function __wakeup() { // Attach all necessary services. $this->user = \Drupal::currentUser(); - $this->viewsData = \Drupal::service($this->serializationData['views_data']); - $this->routeProvider = \Drupal::service($this->serializationData['route_provider']); + $this->viewsData = \Drupal::service('views.views_data'); + $this->routeProvider = \Drupal::service('router.route_provider'); // Restore the state of this executable. if ($request = \Drupal::request()) { diff --git a/web/core/modules/views/tests/src/Functional/Wizard/BasicTest.php b/web/core/modules/views/tests/src/Functional/Wizard/BasicTest.php index 0909299bf6cb9f7acf274a11059ace2ecb1ecb39..fbbd320609d4a9ce4411619b4a17522bf989a915 100644 --- a/web/core/modules/views/tests/src/Functional/Wizard/BasicTest.php +++ b/web/core/modules/views/tests/src/Functional/Wizard/BasicTest.php @@ -155,9 +155,6 @@ public function testViewsWizardAndListing() { $this->assertSession()->pageTextContains($node1->label()); $this->assertSession()->pageTextNotContains($node2->label()); - // Make sure the listing page doesn't show disabled default views. - $this->assertSession()->pageTextNotContains('tracker'); - // Create a view with only a REST export. $view4 = []; $view4['label'] = $this->randomMachineName(16); diff --git a/web/core/scripts/js/vendor-update.js b/web/core/scripts/js/vendor-update.js index df014bab69f0291f578e5621a6bdc49a025bd1a0..56f79e0759d699eba7112c4264a37f7a48ceb4b0 100644 --- a/web/core/scripts/js/vendor-update.js +++ b/web/core/scripts/js/vendor-update.js @@ -77,7 +77,7 @@ const assetsFolder = `${coreFolder}/assets/vendor`; { pack: 'backbone', library: 'internal.backbone', - files: ['backbone.js', 'backbone-min.js', 'backbone-min.map'], + files: ['backbone.js', 'backbone-min.js', 'backbone-min.js.map'], }, // Only used to update the version number of the deprecated library. { diff --git a/web/core/tests/Drupal/BuildTests/Composer/Template/ComposerProjectTemplatesTest.php b/web/core/tests/Drupal/BuildTests/Composer/Template/ComposerProjectTemplatesTest.php index e7e7b2801ffd0db959dc2fe7af94a32f2344b737..7aad3dd7916c87b3452d2792417896b64065e4ed 100644 --- a/web/core/tests/Drupal/BuildTests/Composer/Template/ComposerProjectTemplatesTest.php +++ b/web/core/tests/Drupal/BuildTests/Composer/Template/ComposerProjectTemplatesTest.php @@ -244,6 +244,14 @@ public function testTemplateCreateProject($project, $package_dir, $docroot_dir) $this->executeCommand("COMPOSER_HOME=$composer_home COMPOSER_ROOT_VERSION=$simulated_core_version composer create-project --no-ansi $project testproject $simulated_core_version -vvv --repository $repository_path"); $this->assertCommandSuccessful(); + // Check the output of the project creation for the absence of warnings + // about any non-allowed composer plugins. + // Note: There are different warnings for unallowed composer plugins + // depending on running in non-interactive mode or not. It seems the Drupal + // CI environment always forces composer commands to run in the + // non-interactive mode. The only thing these messages have in common is the + // following string. + $this->assertErrorOutputNotContains('See https://getcomposer.org/allow-plugins'); // Ensure we used the project from our codebase. $this->assertErrorOutputContains("Installing $project ($simulated_core_version): Symlinking from $package_dir"); @@ -386,6 +394,16 @@ protected function makeVendorPackage($repository_path) { "version" => $version, ], ]; + // Ensure composer plugins are registered correctly. + $package_json = json_decode(file_get_contents($full_path . '/composer.json'), TRUE); + if (isset($package_json['type']) && $package_json['type'] === 'composer-plugin') { + $packages['packages'][$name][$version]['type'] = $package_json['type']; + $packages['packages'][$name][$version]['require'] = $package_json['require']; + $packages['packages'][$name][$version]['extra'] = $package_json['extra']; + if (isset($package_json['autoload'])) { + $packages['packages'][$name][$version]['autoload'] = $package_json['autoload']; + } + } } } diff --git a/web/core/tests/Drupal/BuildTests/Framework/BuildTestBase.php b/web/core/tests/Drupal/BuildTests/Framework/BuildTestBase.php index 05cb76783bd27b0885466c9c0724df1c94a2f6fa..a6de48990a18ec1330bf7a8d954feaa849b9eb4f 100644 --- a/web/core/tests/Drupal/BuildTests/Framework/BuildTestBase.php +++ b/web/core/tests/Drupal/BuildTests/Framework/BuildTestBase.php @@ -265,6 +265,16 @@ public function assertErrorOutputContains($expected) { $this->assertStringContainsString($expected, $this->commandProcess->getErrorOutput()); } + /** + * Assert text is not present in the error output of the most recent command. + * + * @param string $expected + * Text we expect not to find in the error output of the command. + */ + public function assertErrorOutputNotContains($expected) { + $this->assertStringNotContainsString($expected, $this->commandProcess->getErrorOutput()); + } + /** * Assert that text is present in the output of the most recent command. * diff --git a/web/core/tests/Drupal/FunctionalTests/BrowserTestBaseTest.php b/web/core/tests/Drupal/FunctionalTests/BrowserTestBaseTest.php index a4f2a6500fcceec5fa0774269500ed385efe9d4a..ab224eca47384b8d21ec534b3c386efec5e654fc 100644 --- a/web/core/tests/Drupal/FunctionalTests/BrowserTestBaseTest.php +++ b/web/core/tests/Drupal/FunctionalTests/BrowserTestBaseTest.php @@ -760,6 +760,9 @@ public function testCronRun() { public function testInstall() { $htaccess_filename = $this->tempFilesDirectory . '/.htaccess'; $this->assertFileExists($htaccess_filename); + + // Ensure the update module is not installed. + $this->assertFalse(\Drupal::moduleHandler()->moduleExists('update'), 'The Update module is not installed.'); } /** diff --git a/web/core/tests/Drupal/FunctionalTests/Installer/InstallerExistingConfigTestBase.php b/web/core/tests/Drupal/FunctionalTests/Installer/InstallerExistingConfigTestBase.php index 8a6a9308fcaad1fe3ede391d071a966b9f2b5f61..1e04685e241d778607c49c53224fd5d6158d7c5a 100644 --- a/web/core/tests/Drupal/FunctionalTests/Installer/InstallerExistingConfigTestBase.php +++ b/web/core/tests/Drupal/FunctionalTests/Installer/InstallerExistingConfigTestBase.php @@ -105,7 +105,8 @@ protected function installParameters() { // existing configuration. unset($parameters['forms']['install_configure_form']['site_name']); unset($parameters['forms']['install_configure_form']['site_mail']); - unset($parameters['forms']['install_configure_form']['update_status_module']); + unset($parameters['forms']['install_configure_form']['enable_update_status_module']); + unset($parameters['forms']['install_configure_form']['enable_update_status_emails']); return $parameters; } diff --git a/web/core/tests/Drupal/FunctionalTests/Installer/InstallerTest.php b/web/core/tests/Drupal/FunctionalTests/Installer/InstallerTest.php index 118a77124577aede34f9033925258dee1f1560d9..af85b7e7fd221a14684dd71394bf6538e88fe4f4 100644 --- a/web/core/tests/Drupal/FunctionalTests/Installer/InstallerTest.php +++ b/web/core/tests/Drupal/FunctionalTests/Installer/InstallerTest.php @@ -131,6 +131,9 @@ public function testInstalled() { $module = $database->getProvider(); $module_handler = \Drupal::service('module_handler'); + // Ensure the update module is not installed. + $this->assertFalse($module_handler->moduleExists('update'), 'The Update module is not installed.'); + // Assert that the module that is providing the database driver has been // installed. $this->assertTrue($module_handler->moduleExists($module)); diff --git a/web/core/tests/Drupal/FunctionalTests/Installer/InstallerTestBase.php b/web/core/tests/Drupal/FunctionalTests/Installer/InstallerTestBase.php index caf4afab0ff984fca4ab2d891afbf4617373226c..1cc8300aadcb93009a18243eacc21bc422a28e47 100644 --- a/web/core/tests/Drupal/FunctionalTests/Installer/InstallerTestBase.php +++ b/web/core/tests/Drupal/FunctionalTests/Installer/InstallerTestBase.php @@ -73,6 +73,19 @@ abstract class InstallerTestBase extends BrowserTestBase { */ protected $isInstalled = FALSE; + /** + * {@inheritdoc} + */ + protected function installParameters() { + $params = parent::installParameters(); + // Set the checkbox values to FALSE so that + // \Drupal\Tests\BrowserTestBase::translatePostValues() does not remove + // them. + $params['forms']['install_configure_form']['enable_update_status_module'] = FALSE; + $params['forms']['install_configure_form']['enable_update_status_emails'] = FALSE; + return $params; + } + /** * {@inheritdoc} */ diff --git a/web/core/tests/Drupal/KernelTests/Core/Image/ToolkitGdTest.php b/web/core/tests/Drupal/KernelTests/Core/Image/ToolkitGdTest.php index 3854f3ef8f1d49ec9a95a9a13480d56b2266996c..8db24885962a23e43d62d3dd497139b40d314d69 100644 --- a/web/core/tests/Drupal/KernelTests/Core/Image/ToolkitGdTest.php +++ b/web/core/tests/Drupal/KernelTests/Core/Image/ToolkitGdTest.php @@ -4,54 +4,46 @@ use Drupal\Core\File\FileSystemInterface; use Drupal\Core\Image\ImageInterface; -use Drupal\Component\Render\FormattableMarkup; -use Drupal\Core\Site\Settings; use Drupal\KernelTests\KernelTestBase; /** - * Tests that core image manipulations work properly: scale, resize, rotate, - * crop, scale and crop, and desaturate. + * Tests for the GD image toolkit. * + * @coversDefaultClass \Drupal\system\Plugin\ImageToolkit\GDToolkit * @group Image * @requires extension gd */ class ToolkitGdTest extends KernelTestBase { /** - * The image factory service. - * - * @var \Drupal\Core\Image\ImageFactory + * Colors that are used in testing. */ - protected $imageFactory; + protected const BLACK = [0, 0, 0, 0]; + protected const RED = [255, 0, 0, 0]; + protected const GREEN = [0, 255, 0, 0]; + protected const BLUE = [0, 0, 255, 0]; + protected const YELLOW = [255, 255, 0, 0]; + protected const WHITE = [255, 255, 255, 0]; + protected const TRANSPARENT = [0, 0, 0, 127]; + protected const FUCHSIA = [255, 0, 255, 0]; + protected const ROTATE_TRANSPARENT = [255, 255, 255, 127]; /** - * Colors that are used in testing. + * The image factory service. * - * @var array + * @var \Drupal\Core\Image\ImageFactory */ - protected $black = [0, 0, 0, 0]; - protected $red = [255, 0, 0, 0]; - protected $green = [0, 255, 0, 0]; - protected $blue = [0, 0, 255, 0]; - protected $yellow = [255, 255, 0, 0]; - protected $white = [255, 255, 255, 0]; - protected $transparent = [0, 0, 0, 127]; + protected $imageFactory; /** - * Used as rotate background colors. + * A directory where test image files can be saved to. * - * @var array + * @var string */ - protected $fuchsia = [255, 0, 255, 0]; - protected $rotateTransparent = [255, 255, 255, 127]; - - protected $width = 40; - protected $height = 20; + protected $directory; /** - * Modules to enable. - * - * @var array + * {@inheritdoc} */ protected static $modules = ['system']; @@ -62,32 +54,41 @@ protected function setUp(): void { parent::setUp(); $this->installConfig(['system']); + // Set the image factory service. $this->imageFactory = $this->container->get('image.factory'); + $this->assertEquals('gd', $this->imageFactory->getToolkitId(), 'The image factory is set to use the \'gd\' image toolkit.'); + + // Prepare a directory for test file results. + $this->directory = 'public://imagetest'; + \Drupal::service('file_system')->prepareDirectory($this->directory, FileSystemInterface::CREATE_DIRECTORY); } /** - * Function to compare two colors by RGBa. + * Assert two colors are equal by RGBA, net of full transparency. + * + * @param int[] $expected + * The expected RGBA array. + * @param int[] $actual + * The actual RGBA array. + * @param int $tolerance + * The acceptable difference between the colors. + * @param string $message + * The assertion message. */ - public function colorsAreEqual($color_a, $color_b) { - // Fully transparent pixels are equal, regardless of RGB. - if ($color_a[3] == 127 && $color_b[3] == 127) { - return TRUE; + protected function assertColorsAreEqual(array $expected, array $actual, int $tolerance, string $message = ''): void { + // Fully transparent colors are equal, regardless of RGB. + if ($actual[3] == 127 && $expected[3] == 127) { + return; } - - foreach ($color_a as $key => $value) { - if ($color_b[$key] != $value) { - return FALSE; - } - } - - return TRUE; + $distance = pow(($actual[0] - $expected[0]), 2) + pow(($actual[1] - $expected[1]), 2) + pow(($actual[2] - $expected[2]), 2) + pow(($actual[3] - $expected[3]), 2); + $this->assertLessThanOrEqual($tolerance, $distance, $message . " - Actual: {" . implode(',', $actual) . "}, Expected: {" . implode(',', $expected) . "}, Distance: " . $distance . ", Tolerance: " . $tolerance); } /** * Function for finding a pixel's RGBa values. */ - public function getPixelColor(ImageInterface $image, $x, $y) { + public function getPixelColor(ImageInterface $image, int $x, int $y): array { $toolkit = $image->getToolkit(); $color_index = imagecolorat($toolkit->getResource(), $x, $y); @@ -100,123 +101,87 @@ public function getPixelColor(ImageInterface $image, $x, $y) { } /** - * Since PHP can't visually check that our images have been manipulated - * properly, build a list of expected color values for each of the corners and - * the expected height and widths for the final images. + * Data provider for ::testManipulations(). */ - public function testManipulations() { - - // Test that the image factory is set to use the GD toolkit. - $this->assertEquals('gd', $this->imageFactory->getToolkitId(), 'The image factory is set to use the \'gd\' image toolkit.'); - - // Test the list of supported extensions. - $expected_extensions = ['png', 'gif', 'jpeg', 'jpg', 'jpe', 'webp']; - $supported_extensions = $this->imageFactory->getSupportedExtensions(); - $this->assertEquals($expected_extensions, array_intersect($expected_extensions, $supported_extensions)); - - // Test that the supported extensions map to correct internal GD image - // types. - $expected_image_types = [ - 'png' => IMAGETYPE_PNG, - 'gif' => IMAGETYPE_GIF, - 'jpeg' => IMAGETYPE_JPEG, - 'jpg' => IMAGETYPE_JPEG, - 'jpe' => IMAGETYPE_JPEG, - 'webp' => IMAGETYPE_WEBP, - ]; - $image = $this->imageFactory->get(); - foreach ($expected_image_types as $extension => $expected_image_type) { - $image_type = $image->getToolkit()->extensionToImageType($extension); - $this->assertSame($expected_image_type, $image_type); - } - + public function providerTestImageFiles(): array { // Typically the corner colors will be unchanged. These colors are in the // order of top-left, top-right, bottom-right, bottom-left. - $default_corners = [$this->red, $this->green, $this->blue, $this->transparent]; - - // A list of files that will be tested. - $files = [ - 'image-test.png', - 'image-test.gif', - 'image-test-no-transparency.gif', - 'image-test.jpg', - 'img-test.webp', - ]; + $default_corners = [static::RED, static::GREEN, static::BLUE, static::TRANSPARENT]; // Setup a list of tests to perform on each type. - $operations = [ + $test_cases = [ 'resize' => [ - 'function' => 'resize', + 'operation' => 'resize', 'arguments' => ['width' => 20, 'height' => 10], 'width' => 20, 'height' => 10, 'corners' => $default_corners, ], 'scale_x' => [ - 'function' => 'scale', + 'operation' => 'scale', 'arguments' => ['width' => 20], 'width' => 20, 'height' => 10, 'corners' => $default_corners, ], 'scale_y' => [ - 'function' => 'scale', + 'operation' => 'scale', 'arguments' => ['height' => 10], 'width' => 20, 'height' => 10, 'corners' => $default_corners, ], 'upscale_x' => [ - 'function' => 'scale', + 'operation' => 'scale', 'arguments' => ['width' => 80, 'upscale' => TRUE], 'width' => 80, 'height' => 40, 'corners' => $default_corners, ], 'upscale_y' => [ - 'function' => 'scale', + 'operation' => 'scale', 'arguments' => ['height' => 40, 'upscale' => TRUE], 'width' => 80, 'height' => 40, 'corners' => $default_corners, ], 'crop' => [ - 'function' => 'crop', + 'operation' => 'crop', 'arguments' => ['x' => 12, 'y' => 4, 'width' => 16, 'height' => 12], 'width' => 16, 'height' => 12, - 'corners' => array_fill(0, 4, $this->white), + 'corners' => array_fill(0, 4, static::WHITE), ], 'scale_and_crop' => [ - 'function' => 'scale_and_crop', + 'operation' => 'scale_and_crop', 'arguments' => ['width' => 10, 'height' => 8], 'width' => 10, 'height' => 8, - 'corners' => array_fill(0, 4, $this->black), + 'corners' => array_fill(0, 4, static::BLACK), ], 'convert_jpg' => [ - 'function' => 'convert', + 'operation' => 'convert', 'width' => 40, 'height' => 20, 'arguments' => ['extension' => 'jpeg'], 'corners' => $default_corners, ], 'convert_gif' => [ - 'function' => 'convert', + 'operation' => 'convert', 'width' => 40, 'height' => 20, 'arguments' => ['extension' => 'gif'], 'corners' => $default_corners, ], 'convert_png' => [ - 'function' => 'convert', + 'operation' => 'convert', 'width' => 40, 'height' => 20, 'arguments' => ['extension' => 'png'], 'corners' => $default_corners, ], 'convert_webp' => [ - 'function' => 'convert', + 'operation' => 'convert', 'width' => 40, 'height' => 20, 'arguments' => ['extension' => 'webp'], @@ -224,49 +189,51 @@ public function testManipulations() { ], ]; - // Systems using non-bundled GD2 don't have imagerotate. Test if available. - // @todo Remove the version check once - // https://www.drupal.org/project/drupal/issues/2670966 is resolved. - if (function_exists('imagerotate') && (version_compare(phpversion(), '7.0.26') < 0)) { - $operations += [ + // Systems using non-bundled GD2 may miss imagerotate(). Test if available. + if (function_exists('imagerotate')) { + $test_cases += [ 'rotate_5' => [ - 'function' => 'rotate', + 'operation' => 'rotate', // Fuchsia background. 'arguments' => ['degrees' => 5, 'background' => '#FF00FF'], - 'width' => 41, - 'height' => 23, - 'corners' => array_fill(0, 4, $this->fuchsia), + // @todo Re-enable dimensions' check once + // https://www.drupal.org/project/drupal/issues/2921123 is resolved. + // 'width' => 41, + // 'height' => 23, + 'corners' => array_fill(0, 4, static::FUCHSIA), + ], + 'rotate_transparent_5' => [ + 'operation' => 'rotate', + 'arguments' => ['degrees' => 5], + // @todo Re-enable dimensions' check once + // https://www.drupal.org/project/drupal/issues/2921123 is resolved. + // 'width' => 41, + // 'height' => 23, + 'corners' => array_fill(0, 4, static::ROTATE_TRANSPARENT), ], 'rotate_90' => [ - 'function' => 'rotate', + 'operation' => 'rotate', // Fuchsia background. 'arguments' => ['degrees' => 90, 'background' => '#FF00FF'], 'width' => 20, 'height' => 40, - 'corners' => [$this->transparent, $this->red, $this->green, $this->blue], - ], - 'rotate_transparent_5' => [ - 'function' => 'rotate', - 'arguments' => ['degrees' => 5], - 'width' => 41, - 'height' => 23, - 'corners' => array_fill(0, 4, $this->rotateTransparent), + 'corners' => [static::TRANSPARENT, static::RED, static::GREEN, static::BLUE], ], 'rotate_transparent_90' => [ - 'function' => 'rotate', + 'operation' => 'rotate', 'arguments' => ['degrees' => 90], 'width' => 20, 'height' => 40, - 'corners' => [$this->transparent, $this->red, $this->green, $this->blue], + 'corners' => [static::TRANSPARENT, static::RED, static::GREEN, static::BLUE], ], ]; } - // Systems using non-bundled GD2 don't have imagefilter. Test if available. + // Systems using non-bundled GD2 may miss imagefilter(). Test if available. if (function_exists('imagefilter')) { - $operations += [ + $test_cases += [ 'desaturate' => [ - 'function' => 'desaturate', + 'operation' => 'desaturate', 'arguments' => [], 'height' => 20, 'width' => 40, @@ -283,148 +250,202 @@ public function testManipulations() { ]; } - // Prepare a directory for test file results. - $directory = Settings::get('file_public_path') . '/imagetest'; - \Drupal::service('file_system')->prepareDirectory($directory, FileSystemInterface::CREATE_DIRECTORY); - - foreach ($files as $file) { - foreach ($operations as $op => $values) { - // Load up a fresh image. - $image = $this->imageFactory->get('core/tests/fixtures/files/' . $file); - $toolkit = $image->getToolkit(); - if (!$image->isValid()) { - $this->fail(new FormattableMarkup('Could not load image %file.', ['%file' => $file])); - continue 2; - } - $image_original_type = $image->getToolkit()->getType(); + $ret = []; + foreach ([ + 'image-test.png', + 'image-test.gif', + 'image-test-no-transparency.gif', + 'image-test.jpg', + 'img-test.webp', + ] as $file_name) { + foreach ($test_cases as $test_case => $values) { + $operation = $values['operation']; + $arguments = $values['arguments']; + unset($values['operation'], $values['arguments']); + $ret[] = [$file_name, $test_case, $operation, $arguments, $values]; + } + } - // All images should be converted to truecolor when loaded. - $image_truecolor = imageistruecolor($toolkit->getResource()); - $this->assertTrue($image_truecolor, new FormattableMarkup('Image %file after load is a truecolor image.', ['%file' => $file])); + return $ret; + } - // Store the original GD resource. - $old_res = $toolkit->getResource(); + /** + * Since PHP can't visually check that our images have been manipulated + * properly, build a list of expected color values for each of the corners and + * the expected height and widths for the final images. + * + * @dataProvider providerTestImageFiles + */ + public function testManipulations(string $file_name, string $test_case, string $operation, array $arguments, array $expected): void { + // Load up a fresh image. + $image = $this->imageFactory->get('core/tests/fixtures/files/' . $file_name); + $toolkit = $image->getToolkit(); + $this->assertTrue($image->isValid()); + $image_original_type = $image->getToolkit()->getType(); - // Perform our operation. - $image->apply($values['function'], $values['arguments']); + $this->assertTrue(imageistruecolor($toolkit->getResource()), "Image '$file_name' after load should be a truecolor image, but it is not."); - // If the operation replaced the resource, check that the old one has - // been destroyed. - $new_res = $toolkit->getResource(); - if ($new_res !== $old_res) { - // @todo In https://www.drupal.org/node/3133236 convert this to - // $this->assertIsNotResource($old_res). - $this->assertFalse(is_resource($old_res), new FormattableMarkup("'%operation' destroyed the original resource.", ['%operation' => $values['function']])); - } + // Perform our operation. + $image->apply($operation, $arguments); - // To keep from flooding the test with assert values, make a general - // value for whether each group of values fail. - $correct_dimensions_real = TRUE; - $correct_dimensions_object = TRUE; + // Flush Image object to disk storage. + $file_path = $this->directory . '/' . $test_case . image_type_to_extension($image->getToolkit()->getType()); + $image->save($file_path); - if (imagesy($toolkit->getResource()) != $values['height'] || imagesx($toolkit->getResource()) != $values['width']) { - $correct_dimensions_real = FALSE; - } + // Check that the both the GD object and the Image object have an accurate + // record of the dimensions. + if (isset($expected['height']) && isset($expected['width'])) { + $this->assertSame($expected['height'], imagesy($toolkit->getResource()), "Image '$file_name' after '$test_case' should have a proper height."); + $this->assertSame($expected['width'], imagesx($toolkit->getResource()), "Image '$file_name' after '$test_case' should have a proper width."); + $this->assertSame($expected['height'], $image->getHeight(), "Image '$file_name' after '$test_case' should have a proper height."); + $this->assertSame($expected['width'], $image->getWidth(), "Image '$file_name' after '$test_case' should have a proper width."); + } - // Check that the image object has an accurate record of the dimensions. - if ($image->getWidth() != $values['width'] || $image->getHeight() != $values['height']) { - $correct_dimensions_object = FALSE; + // Now check each of the corners to ensure color correctness. + foreach ($expected['corners'] as $key => $expected_color) { + // The test gif that does not have transparency color set is a + // special case. + if ($file_name === 'image-test-no-transparency.gif') { + if ($test_case == 'desaturate') { + // For desaturating, keep the expected color from the test + // data, but set alpha channel to fully opaque. + $expected_color[3] = 0; } - - $file_path = $directory . '/' . $op . image_type_to_extension($image->getToolkit()->getType()); - $image->save($file_path); - - $this->assertTrue($correct_dimensions_real, new FormattableMarkup('Image %file after %action action has proper dimensions.', ['%file' => $file, '%action' => $op])); - $this->assertTrue($correct_dimensions_object, new FormattableMarkup('Image %file object after %action action is reporting the proper height and width values.', ['%file' => $file, '%action' => $op])); - - // JPEG colors will always be messed up due to compression. So we skip - // these tests if the original or the result is in jpeg format. - if ($image->getToolkit()->getType() != IMAGETYPE_JPEG && $image_original_type != IMAGETYPE_JPEG) { - // Now check each of the corners to ensure color correctness. - foreach ($values['corners'] as $key => $corner) { - // The test gif that does not have transparency color set is a - // special case. - if ($file === 'image-test-no-transparency.gif') { - if ($op == 'desaturate') { - // For desaturating, keep the expected color from the test - // data, but set alpha channel to fully opaque. - $corner[3] = 0; - } - elseif ($corner === $this->transparent) { - // Set expected pixel to yellow where the others have - // transparent. - $corner = $this->yellow; - } - } - - // Get the location of the corner. - switch ($key) { - case 0: - $x = 0; - $y = 0; - break; - - case 1: - $x = $image->getWidth() - 1; - $y = 0; - break; - - case 2: - $x = $image->getWidth() - 1; - $y = $image->getHeight() - 1; - break; - - case 3: - $x = 0; - $y = $image->getHeight() - 1; - break; - } - $color = $this->getPixelColor($image, $x, $y); - // We also skip the color test for transparency for gif <-> png - // conversion. The convert operation cannot handle that correctly. - if ($image->getToolkit()->getType() == $image_original_type || $corner != $this->transparent) { - $correct_colors = $this->colorsAreEqual($color, $corner); - $this->assertTrue($correct_colors, new FormattableMarkup('Image %file object after %action action has the correct color placement at corner %corner.', - ['%file' => $file, '%action' => $op, '%corner' => $key])); - } - } + elseif ($expected_color === static::TRANSPARENT) { + // Set expected pixel to yellow where the others have + // transparent. + $expected_color = static::YELLOW; } + } - // Check that saved image reloads without raising PHP errors. - $image_reloaded = $this->imageFactory->get($file_path); - $resource = $image_reloaded->getToolkit()->getResource(); + // Get the location of the corner. + switch ($key) { + case 0: + $x = 0; + $y = 0; + break; + + case 1: + $x = $image->getWidth() - 1; + $y = 0; + break; + + case 2: + $x = $image->getWidth() - 1; + $y = $image->getHeight() - 1; + break; + + case 3: + $x = 0; + $y = $image->getHeight() - 1; + break; } - } + $actual_color = $this->getPixelColor($image, $x, $y); - // Test creation of image from scratch, and saving to storage. - foreach ([IMAGETYPE_PNG, IMAGETYPE_GIF, IMAGETYPE_JPEG, IMAGETYPE_WEBP] as $type) { - $image = $this->imageFactory->get(); - $image->createNew(50, 20, image_type_to_extension($type, FALSE), '#ffff00'); - $file = 'from_null' . image_type_to_extension($type); - $file_path = $directory . '/' . $file; - $this->assertEquals(50, $image->getWidth(), new FormattableMarkup('Image file %file has the correct width.', ['%file' => $file])); - $this->assertEquals(20, $image->getHeight(), new FormattableMarkup('Image file %file has the correct height.', ['%file' => $file])); - $this->assertEquals(image_type_to_mime_type($type), $image->getMimeType(), new FormattableMarkup('Image file %file has the correct MIME type.', ['%file' => $file])); - $this->assertTrue($image->save($file_path), new FormattableMarkup('Image %file created anew from a null image was saved.', ['%file' => $file])); - - // Reload saved image. - $image_reloaded = $this->imageFactory->get($file_path); - if (!$image_reloaded->isValid()) { - $this->fail(new FormattableMarkup('Could not load image %file.', ['%file' => $file])); + // If image cannot handle transparent colors, skip the pixel color test. + if ($actual_color[3] === 0 && $expected_color[3] === 127) { continue; } - $this->assertEquals(50, $image_reloaded->getWidth(), new FormattableMarkup('Image file %file has the correct width.', ['%file' => $file])); - $this->assertEquals(20, $image_reloaded->getHeight(), new FormattableMarkup('Image file %file has the correct height.', ['%file' => $file])); - $this->assertEquals(image_type_to_mime_type($type), $image_reloaded->getMimeType(), new FormattableMarkup('Image file %file has the correct MIME type.', ['%file' => $file])); - if ($image_reloaded->getToolkit()->getType() == IMAGETYPE_GIF) { - $this->assertEquals('#ffff00', $image_reloaded->getToolkit()->getTransparentColor(), new FormattableMarkup('Image file %file has the correct transparent color channel set.', ['%file' => $file])); - } - else { - $this->assertNull($image_reloaded->getToolkit()->getTransparentColor(), new FormattableMarkup('Image file %file has no color channel set.', ['%file' => $file])); - } + + // JPEG has small differences in color after processing. + $tolerance = $image_original_type === IMAGETYPE_JPEG ? 3 : 0; + + $this->assertColorsAreEqual($expected_color, $actual_color, $tolerance, "Image '$file_name' object after '$test_case' action has the correct color placement at corner '$key'"); + } + + // Check that saved image reloads without raising PHP errors. + $image_reloaded = $this->imageFactory->get($file_path); + if (PHP_VERSION_ID >= 80000) { + $this->assertInstanceOf(\GDImage::class, $image_reloaded->getToolkit()->getResource()); + } + else { + $this->assertIsResource($image_reloaded->getToolkit()->getResource()); + $this->assertSame(get_resource_type($image_reloaded->getToolkit()->getResource()), 'gd'); + } + } + + /** + * @covers ::getSupportedExtensions + * @covers ::extensionToImageType + */ + public function testSupportedExtensions(): void { + // Test the list of supported extensions. + $expected_extensions = ['png', 'gif', 'jpeg', 'jpg', 'jpe', 'webp']; + $this->assertEqualsCanonicalizing($expected_extensions, $this->imageFactory->getSupportedExtensions()); + + // Test that the supported extensions map to correct internal GD image + // types. + $expected_image_types = [ + 'png' => IMAGETYPE_PNG, + 'gif' => IMAGETYPE_GIF, + 'jpeg' => IMAGETYPE_JPEG, + 'jpg' => IMAGETYPE_JPEG, + 'jpe' => IMAGETYPE_JPEG, + 'webp' => IMAGETYPE_WEBP, + ]; + $image = $this->imageFactory->get(); + foreach ($expected_image_types as $extension => $expected_image_type) { + $this->assertSame($expected_image_type, $image->getToolkit()->extensionToImageType($extension)); } + } + + /** + * Data provider for ::testCreateImageFromScratch(). + */ + public function providerSupportedImageTypes(): array { + return [ + [IMAGETYPE_PNG], + [IMAGETYPE_GIF], + [IMAGETYPE_JPEG], + [IMAGETYPE_WEBP], + ]; + } - // Test failures of the 'create_new' operation. + /** + * Tests that GD functions for the image type are available. + * + * @dataProvider providerSupportedImageTypes + */ + public function testGdFunctionsExist(int $type): void { + $extension = image_type_to_extension($type, FALSE); + $this->assertTrue(function_exists("imagecreatefrom$extension"), "imagecreatefrom$extension should exist."); + $this->assertTrue(function_exists("image$extension"), "image$extension should exist."); + } + + /** + * Tests creation of image from scratch, and saving to storage. + * + * @dataProvider providerSupportedImageTypes + */ + public function testCreateImageFromScratch(int $type): void { + // Build an image from scratch. + $image = $this->imageFactory->get(); + $image->createNew(50, 20, image_type_to_extension($type, FALSE), '#ffff00'); + $file = 'from_null' . image_type_to_extension($type); + $file_path = $this->directory . '/' . $file; + $this->assertSame(50, $image->getWidth()); + $this->assertSame(20, $image->getHeight()); + $this->assertSame(image_type_to_mime_type($type), $image->getMimeType()); + $this->assertTrue($image->save($file_path), "Image '$file' should have been saved successfully, but it has not."); + + // Reload and check saved image. + $image_reloaded = $this->imageFactory->get($file_path); + $this->assertTrue($image_reloaded->isValid()); + $this->assertSame(50, $image_reloaded->getWidth()); + $this->assertSame(20, $image_reloaded->getHeight()); + $this->assertSame(image_type_to_mime_type($type), $image_reloaded->getMimeType()); + if ($image_reloaded->getToolkit()->getType() == IMAGETYPE_GIF) { + $this->assertSame('#ffff00', $image_reloaded->getToolkit()->getTransparentColor(), "Image '$file' after reload should have color channel set to #ffff00, but it has not."); + } + else { + $this->assertNull($image_reloaded->getToolkit()->getTransparentColor(), "Image '$file' after reload should have no color channel set, but it has."); + } + } + + /** + * Tests failures of the 'create_new' operation. + */ + public function testCreateNewFailures(): void { $image = $this->imageFactory->get(); $image->createNew(-50, 20); $this->assertFalse($image->isValid(), 'CreateNew with negative width fails.'); @@ -472,11 +493,7 @@ public function testResourceDestruction() { /** * Tests for GIF images with transparency. */ - public function testGifTransparentImages() { - // Prepare a directory for test file results. - $directory = Settings::get('file_public_path') . '/imagetest'; - \Drupal::service('file_system')->prepareDirectory($directory, FileSystemInterface::CREATE_DIRECTORY); - + public function testGifTransparentImages(): void { // Test loading an indexed GIF image with transparent color set. // Color at top-right pixel should be fully transparent. $file = 'image-test-transparent-indexed.gif'; @@ -484,20 +501,20 @@ public function testGifTransparentImages() { $resource = $image->getToolkit()->getResource(); $color_index = imagecolorat($resource, $image->getWidth() - 1, 0); $color = array_values(imagecolorsforindex($resource, $color_index)); - $this->assertEquals($this->rotateTransparent, $color, "Image {$file} after load has full transparent color at corner 1."); + $this->assertEquals(static::ROTATE_TRANSPARENT, $color, "Image {$file} after load has full transparent color at corner 1."); // Test deliberately creating a GIF image with no transparent color set. // Color at top-right pixel should be fully transparent while in memory, // fully opaque after flushing image to file. $file = 'image-test-no-transparent-color-set.gif'; - $file_path = $directory . '/' . $file; + $file_path = $this->directory . '/' . $file; // Create image. $image = $this->imageFactory->get(); $image->createNew(50, 20, 'gif', NULL); $resource = $image->getToolkit()->getResource(); $color_index = imagecolorat($resource, $image->getWidth() - 1, 0); $color = array_values(imagecolorsforindex($resource, $color_index)); - $this->assertEquals($this->rotateTransparent, $color, "New GIF image with no transparent color set after creation has full transparent color at corner 1."); + $this->assertEquals(static::ROTATE_TRANSPARENT, $color, "New GIF image with no transparent color set after creation has full transparent color at corner 1."); // Save image. $this->assertTrue($image->save($file_path), "New GIF image {$file} was saved."); // Reload image. @@ -522,37 +539,20 @@ public function testGifTransparentImages() { // can be loaded correctly. $file = 'image-test-transparent-out-of-range.gif'; $image = $this->imageFactory->get('core/tests/fixtures/files/' . $file); - $toolkit = $image->getToolkit(); - - if (!$image->isValid()) { - $this->fail(new FormattableMarkup('Could not load image %file.', ['%file' => $file])); - } - else { - // All images should be converted to truecolor when loaded. - $image_truecolor = imageistruecolor($toolkit->getResource()); - $this->assertTrue($image_truecolor, new FormattableMarkup('Image %file after load is a truecolor image.', ['%file' => $file])); - } + $this->assertTrue($image->isValid(), "Image '$file' after load should be valid, but it is not."); + $this->assertTrue(imageistruecolor($image->getToolkit()->getResource()), "Image '$file' after load should be a truecolor image, but it is not."); } /** * Tests calling a missing image operation plugin. */ - public function testMissingOperation() { - - // Test that the image factory is set to use the GD toolkit. - $this->assertEquals('gd', $this->imageFactory->getToolkitId(), 'The image factory is set to use the \'gd\' image toolkit.'); - - // An image file that will be tested. - $file = 'image-test.png'; - + public function testMissingOperation(): void { // Load up a fresh image. - $image = $this->imageFactory->get('core/tests/fixtures/files/' . $file); - if (!$image->isValid()) { - $this->fail(new FormattableMarkup('Could not load image %file.', ['%file' => $file])); - } + $image = $this->imageFactory->get('core/tests/fixtures/files/image-test.png'); + $this->assertTrue($image->isValid(), "Image 'image-test.png' after load should be valid, but it is not."); // Try perform a missing toolkit operation. - $this->assertFalse($image->apply('missing_op', []), 'Calling a missing image toolkit operation plugin fails.'); + $this->assertFalse($image->apply('missing_op', []), 'Calling a missing image toolkit operation plugin should fail, but it did not.'); } } diff --git a/web/core/tests/Drupal/Tests/BrowserHtmlDebugTrait.php b/web/core/tests/Drupal/Tests/BrowserHtmlDebugTrait.php index 18deac7e359dd8bc5b30b7a299a8c5221ab44115..fe559499f55c28842a02da69170d3fffea104ca9 100644 --- a/web/core/tests/Drupal/Tests/BrowserHtmlDebugTrait.php +++ b/web/core/tests/Drupal/Tests/BrowserHtmlDebugTrait.php @@ -179,11 +179,14 @@ protected function getResponseLogHandler() { $html_output = 'Called from ' . $caller['function'] . ' line ' . $caller['line']; $html_output .= '<hr />' . $request->getMethod() . ' request to: ' . $request->getUri(); - // Get the response body as a string. Any errors are silenced as - // tests should not fail if there is a problem. On PHP 7.4 - // \Drupal\Tests\migrate\Functional\process\DownloadFunctionalTest - // fails without the usage of a silence operator. - $body = @(string) $response->getBody(); + /** @var \Psr\Http\Message\StreamInterface $stream */ + $stream = $response->getBody(); + + // Get the response body as a string. + $body = $stream->isReadable() + ? (string) $stream + : 'Response is not readable.'; + // On redirect responses (status code starting with '3') we need // to remove the meta tag that would do a browser refresh. We // don't want to redirect developers away when they look at the diff --git a/web/core/tests/Drupal/Tests/Composer/Plugin/Scaffold/Functional/ComposerHookTest.php b/web/core/tests/Drupal/Tests/Composer/Plugin/Scaffold/Functional/ComposerHookTest.php index 8ff94785d746efca375e304cf33327574903f7bd..1bc89295b481fe5ef8500af84dbdc9037d22e841 100644 --- a/web/core/tests/Drupal/Tests/Composer/Plugin/Scaffold/Functional/ComposerHookTest.php +++ b/web/core/tests/Drupal/Tests/Composer/Plugin/Scaffold/Functional/ComposerHookTest.php @@ -3,10 +3,10 @@ namespace Drupal\Tests\Composer\Plugin\Scaffold\Functional; use Composer\Util\Filesystem; +use Drupal\BuildTests\Framework\BuildTestBase; use Drupal\Tests\Composer\Plugin\Scaffold\AssertUtilsTrait; use Drupal\Tests\Composer\Plugin\Scaffold\ExecTrait; use Drupal\Tests\Composer\Plugin\Scaffold\Fixtures; -use PHPUnit\Framework\TestCase; /** * Tests Composer Hooks that run scaffold operations. @@ -22,7 +22,8 @@ * * @group Scaffold */ -class ComposerHookTest extends TestCase { +class ComposerHookTest extends BuildTestBase { + use ExecTrait; use AssertUtilsTrait; @@ -120,9 +121,10 @@ public function testComposerHooks() { $this->mustExec("composer install --no-ansi", $sut); // Require a project that is not allowed to scaffold and confirm that we // get a warning, and it does not scaffold. - $stdout = $this->mustExec("composer require --no-ansi --no-interaction fixtures/drupal-assets-fixture:dev-main fixtures/scaffold-override-fixture:dev-main", $sut); + $this->executeCommand("composer require --no-ansi --no-interaction fixtures/drupal-assets-fixture:dev-main fixtures/scaffold-override-fixture:dev-main", $sut); + $this->assertCommandSuccessful(); $this->assertFileDoesNotExist($sut . '/sites/default/default.settings.php'); - $this->assertStringContainsString("Not scaffolding files for fixtures/scaffold-override-fixture, because it is not listed in the element 'extra.drupal-scaffold.allowed-packages' in the root-level composer.json file.", $stdout); + $this->assertErrorOutputContains('See https://getcomposer.org/allow-plugins'); } /** diff --git a/web/core/tests/Drupal/Tests/Composer/Plugin/Scaffold/fixtures/composer-hooks-fixture/composer.json.tmpl b/web/core/tests/Drupal/Tests/Composer/Plugin/Scaffold/fixtures/composer-hooks-fixture/composer.json.tmpl index f5f5d2a2866c6e9ce6fcba1126318262c9967119..d28a71273df1f915da41a3d2f56d30564c1ffd60 100644 --- a/web/core/tests/Drupal/Tests/Composer/Plugin/Scaffold/fixtures/composer-hooks-fixture/composer.json.tmpl +++ b/web/core/tests/Drupal/Tests/Composer/Plugin/Scaffold/fixtures/composer-hooks-fixture/composer.json.tmpl @@ -64,5 +64,10 @@ "libraries/{$name}": ["type:drupal-library"], "drush/Commands/contrib/{$name}": ["type:drupal-drush"] } + }, + "config": { + "allow-plugins": { + "drupal/core-composer-scaffold": true + } } } diff --git a/web/core/tests/Drupal/Tests/Composer/Plugin/Scaffold/fixtures/drupal-drupal/composer.json.tmpl b/web/core/tests/Drupal/Tests/Composer/Plugin/Scaffold/fixtures/drupal-drupal/composer.json.tmpl index 00a91d79591f2460ab05d8d59d384553192f1255..bf8b11d6c4a02801bf5233c43221309682ad3ee1 100644 --- a/web/core/tests/Drupal/Tests/Composer/Plugin/Scaffold/fixtures/drupal-drupal/composer.json.tmpl +++ b/web/core/tests/Drupal/Tests/Composer/Plugin/Scaffold/fixtures/drupal-drupal/composer.json.tmpl @@ -67,5 +67,10 @@ "libraries/{$name}": ["type:drupal-library"], "drush/Commands/contrib/{$name}": ["type:drupal-drush"] } - } + }, + "config": { + "allow-plugins": { + "drupal/core-composer-scaffold": true + } + } } diff --git a/web/core/tests/Drupal/Tests/Core/Site/SettingsTest.php b/web/core/tests/Drupal/Tests/Core/Site/SettingsTest.php index bcc2eda6c9d1d944e267f0b722fbd201aabd9a28..4e9a3ec6fdf84dc8276e29ce4574b0b9a01973e9 100644 --- a/web/core/tests/Drupal/Tests/Core/Site/SettingsTest.php +++ b/web/core/tests/Drupal/Tests/Core/Site/SettingsTest.php @@ -353,7 +353,7 @@ public function testDatabaseInfoInitialization(string $driver, ?string $namespac if (!empty($expected_autoload)) { $class_loader->expects($this->once()) ->method('addPsr4') - ->with($expected_namespace . '\\', $expected_autoload); + ->with($expected_namespace . '\\', vfsStream::url('root') . '/' . $expected_autoload); } else { $class_loader->expects($this->never()) diff --git a/web/core/themes/olivero/templates/includes/get-started.html.twig b/web/core/themes/olivero/templates/includes/get-started.html.twig index e96327a7fca43da374beea5313a9b090f208ab3b..fd9600cb9eebacbc770d82e90db15310ad149ac6 100644 --- a/web/core/themes/olivero/templates/includes/get-started.html.twig +++ b/web/core/themes/olivero/templates/includes/get-started.html.twig @@ -14,7 +14,7 @@ {% set drupal_community = 'https://www.drupal.org/community' %} {% set drupal_values = 'https://www.drupal.org/about/values-and-principles' %} {% set drupal_user_guide = 'https://www.drupal.org/docs/user_guide/en/index.html' %} -{% set create_content = '/node/add' %} +{% set create_content = path('node.add_page') %} {% set drupal_extend = 'https://www.drupal.org/docs/extending-drupal' %} {% set drupal_global_training_days = 'https://groups.drupal.org/global-training-days' %} {% set drupal_events = 'https://www.drupal.org/community/events' %} diff --git a/web/core/themes/olivero/templates/views/views-mini-pager.html.twig b/web/core/themes/olivero/templates/views/views-mini-pager.html.twig index b64be942db8357f2fc43116841dafb3e8f3b43e5..a9acc73a0026a2cac595fa088a9a5e5a2738945f 100644 --- a/web/core/themes/olivero/templates/views/views-mini-pager.html.twig +++ b/web/core/themes/olivero/templates/views/views-mini-pager.html.twig @@ -38,7 +38,7 @@ {% apply spaceless %} <li class="pager__item pager__item--control pager__item--next"> <a href="{{ items.next.href }}" class="pager__link" title="{{ 'Go to next page'|t }}" rel="next"{{ items.next.attributes|without('href', 'title', 'rel') }}> - <span class="visually-hidden">{{ 'Previous page'|t }}</span> + <span class="visually-hidden">{{ 'Next page'|t }}</span> {% include "@olivero/../images/pager-previous.svg" %} </a> </li> diff --git a/web/sites/default/default.settings.php b/web/sites/default/default.settings.php index 72be7750b93a427526891c4d02068fed3c9a74f6..f3dca008fa380e153e86c2a6bb953b4c030184b5 100644 --- a/web/sites/default/default.settings.php +++ b/web/sites/default/default.settings.php @@ -490,6 +490,29 @@ */ # $settings['file_public_path'] = 'sites/default/files'; +/** + * Additional public file schemes: + * + * Public schemes are URI schemes that allow download access to all users for + * all files within that scheme. + * + * The "public" scheme is always public, and the "private" scheme is always + * private, but other schemes, such as "https", "s3", "example", or others, + * can be either public or private depending on the site. By default, they're + * private, and access to individual files is controlled via + * hook_file_download(). + * + * Typically, if a scheme should be public, a module makes it public by + * implementing hook_file_download(), and granting access to all users for all + * files. This could be either the same module that provides the stream wrapper + * for the scheme, or a different module that decides to make the scheme + * public. However, in cases where a site needs to make a scheme public, but + * is unable to add code in a module to do so, the scheme may be added to this + * variable, the result of which is that system_file_download() grants public + * access to all files within that scheme. + */ +# $settings['file_additional_public_schemes'] = ['example']; + /** * Private file path: *