]> git.mxchange.org Git - friendica-addons.git/commitdiff
[advancedcontentfilter] Update Composer dependencies ahead of release
authorHypolite Petovan <hypolite@mrpetovan.com>
Wed, 20 Mar 2024 02:35:09 +0000 (22:35 -0400)
committerHypolite Petovan <hypolite@mrpetovan.com>
Wed, 20 Mar 2024 03:10:07 +0000 (23:10 -0400)
- Removing symfony/polyfill-apcu (v1.28.0)
- Removing psr/simple-cache (1.0.1)
- Updating psr/http-message (1.1 => 2.0)
- Downgrading psr/container (2.0.2 => 1.1.2)
- Updating slim/slim (4.12.0 => 4.13.0)
- Installing symfony/polyfill-php80 (v1.29.0)
- Installing symfony/var-exporter (v5.4.35)
- Installing symfony/deprecation-contracts (v2.5.2)
- Installing symfony/service-contracts (v2.5.2)
- Installing symfony/polyfill-php73 (v1.29.0)
- Installing symfony/cache-contracts (v2.5.2)
- Updating symfony/cache (v3.4.47 => v4.4.48)

152 files changed:
advancedcontentfilter/composer.lock
advancedcontentfilter/vendor/composer/autoload_classmap.php
advancedcontentfilter/vendor/composer/autoload_files.php
advancedcontentfilter/vendor/composer/autoload_psr4.php
advancedcontentfilter/vendor/composer/autoload_static.php
advancedcontentfilter/vendor/composer/installed.json
advancedcontentfilter/vendor/psr/container/composer.json
advancedcontentfilter/vendor/psr/container/src/ContainerInterface.php
advancedcontentfilter/vendor/psr/http-message/composer.json
advancedcontentfilter/vendor/psr/http-message/src/MessageInterface.php
advancedcontentfilter/vendor/psr/http-message/src/RequestInterface.php
advancedcontentfilter/vendor/psr/http-message/src/ResponseInterface.php
advancedcontentfilter/vendor/psr/http-message/src/ServerRequestInterface.php
advancedcontentfilter/vendor/psr/http-message/src/StreamInterface.php
advancedcontentfilter/vendor/psr/http-message/src/UploadedFileInterface.php
advancedcontentfilter/vendor/psr/http-message/src/UriInterface.php
advancedcontentfilter/vendor/slim/slim/Slim/Exception/HttpTooManyRequestsException.php [new file with mode: 0644]
advancedcontentfilter/vendor/slim/slim/composer.json
advancedcontentfilter/vendor/symfony/cache-contracts/.gitignore [new file with mode: 0644]
advancedcontentfilter/vendor/symfony/cache-contracts/CHANGELOG.md [new file with mode: 0644]
advancedcontentfilter/vendor/symfony/cache-contracts/CacheInterface.php [new file with mode: 0644]
advancedcontentfilter/vendor/symfony/cache-contracts/CacheTrait.php [new file with mode: 0644]
advancedcontentfilter/vendor/symfony/cache-contracts/CallbackInterface.php [new file with mode: 0644]
advancedcontentfilter/vendor/symfony/cache-contracts/ItemInterface.php [new file with mode: 0644]
advancedcontentfilter/vendor/symfony/cache-contracts/LICENSE [new file with mode: 0644]
advancedcontentfilter/vendor/symfony/cache-contracts/README.md [new file with mode: 0644]
advancedcontentfilter/vendor/symfony/cache-contracts/TagAwareCacheInterface.php [new file with mode: 0644]
advancedcontentfilter/vendor/symfony/cache-contracts/composer.json [new file with mode: 0644]
advancedcontentfilter/vendor/symfony/cache/Adapter/AbstractAdapter.php
advancedcontentfilter/vendor/symfony/cache/Adapter/AbstractTagAwareAdapter.php [new file with mode: 0644]
advancedcontentfilter/vendor/symfony/cache/Adapter/AdapterInterface.php
advancedcontentfilter/vendor/symfony/cache/Adapter/ApcuAdapter.php
advancedcontentfilter/vendor/symfony/cache/Adapter/ArrayAdapter.php
advancedcontentfilter/vendor/symfony/cache/Adapter/ChainAdapter.php
advancedcontentfilter/vendor/symfony/cache/Adapter/DoctrineAdapter.php
advancedcontentfilter/vendor/symfony/cache/Adapter/FilesystemAdapter.php
advancedcontentfilter/vendor/symfony/cache/Adapter/FilesystemTagAwareAdapter.php [new file with mode: 0644]
advancedcontentfilter/vendor/symfony/cache/Adapter/MemcachedAdapter.php
advancedcontentfilter/vendor/symfony/cache/Adapter/NullAdapter.php
advancedcontentfilter/vendor/symfony/cache/Adapter/PdoAdapter.php
advancedcontentfilter/vendor/symfony/cache/Adapter/PhpArrayAdapter.php
advancedcontentfilter/vendor/symfony/cache/Adapter/PhpFilesAdapter.php
advancedcontentfilter/vendor/symfony/cache/Adapter/ProxyAdapter.php
advancedcontentfilter/vendor/symfony/cache/Adapter/Psr16Adapter.php [new file with mode: 0644]
advancedcontentfilter/vendor/symfony/cache/Adapter/RedisAdapter.php
advancedcontentfilter/vendor/symfony/cache/Adapter/RedisTagAwareAdapter.php [new file with mode: 0644]
advancedcontentfilter/vendor/symfony/cache/Adapter/SimpleCacheAdapter.php
advancedcontentfilter/vendor/symfony/cache/Adapter/TagAwareAdapter.php
advancedcontentfilter/vendor/symfony/cache/Adapter/TraceableAdapter.php
advancedcontentfilter/vendor/symfony/cache/Adapter/TraceableTagAwareAdapter.php
advancedcontentfilter/vendor/symfony/cache/CHANGELOG.md
advancedcontentfilter/vendor/symfony/cache/CacheItem.php
advancedcontentfilter/vendor/symfony/cache/DataCollector/CacheDataCollector.php
advancedcontentfilter/vendor/symfony/cache/DependencyInjection/CacheCollectorPass.php [new file with mode: 0644]
advancedcontentfilter/vendor/symfony/cache/DependencyInjection/CachePoolClearerPass.php [new file with mode: 0644]
advancedcontentfilter/vendor/symfony/cache/DependencyInjection/CachePoolPass.php [new file with mode: 0644]
advancedcontentfilter/vendor/symfony/cache/DependencyInjection/CachePoolPrunerPass.php [new file with mode: 0644]
advancedcontentfilter/vendor/symfony/cache/DoctrineProvider.php
advancedcontentfilter/vendor/symfony/cache/Exception/CacheException.php
advancedcontentfilter/vendor/symfony/cache/Exception/InvalidArgumentException.php
advancedcontentfilter/vendor/symfony/cache/Exception/LogicException.php [new file with mode: 0644]
advancedcontentfilter/vendor/symfony/cache/LICENSE
advancedcontentfilter/vendor/symfony/cache/LockRegistry.php [new file with mode: 0644]
advancedcontentfilter/vendor/symfony/cache/Marshaller/DefaultMarshaller.php [new file with mode: 0644]
advancedcontentfilter/vendor/symfony/cache/Marshaller/DeflateMarshaller.php [new file with mode: 0644]
advancedcontentfilter/vendor/symfony/cache/Marshaller/MarshallerInterface.php [new file with mode: 0644]
advancedcontentfilter/vendor/symfony/cache/Marshaller/TagAwareMarshaller.php [new file with mode: 0644]
advancedcontentfilter/vendor/symfony/cache/Psr16Cache.php [new file with mode: 0644]
advancedcontentfilter/vendor/symfony/cache/README.md
advancedcontentfilter/vendor/symfony/cache/ResettableInterface.php
advancedcontentfilter/vendor/symfony/cache/Simple/AbstractCache.php
advancedcontentfilter/vendor/symfony/cache/Simple/ApcuCache.php
advancedcontentfilter/vendor/symfony/cache/Simple/ArrayCache.php
advancedcontentfilter/vendor/symfony/cache/Simple/ChainCache.php
advancedcontentfilter/vendor/symfony/cache/Simple/DoctrineCache.php
advancedcontentfilter/vendor/symfony/cache/Simple/FilesystemCache.php
advancedcontentfilter/vendor/symfony/cache/Simple/MemcachedCache.php
advancedcontentfilter/vendor/symfony/cache/Simple/NullCache.php
advancedcontentfilter/vendor/symfony/cache/Simple/PdoCache.php
advancedcontentfilter/vendor/symfony/cache/Simple/PhpArrayCache.php
advancedcontentfilter/vendor/symfony/cache/Simple/PhpFilesCache.php
advancedcontentfilter/vendor/symfony/cache/Simple/Psr6Cache.php
advancedcontentfilter/vendor/symfony/cache/Simple/RedisCache.php
advancedcontentfilter/vendor/symfony/cache/Simple/TraceableCache.php
advancedcontentfilter/vendor/symfony/cache/Traits/AbstractAdapterTrait.php [new file with mode: 0644]
advancedcontentfilter/vendor/symfony/cache/Traits/AbstractTrait.php
advancedcontentfilter/vendor/symfony/cache/Traits/ApcuTrait.php
advancedcontentfilter/vendor/symfony/cache/Traits/ArrayTrait.php
advancedcontentfilter/vendor/symfony/cache/Traits/ContractsTrait.php [new file with mode: 0644]
advancedcontentfilter/vendor/symfony/cache/Traits/DoctrineTrait.php
advancedcontentfilter/vendor/symfony/cache/Traits/FilesystemCommonTrait.php
advancedcontentfilter/vendor/symfony/cache/Traits/FilesystemTrait.php
advancedcontentfilter/vendor/symfony/cache/Traits/MemcachedTrait.php
advancedcontentfilter/vendor/symfony/cache/Traits/PdoTrait.php
advancedcontentfilter/vendor/symfony/cache/Traits/PhpArrayTrait.php
advancedcontentfilter/vendor/symfony/cache/Traits/PhpFilesTrait.php
advancedcontentfilter/vendor/symfony/cache/Traits/ProxyTrait.php
advancedcontentfilter/vendor/symfony/cache/Traits/RedisClusterNodeProxy.php [new file with mode: 0644]
advancedcontentfilter/vendor/symfony/cache/Traits/RedisClusterProxy.php [new file with mode: 0644]
advancedcontentfilter/vendor/symfony/cache/Traits/RedisProxy.php
advancedcontentfilter/vendor/symfony/cache/Traits/RedisTrait.php
advancedcontentfilter/vendor/symfony/cache/composer.json
advancedcontentfilter/vendor/symfony/deprecation-contracts/.gitignore [new file with mode: 0644]
advancedcontentfilter/vendor/symfony/deprecation-contracts/CHANGELOG.md [new file with mode: 0644]
advancedcontentfilter/vendor/symfony/deprecation-contracts/LICENSE [new file with mode: 0644]
advancedcontentfilter/vendor/symfony/deprecation-contracts/README.md [new file with mode: 0644]
advancedcontentfilter/vendor/symfony/deprecation-contracts/composer.json [new file with mode: 0644]
advancedcontentfilter/vendor/symfony/deprecation-contracts/function.php [new file with mode: 0644]
advancedcontentfilter/vendor/symfony/polyfill-php73/LICENSE [new file with mode: 0644]
advancedcontentfilter/vendor/symfony/polyfill-php73/Php73.php [new file with mode: 0644]
advancedcontentfilter/vendor/symfony/polyfill-php73/README.md [new file with mode: 0644]
advancedcontentfilter/vendor/symfony/polyfill-php73/Resources/stubs/JsonException.php [new file with mode: 0644]
advancedcontentfilter/vendor/symfony/polyfill-php73/bootstrap.php [new file with mode: 0644]
advancedcontentfilter/vendor/symfony/polyfill-php73/composer.json [new file with mode: 0644]
advancedcontentfilter/vendor/symfony/polyfill-php80/LICENSE [new file with mode: 0644]
advancedcontentfilter/vendor/symfony/polyfill-php80/Php80.php [new file with mode: 0644]
advancedcontentfilter/vendor/symfony/polyfill-php80/PhpToken.php [new file with mode: 0644]
advancedcontentfilter/vendor/symfony/polyfill-php80/README.md [new file with mode: 0644]
advancedcontentfilter/vendor/symfony/polyfill-php80/Resources/stubs/Attribute.php [new file with mode: 0644]
advancedcontentfilter/vendor/symfony/polyfill-php80/Resources/stubs/PhpToken.php [new file with mode: 0644]
advancedcontentfilter/vendor/symfony/polyfill-php80/Resources/stubs/Stringable.php [new file with mode: 0644]
advancedcontentfilter/vendor/symfony/polyfill-php80/Resources/stubs/UnhandledMatchError.php [new file with mode: 0644]
advancedcontentfilter/vendor/symfony/polyfill-php80/Resources/stubs/ValueError.php [new file with mode: 0644]
advancedcontentfilter/vendor/symfony/polyfill-php80/bootstrap.php [new file with mode: 0644]
advancedcontentfilter/vendor/symfony/polyfill-php80/composer.json [new file with mode: 0644]
advancedcontentfilter/vendor/symfony/service-contracts/.gitignore [new file with mode: 0644]
advancedcontentfilter/vendor/symfony/service-contracts/Attribute/Required.php [new file with mode: 0644]
advancedcontentfilter/vendor/symfony/service-contracts/Attribute/SubscribedService.php [new file with mode: 0644]
advancedcontentfilter/vendor/symfony/service-contracts/CHANGELOG.md [new file with mode: 0644]
advancedcontentfilter/vendor/symfony/service-contracts/LICENSE [new file with mode: 0644]
advancedcontentfilter/vendor/symfony/service-contracts/README.md [new file with mode: 0644]
advancedcontentfilter/vendor/symfony/service-contracts/ResetInterface.php [new file with mode: 0644]
advancedcontentfilter/vendor/symfony/service-contracts/ServiceLocatorTrait.php [new file with mode: 0644]
advancedcontentfilter/vendor/symfony/service-contracts/ServiceProviderInterface.php [new file with mode: 0644]
advancedcontentfilter/vendor/symfony/service-contracts/ServiceSubscriberInterface.php [new file with mode: 0644]
advancedcontentfilter/vendor/symfony/service-contracts/ServiceSubscriberTrait.php [new file with mode: 0644]
advancedcontentfilter/vendor/symfony/service-contracts/Test/ServiceLocatorTest.php [new file with mode: 0644]
advancedcontentfilter/vendor/symfony/service-contracts/composer.json [new file with mode: 0644]
advancedcontentfilter/vendor/symfony/var-exporter/CHANGELOG.md [new file with mode: 0644]
advancedcontentfilter/vendor/symfony/var-exporter/Exception/ClassNotFoundException.php [new file with mode: 0644]
advancedcontentfilter/vendor/symfony/var-exporter/Exception/ExceptionInterface.php [new file with mode: 0644]
advancedcontentfilter/vendor/symfony/var-exporter/Exception/NotInstantiableTypeException.php [new file with mode: 0644]
advancedcontentfilter/vendor/symfony/var-exporter/Instantiator.php [new file with mode: 0644]
advancedcontentfilter/vendor/symfony/var-exporter/Internal/Exporter.php [new file with mode: 0644]
advancedcontentfilter/vendor/symfony/var-exporter/Internal/Hydrator.php [new file with mode: 0644]
advancedcontentfilter/vendor/symfony/var-exporter/Internal/Reference.php [new file with mode: 0644]
advancedcontentfilter/vendor/symfony/var-exporter/Internal/Registry.php [new file with mode: 0644]
advancedcontentfilter/vendor/symfony/var-exporter/Internal/Values.php [new file with mode: 0644]
advancedcontentfilter/vendor/symfony/var-exporter/LICENSE [new file with mode: 0644]
advancedcontentfilter/vendor/symfony/var-exporter/README.md [new file with mode: 0644]
advancedcontentfilter/vendor/symfony/var-exporter/VarExporter.php [new file with mode: 0644]
advancedcontentfilter/vendor/symfony/var-exporter/composer.json [new file with mode: 0644]

index 83d61074d8ccb7afd7aafc6b5221c1b9836fc826..6dbd17ba31d11e9825d55f9e841bd0ea2be6d481 100644 (file)
@@ -4,7 +4,7 @@
         "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
         "This file is @generated automatically"
     ],
-    "content-hash": "3e87f0369e4799fc35d98f399c67f1e9",
+    "content-hash": "a7276eb2d2108a26699f69c750d02d27",
     "packages": [
         {
             "name": "nikic/fast-route",
         },
         {
             "name": "psr/container",
-            "version": "2.0.2",
+            "version": "1.1.2",
             "source": {
                 "type": "git",
                 "url": "https://github.com/php-fig/container.git",
-                "reference": "c71ecc56dfe541dbd90c5360474fbc405f8d5963"
+                "reference": "513e0666f7216c7459170d56df27dfcefe1689ea"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/php-fig/container/zipball/c71ecc56dfe541dbd90c5360474fbc405f8d5963",
-                "reference": "c71ecc56dfe541dbd90c5360474fbc405f8d5963",
+                "url": "https://api.github.com/repos/php-fig/container/zipball/513e0666f7216c7459170d56df27dfcefe1689ea",
+                "reference": "513e0666f7216c7459170d56df27dfcefe1689ea",
                 "shasum": ""
             },
             "require": {
                 "php": ">=7.4.0"
             },
             "type": "library",
-            "extra": {
-                "branch-alias": {
-                    "dev-master": "2.0.x-dev"
-                }
-            },
             "autoload": {
                 "psr-4": {
                     "Psr\\Container\\": "src/"
                 "container-interop",
                 "psr"
             ],
-            "time": "2021-11-05T16:47:00+00:00"
+            "time": "2021-11-05T16:50:12+00:00"
         },
         {
             "name": "psr/http-factory",
         },
         {
             "name": "psr/http-message",
-            "version": "1.1",
+            "version": "2.0",
             "source": {
                 "type": "git",
                 "url": "https://github.com/php-fig/http-message.git",
-                "reference": "cb6ce4845ce34a8ad9e68117c10ee90a29919eba"
+                "reference": "402d35bcb92c70c026d1a6a9883f06b2ead23d71"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/php-fig/http-message/zipball/cb6ce4845ce34a8ad9e68117c10ee90a29919eba",
-                "reference": "cb6ce4845ce34a8ad9e68117c10ee90a29919eba",
+                "url": "https://api.github.com/repos/php-fig/http-message/zipball/402d35bcb92c70c026d1a6a9883f06b2ead23d71",
+                "reference": "402d35bcb92c70c026d1a6a9883f06b2ead23d71",
                 "shasum": ""
             },
             "require": {
             "type": "library",
             "extra": {
                 "branch-alias": {
-                    "dev-master": "1.1.x-dev"
+                    "dev-master": "2.0.x-dev"
                 }
             },
             "autoload": {
             "authors": [
                 {
                     "name": "PHP-FIG",
-                    "homepage": "http://www.php-fig.org/"
+                    "homepage": "https://www.php-fig.org/"
                 }
             ],
             "description": "Common interface for HTTP messages",
                 "request",
                 "response"
             ],
-            "time": "2023-04-04T09:50:52+00:00"
+            "time": "2023-04-04T09:54:51+00:00"
         },
         {
             "name": "psr/http-server-handler",
             ],
             "time": "2021-05-03T11:20:27+00:00"
         },
-        {
-            "name": "psr/simple-cache",
-            "version": "1.0.1",
-            "source": {
-                "type": "git",
-                "url": "https://github.com/php-fig/simple-cache.git",
-                "reference": "408d5eafb83c57f6365a3ca330ff23aa4a5fa39b"
-            },
-            "dist": {
-                "type": "zip",
-                "url": "https://api.github.com/repos/php-fig/simple-cache/zipball/408d5eafb83c57f6365a3ca330ff23aa4a5fa39b",
-                "reference": "408d5eafb83c57f6365a3ca330ff23aa4a5fa39b",
-                "shasum": ""
-            },
-            "require": {
-                "php": ">=5.3.0"
-            },
-            "type": "library",
-            "extra": {
-                "branch-alias": {
-                    "dev-master": "1.0.x-dev"
-                }
-            },
-            "autoload": {
-                "psr-4": {
-                    "Psr\\SimpleCache\\": "src/"
-                }
-            },
-            "notification-url": "https://packagist.org/downloads/",
-            "license": [
-                "MIT"
-            ],
-            "authors": [
-                {
-                    "name": "PHP-FIG",
-                    "homepage": "http://www.php-fig.org/"
-                }
-            ],
-            "description": "Common interfaces for simple caching",
-            "keywords": [
-                "cache",
-                "caching",
-                "psr",
-                "psr-16",
-                "simple-cache"
-            ],
-            "time": "2017-10-23T01:57:42+00:00"
-        },
         {
             "name": "slim/slim",
-            "version": "4.12.0",
+            "version": "4.13.0",
             "source": {
                 "type": "git",
                 "url": "https://github.com/slimphp/Slim.git",
-                "reference": "e9e99c2b24398b967841c6c4c3048622cc7e2b18"
+                "reference": "038fd5713d5a41636fdff0e8dcceedecdd17fc17"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/slimphp/Slim/zipball/e9e99c2b24398b967841c6c4c3048622cc7e2b18",
-                "reference": "e9e99c2b24398b967841c6c4c3048622cc7e2b18",
+                "url": "https://api.github.com/repos/slimphp/Slim/zipball/038fd5713d5a41636fdff0e8dcceedecdd17fc17",
+                "reference": "038fd5713d5a41636fdff0e8dcceedecdd17fc17",
                 "shasum": ""
             },
             "require": {
                 "php": "^7.4 || ^8.0",
                 "psr/container": "^1.0 || ^2.0",
                 "psr/http-factory": "^1.0",
-                "psr/http-message": "^1.1",
+                "psr/http-message": "^1.1 || ^2.0",
                 "psr/http-server-handler": "^1.0",
                 "psr/http-server-middleware": "^1.0",
                 "psr/log": "^1.1 || ^2.0 || ^3.0"
             "require-dev": {
                 "adriansuter/php-autoload-override": "^1.4",
                 "ext-simplexml": "*",
-                "guzzlehttp/psr7": "^2.5",
+                "guzzlehttp/psr7": "^2.6",
                 "httpsoft/http-message": "^1.1",
                 "httpsoft/http-server-request": "^1.1",
-                "laminas/laminas-diactoros": "^2.17",
+                "laminas/laminas-diactoros": "^2.17 || ^3",
                 "nyholm/psr7": "^1.8",
-                "nyholm/psr7-server": "^1.0",
-                "phpspec/prophecy": "^1.17",
-                "phpspec/prophecy-phpunit": "^2.0",
+                "nyholm/psr7-server": "^1.1",
+                "phpspec/prophecy": "^1.19",
+                "phpspec/prophecy-phpunit": "^2.1",
                 "phpstan/phpstan": "^1.10",
                 "phpunit/phpunit": "^9.6",
                 "slim/http": "^1.3",
                 "slim/psr7": "^1.6",
-                "squizlabs/php_codesniffer": "^3.7"
+                "squizlabs/php_codesniffer": "^3.9"
             },
             "suggest": {
                 "ext-simplexml": "Needed to support XML format in BodyParsingMiddleware",
                     "type": "tidelift"
                 }
             ],
-            "time": "2023-07-23T04:54:29+00:00"
+            "time": "2024-03-03T21:25:30+00:00"
         },
         {
             "name": "symfony/cache",
-            "version": "v3.4.47",
+            "version": "v4.4.48",
             "source": {
                 "type": "git",
                 "url": "https://github.com/symfony/cache.git",
-                "reference": "a7a14c4832760bd1fbd31be2859ffedc9b6ff813"
+                "reference": "3b98ed664887ad197b8ede3da2432787212eb915"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/symfony/cache/zipball/a7a14c4832760bd1fbd31be2859ffedc9b6ff813",
-                "reference": "a7a14c4832760bd1fbd31be2859ffedc9b6ff813",
+                "url": "https://api.github.com/repos/symfony/cache/zipball/3b98ed664887ad197b8ede3da2432787212eb915",
+                "reference": "3b98ed664887ad197b8ede3da2432787212eb915",
                 "shasum": ""
             },
             "require": {
-                "php": "^5.5.9|>=7.0.8",
-                "psr/cache": "~1.0",
-                "psr/log": "~1.0",
-                "psr/simple-cache": "^1.0",
-                "symfony/polyfill-apcu": "~1.1"
+                "php": ">=7.1.3",
+                "psr/cache": "^1.0|^2.0",
+                "psr/log": "^1|^2|^3",
+                "symfony/cache-contracts": "^1.1.7|^2",
+                "symfony/polyfill-php73": "^1.9",
+                "symfony/polyfill-php80": "^1.16",
+                "symfony/service-contracts": "^1.1|^2",
+                "symfony/var-exporter": "^4.2|^5.0"
             },
             "conflict": {
-                "symfony/var-dumper": "<3.3"
+                "doctrine/dbal": "<2.7",
+                "symfony/dependency-injection": "<3.4",
+                "symfony/http-kernel": "<4.4|>=5.0",
+                "symfony/var-dumper": "<4.4"
             },
             "provide": {
-                "psr/cache-implementation": "1.0",
-                "psr/simple-cache-implementation": "1.0"
+                "psr/cache-implementation": "1.0|2.0",
+                "psr/simple-cache-implementation": "1.0|2.0",
+                "symfony/cache-implementation": "1.0|2.0"
             },
             "require-dev": {
                 "cache/integration-tests": "dev-master",
-                "doctrine/cache": "^1.6",
-                "doctrine/dbal": "^2.4|^3.0",
-                "predis/predis": "^1.0"
+                "doctrine/cache": "^1.6|^2.0",
+                "doctrine/dbal": "^2.7|^3.0",
+                "predis/predis": "^1.1",
+                "psr/simple-cache": "^1.0|^2.0",
+                "symfony/config": "^4.2|^5.0",
+                "symfony/dependency-injection": "^3.4|^4.1|^5.0",
+                "symfony/filesystem": "^4.4|^5.0",
+                "symfony/http-kernel": "^4.4",
+                "symfony/var-dumper": "^4.4|^5.0"
             },
             "type": "library",
             "autoload": {
                     "homepage": "https://symfony.com/contributors"
                 }
             ],
-            "description": "Symfony Cache component with PSR-6, PSR-16, and tags",
+            "description": "Provides extended PSR-6, PSR-16 (and tags) implementations",
             "homepage": "https://symfony.com",
             "keywords": [
                 "caching",
                     "type": "tidelift"
                 }
             ],
-            "time": "2020-10-24T10:57:07+00:00"
+            "time": "2022-10-17T20:21:54+00:00"
+        },
+        {
+            "name": "symfony/cache-contracts",
+            "version": "v2.5.2",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/symfony/cache-contracts.git",
+                "reference": "64be4a7acb83b6f2bf6de9a02cee6dad41277ebc"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/symfony/cache-contracts/zipball/64be4a7acb83b6f2bf6de9a02cee6dad41277ebc",
+                "reference": "64be4a7acb83b6f2bf6de9a02cee6dad41277ebc",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=7.2.5",
+                "psr/cache": "^1.0|^2.0|^3.0"
+            },
+            "suggest": {
+                "symfony/cache-implementation": ""
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-main": "2.5-dev"
+                },
+                "thanks": {
+                    "name": "symfony/contracts",
+                    "url": "https://github.com/symfony/contracts"
+                }
+            },
+            "autoload": {
+                "psr-4": {
+                    "Symfony\\Contracts\\Cache\\": ""
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Nicolas Grekas",
+                    "email": "p@tchwork.com"
+                },
+                {
+                    "name": "Symfony Community",
+                    "homepage": "https://symfony.com/contributors"
+                }
+            ],
+            "description": "Generic abstractions related to caching",
+            "homepage": "https://symfony.com",
+            "keywords": [
+                "abstractions",
+                "contracts",
+                "decoupling",
+                "interfaces",
+                "interoperability",
+                "standards"
+            ],
+            "funding": [
+                {
+                    "url": "https://symfony.com/sponsor",
+                    "type": "custom"
+                },
+                {
+                    "url": "https://github.com/fabpot",
+                    "type": "github"
+                },
+                {
+                    "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
+                    "type": "tidelift"
+                }
+            ],
+            "time": "2022-01-02T09:53:40+00:00"
+        },
+        {
+            "name": "symfony/deprecation-contracts",
+            "version": "v2.5.2",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/symfony/deprecation-contracts.git",
+                "reference": "e8b495ea28c1d97b5e0c121748d6f9b53d075c66"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/e8b495ea28c1d97b5e0c121748d6f9b53d075c66",
+                "reference": "e8b495ea28c1d97b5e0c121748d6f9b53d075c66",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=7.1"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-main": "2.5-dev"
+                },
+                "thanks": {
+                    "name": "symfony/contracts",
+                    "url": "https://github.com/symfony/contracts"
+                }
+            },
+            "autoload": {
+                "files": [
+                    "function.php"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Nicolas Grekas",
+                    "email": "p@tchwork.com"
+                },
+                {
+                    "name": "Symfony Community",
+                    "homepage": "https://symfony.com/contributors"
+                }
+            ],
+            "description": "A generic function and convention to trigger deprecation notices",
+            "homepage": "https://symfony.com",
+            "funding": [
+                {
+                    "url": "https://symfony.com/sponsor",
+                    "type": "custom"
+                },
+                {
+                    "url": "https://github.com/fabpot",
+                    "type": "github"
+                },
+                {
+                    "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
+                    "type": "tidelift"
+                }
+            ],
+            "time": "2022-01-02T09:53:40+00:00"
         },
         {
             "name": "symfony/expression-language",
             "time": "2020-10-24T10:57:07+00:00"
         },
         {
-            "name": "symfony/polyfill-apcu",
-            "version": "v1.28.0",
+            "name": "symfony/polyfill-php70",
+            "version": "v1.20.0",
             "source": {
                 "type": "git",
-                "url": "https://github.com/symfony/polyfill-apcu.git",
-                "reference": "c6c2c0f5f4cb0b100c5dfea807ef5cd27bbe9899"
+                "url": "https://github.com/symfony/polyfill-php70.git",
+                "reference": "5f03a781d984aae42cebd18e7912fa80f02ee644"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/symfony/polyfill-apcu/zipball/c6c2c0f5f4cb0b100c5dfea807ef5cd27bbe9899",
-                "reference": "c6c2c0f5f4cb0b100c5dfea807ef5cd27bbe9899",
+                "url": "https://api.github.com/repos/symfony/polyfill-php70/zipball/5f03a781d984aae42cebd18e7912fa80f02ee644",
+                "reference": "5f03a781d984aae42cebd18e7912fa80f02ee644",
                 "shasum": ""
             },
             "require": {
                 "php": ">=7.1"
             },
-            "type": "library",
+            "type": "metapackage",
             "extra": {
                 "branch-alias": {
-                    "dev-main": "1.28-dev"
+                    "dev-main": "1.20-dev"
                 },
                 "thanks": {
                     "name": "symfony/polyfill",
                     "url": "https://github.com/symfony/polyfill"
                 }
             },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Nicolas Grekas",
+                    "email": "p@tchwork.com"
+                },
+                {
+                    "name": "Symfony Community",
+                    "homepage": "https://symfony.com/contributors"
+                }
+            ],
+            "description": "Symfony polyfill backporting some PHP 7.0+ features to lower PHP versions",
+            "homepage": "https://symfony.com",
+            "keywords": [
+                "compatibility",
+                "polyfill",
+                "portable",
+                "shim"
+            ],
+            "funding": [
+                {
+                    "url": "https://symfony.com/sponsor",
+                    "type": "custom"
+                },
+                {
+                    "url": "https://github.com/fabpot",
+                    "type": "github"
+                },
+                {
+                    "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
+                    "type": "tidelift"
+                }
+            ],
+            "time": "2020-10-23T14:02:19+00:00"
+        },
+        {
+            "name": "symfony/polyfill-php73",
+            "version": "v1.29.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/symfony/polyfill-php73.git",
+                "reference": "21bd091060673a1177ae842c0ef8fe30893114d2"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/symfony/polyfill-php73/zipball/21bd091060673a1177ae842c0ef8fe30893114d2",
+                "reference": "21bd091060673a1177ae842c0ef8fe30893114d2",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=7.1"
+            },
+            "type": "library",
+            "extra": {
+                "thanks": {
+                    "name": "symfony/polyfill",
+                    "url": "https://github.com/symfony/polyfill"
+                }
+            },
             "autoload": {
                 "files": [
                     "bootstrap.php"
                 ],
                 "psr-4": {
-                    "Symfony\\Polyfill\\Apcu\\": ""
-                }
+                    "Symfony\\Polyfill\\Php73\\": ""
+                },
+                "classmap": [
+                    "Resources/stubs"
+                ]
             },
             "notification-url": "https://packagist.org/downloads/",
             "license": [
                     "homepage": "https://symfony.com/contributors"
                 }
             ],
-            "description": "Symfony polyfill backporting apcu_* functions to lower PHP versions",
+            "description": "Symfony polyfill backporting some PHP 7.3+ features to lower PHP versions",
             "homepage": "https://symfony.com",
             "keywords": [
-                "apcu",
                 "compatibility",
                 "polyfill",
                 "portable",
                     "type": "tidelift"
                 }
             ],
-            "time": "2023-01-26T09:26:14+00:00"
+            "time": "2024-01-29T20:11:03+00:00"
         },
         {
-            "name": "symfony/polyfill-php70",
-            "version": "v1.20.0",
+            "name": "symfony/polyfill-php80",
+            "version": "v1.29.0",
             "source": {
                 "type": "git",
-                "url": "https://github.com/symfony/polyfill-php70.git",
-                "reference": "5f03a781d984aae42cebd18e7912fa80f02ee644"
+                "url": "https://github.com/symfony/polyfill-php80.git",
+                "reference": "87b68208d5c1188808dd7839ee1e6c8ec3b02f1b"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/symfony/polyfill-php70/zipball/5f03a781d984aae42cebd18e7912fa80f02ee644",
-                "reference": "5f03a781d984aae42cebd18e7912fa80f02ee644",
+                "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/87b68208d5c1188808dd7839ee1e6c8ec3b02f1b",
+                "reference": "87b68208d5c1188808dd7839ee1e6c8ec3b02f1b",
                 "shasum": ""
             },
             "require": {
                 "php": ">=7.1"
             },
-            "type": "metapackage",
+            "type": "library",
             "extra": {
-                "branch-alias": {
-                    "dev-main": "1.20-dev"
-                },
                 "thanks": {
                     "name": "symfony/polyfill",
                     "url": "https://github.com/symfony/polyfill"
                 }
             },
+            "autoload": {
+                "files": [
+                    "bootstrap.php"
+                ],
+                "psr-4": {
+                    "Symfony\\Polyfill\\Php80\\": ""
+                },
+                "classmap": [
+                    "Resources/stubs"
+                ]
+            },
             "notification-url": "https://packagist.org/downloads/",
             "license": [
                 "MIT"
             ],
             "authors": [
+                {
+                    "name": "Ion Bazan",
+                    "email": "ion.bazan@gmail.com"
+                },
                 {
                     "name": "Nicolas Grekas",
                     "email": "p@tchwork.com"
                     "homepage": "https://symfony.com/contributors"
                 }
             ],
-            "description": "Symfony polyfill backporting some PHP 7.0+ features to lower PHP versions",
+            "description": "Symfony polyfill backporting some PHP 8.0+ features to lower PHP versions",
             "homepage": "https://symfony.com",
             "keywords": [
                 "compatibility",
                     "type": "tidelift"
                 }
             ],
-            "time": "2020-10-23T14:02:19+00:00"
+            "time": "2024-01-29T20:11:03+00:00"
+        },
+        {
+            "name": "symfony/service-contracts",
+            "version": "v2.5.2",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/symfony/service-contracts.git",
+                "reference": "4b426aac47d6427cc1a1d0f7e2ac724627f5966c"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/symfony/service-contracts/zipball/4b426aac47d6427cc1a1d0f7e2ac724627f5966c",
+                "reference": "4b426aac47d6427cc1a1d0f7e2ac724627f5966c",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=7.2.5",
+                "psr/container": "^1.1",
+                "symfony/deprecation-contracts": "^2.1|^3"
+            },
+            "conflict": {
+                "ext-psr": "<1.1|>=2"
+            },
+            "suggest": {
+                "symfony/service-implementation": ""
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-main": "2.5-dev"
+                },
+                "thanks": {
+                    "name": "symfony/contracts",
+                    "url": "https://github.com/symfony/contracts"
+                }
+            },
+            "autoload": {
+                "psr-4": {
+                    "Symfony\\Contracts\\Service\\": ""
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Nicolas Grekas",
+                    "email": "p@tchwork.com"
+                },
+                {
+                    "name": "Symfony Community",
+                    "homepage": "https://symfony.com/contributors"
+                }
+            ],
+            "description": "Generic abstractions related to writing services",
+            "homepage": "https://symfony.com",
+            "keywords": [
+                "abstractions",
+                "contracts",
+                "decoupling",
+                "interfaces",
+                "interoperability",
+                "standards"
+            ],
+            "funding": [
+                {
+                    "url": "https://symfony.com/sponsor",
+                    "type": "custom"
+                },
+                {
+                    "url": "https://github.com/fabpot",
+                    "type": "github"
+                },
+                {
+                    "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
+                    "type": "tidelift"
+                }
+            ],
+            "time": "2022-05-30T19:17:29+00:00"
+        },
+        {
+            "name": "symfony/var-exporter",
+            "version": "v5.4.35",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/symfony/var-exporter.git",
+                "reference": "abb0a151b62d6b07e816487e20040464af96cae7"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/symfony/var-exporter/zipball/abb0a151b62d6b07e816487e20040464af96cae7",
+                "reference": "abb0a151b62d6b07e816487e20040464af96cae7",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=7.2.5",
+                "symfony/polyfill-php80": "^1.16"
+            },
+            "require-dev": {
+                "symfony/var-dumper": "^4.4.9|^5.0.9|^6.0"
+            },
+            "type": "library",
+            "autoload": {
+                "psr-4": {
+                    "Symfony\\Component\\VarExporter\\": ""
+                },
+                "exclude-from-classmap": [
+                    "/Tests/"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Nicolas Grekas",
+                    "email": "p@tchwork.com"
+                },
+                {
+                    "name": "Symfony Community",
+                    "homepage": "https://symfony.com/contributors"
+                }
+            ],
+            "description": "Allows exporting any serializable PHP data structure to plain PHP code",
+            "homepage": "https://symfony.com",
+            "keywords": [
+                "clone",
+                "construct",
+                "export",
+                "hydrate",
+                "instantiate",
+                "serialize"
+            ],
+            "funding": [
+                {
+                    "url": "https://symfony.com/sponsor",
+                    "type": "custom"
+                },
+                {
+                    "url": "https://github.com/fabpot",
+                    "type": "github"
+                },
+                {
+                    "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
+                    "type": "tidelift"
+                }
+            ],
+            "time": "2024-01-23T13:51:25+00:00"
         }
     ],
     "packages-dev": [],
     "stability-flags": [],
     "prefer-stable": false,
     "prefer-lowest": false,
-    "platform": {
-        "php": ">=5.6.0"
-    },
+    "platform": [],
     "platform-dev": [],
+    "platform-overrides": {
+        "php": "7.4"
+    },
     "plugin-api-version": "1.1.0"
 }
index aa3de8a37436a1a47be8df2cc9aac2f9cb10f565..9f79be5c0a20815ea52300e3b13661fe55dfd914 100644 (file)
@@ -6,6 +6,7 @@ $vendorDir = dirname(dirname(__FILE__));
 $baseDir = dirname($vendorDir);
 
 return array(
+    'Attribute' => $vendorDir . '/symfony/polyfill-php80/Resources/stubs/Attribute.php',
     'FastRoute\\BadRouteException' => $vendorDir . '/nikic/fast-route/src/BadRouteException.php',
     'FastRoute\\DataGenerator' => $vendorDir . '/nikic/fast-route/src/DataGenerator.php',
     'FastRoute\\DataGenerator\\CharCountBased' => $vendorDir . '/nikic/fast-route/src/DataGenerator/CharCountBased.php',
@@ -23,6 +24,8 @@ return array(
     'FastRoute\\RouteCollector' => $vendorDir . '/nikic/fast-route/src/RouteCollector.php',
     'FastRoute\\RouteParser' => $vendorDir . '/nikic/fast-route/src/RouteParser.php',
     'FastRoute\\RouteParser\\Std' => $vendorDir . '/nikic/fast-route/src/RouteParser/Std.php',
+    'JsonException' => $vendorDir . '/symfony/polyfill-php73/Resources/stubs/JsonException.php',
+    'PhpToken' => $vendorDir . '/symfony/polyfill-php80/Resources/stubs/PhpToken.php',
     'Psr\\Cache\\CacheException' => $vendorDir . '/psr/cache/src/CacheException.php',
     'Psr\\Cache\\CacheItemInterface' => $vendorDir . '/psr/cache/src/CacheItemInterface.php',
     'Psr\\Cache\\CacheItemPoolInterface' => $vendorDir . '/psr/cache/src/CacheItemPoolInterface.php',
@@ -56,9 +59,6 @@ return array(
     'Psr\\Log\\Test\\DummyTest' => $vendorDir . '/psr/log/Psr/Log/Test/DummyTest.php',
     'Psr\\Log\\Test\\LoggerInterfaceTest' => $vendorDir . '/psr/log/Psr/Log/Test/LoggerInterfaceTest.php',
     'Psr\\Log\\Test\\TestLogger' => $vendorDir . '/psr/log/Psr/Log/Test/TestLogger.php',
-    'Psr\\SimpleCache\\CacheException' => $vendorDir . '/psr/simple-cache/src/CacheException.php',
-    'Psr\\SimpleCache\\CacheInterface' => $vendorDir . '/psr/simple-cache/src/CacheInterface.php',
-    'Psr\\SimpleCache\\InvalidArgumentException' => $vendorDir . '/psr/simple-cache/src/InvalidArgumentException.php',
     'Slim\\App' => $vendorDir . '/slim/slim/Slim/App.php',
     'Slim\\CallableResolver' => $vendorDir . '/slim/slim/Slim/CallableResolver.php',
     'Slim\\Error\\AbstractErrorRenderer' => $vendorDir . '/slim/slim/Slim/Error/AbstractErrorRenderer.php',
@@ -75,6 +75,7 @@ return array(
     'Slim\\Exception\\HttpNotFoundException' => $vendorDir . '/slim/slim/Slim/Exception/HttpNotFoundException.php',
     'Slim\\Exception\\HttpNotImplementedException' => $vendorDir . '/slim/slim/Slim/Exception/HttpNotImplementedException.php',
     'Slim\\Exception\\HttpSpecializedException' => $vendorDir . '/slim/slim/Slim/Exception/HttpSpecializedException.php',
+    'Slim\\Exception\\HttpTooManyRequestsException' => $vendorDir . '/slim/slim/Slim/Exception/HttpTooManyRequestsException.php',
     'Slim\\Exception\\HttpUnauthorizedException' => $vendorDir . '/slim/slim/Slim/Exception/HttpUnauthorizedException.php',
     'Slim\\Factory\\AppFactory' => $vendorDir . '/slim/slim/Slim/Factory/AppFactory.php',
     'Slim\\Factory\\Psr17\\GuzzlePsr17Factory' => $vendorDir . '/slim/slim/Slim/Factory/Psr17/GuzzlePsr17Factory.php',
@@ -130,20 +131,25 @@ return array(
     'Slim\\Routing\\RouteResolver' => $vendorDir . '/slim/slim/Slim/Routing/RouteResolver.php',
     'Slim\\Routing\\RouteRunner' => $vendorDir . '/slim/slim/Slim/Routing/RouteRunner.php',
     'Slim\\Routing\\RoutingResults' => $vendorDir . '/slim/slim/Slim/Routing/RoutingResults.php',
+    'Stringable' => $vendorDir . '/symfony/polyfill-php80/Resources/stubs/Stringable.php',
     'Symfony\\Component\\Cache\\Adapter\\AbstractAdapter' => $vendorDir . '/symfony/cache/Adapter/AbstractAdapter.php',
+    'Symfony\\Component\\Cache\\Adapter\\AbstractTagAwareAdapter' => $vendorDir . '/symfony/cache/Adapter/AbstractTagAwareAdapter.php',
     'Symfony\\Component\\Cache\\Adapter\\AdapterInterface' => $vendorDir . '/symfony/cache/Adapter/AdapterInterface.php',
     'Symfony\\Component\\Cache\\Adapter\\ApcuAdapter' => $vendorDir . '/symfony/cache/Adapter/ApcuAdapter.php',
     'Symfony\\Component\\Cache\\Adapter\\ArrayAdapter' => $vendorDir . '/symfony/cache/Adapter/ArrayAdapter.php',
     'Symfony\\Component\\Cache\\Adapter\\ChainAdapter' => $vendorDir . '/symfony/cache/Adapter/ChainAdapter.php',
     'Symfony\\Component\\Cache\\Adapter\\DoctrineAdapter' => $vendorDir . '/symfony/cache/Adapter/DoctrineAdapter.php',
     'Symfony\\Component\\Cache\\Adapter\\FilesystemAdapter' => $vendorDir . '/symfony/cache/Adapter/FilesystemAdapter.php',
+    'Symfony\\Component\\Cache\\Adapter\\FilesystemTagAwareAdapter' => $vendorDir . '/symfony/cache/Adapter/FilesystemTagAwareAdapter.php',
     'Symfony\\Component\\Cache\\Adapter\\MemcachedAdapter' => $vendorDir . '/symfony/cache/Adapter/MemcachedAdapter.php',
     'Symfony\\Component\\Cache\\Adapter\\NullAdapter' => $vendorDir . '/symfony/cache/Adapter/NullAdapter.php',
     'Symfony\\Component\\Cache\\Adapter\\PdoAdapter' => $vendorDir . '/symfony/cache/Adapter/PdoAdapter.php',
     'Symfony\\Component\\Cache\\Adapter\\PhpArrayAdapter' => $vendorDir . '/symfony/cache/Adapter/PhpArrayAdapter.php',
     'Symfony\\Component\\Cache\\Adapter\\PhpFilesAdapter' => $vendorDir . '/symfony/cache/Adapter/PhpFilesAdapter.php',
     'Symfony\\Component\\Cache\\Adapter\\ProxyAdapter' => $vendorDir . '/symfony/cache/Adapter/ProxyAdapter.php',
+    'Symfony\\Component\\Cache\\Adapter\\Psr16Adapter' => $vendorDir . '/symfony/cache/Adapter/Psr16Adapter.php',
     'Symfony\\Component\\Cache\\Adapter\\RedisAdapter' => $vendorDir . '/symfony/cache/Adapter/RedisAdapter.php',
+    'Symfony\\Component\\Cache\\Adapter\\RedisTagAwareAdapter' => $vendorDir . '/symfony/cache/Adapter/RedisTagAwareAdapter.php',
     'Symfony\\Component\\Cache\\Adapter\\SimpleCacheAdapter' => $vendorDir . '/symfony/cache/Adapter/SimpleCacheAdapter.php',
     'Symfony\\Component\\Cache\\Adapter\\TagAwareAdapter' => $vendorDir . '/symfony/cache/Adapter/TagAwareAdapter.php',
     'Symfony\\Component\\Cache\\Adapter\\TagAwareAdapterInterface' => $vendorDir . '/symfony/cache/Adapter/TagAwareAdapterInterface.php',
@@ -152,10 +158,21 @@ return array(
     'Symfony\\Component\\Cache\\Adapter\\TraceableTagAwareAdapter' => $vendorDir . '/symfony/cache/Adapter/TraceableTagAwareAdapter.php',
     'Symfony\\Component\\Cache\\CacheItem' => $vendorDir . '/symfony/cache/CacheItem.php',
     'Symfony\\Component\\Cache\\DataCollector\\CacheDataCollector' => $vendorDir . '/symfony/cache/DataCollector/CacheDataCollector.php',
+    'Symfony\\Component\\Cache\\DependencyInjection\\CacheCollectorPass' => $vendorDir . '/symfony/cache/DependencyInjection/CacheCollectorPass.php',
+    'Symfony\\Component\\Cache\\DependencyInjection\\CachePoolClearerPass' => $vendorDir . '/symfony/cache/DependencyInjection/CachePoolClearerPass.php',
+    'Symfony\\Component\\Cache\\DependencyInjection\\CachePoolPass' => $vendorDir . '/symfony/cache/DependencyInjection/CachePoolPass.php',
+    'Symfony\\Component\\Cache\\DependencyInjection\\CachePoolPrunerPass' => $vendorDir . '/symfony/cache/DependencyInjection/CachePoolPrunerPass.php',
     'Symfony\\Component\\Cache\\DoctrineProvider' => $vendorDir . '/symfony/cache/DoctrineProvider.php',
     'Symfony\\Component\\Cache\\Exception\\CacheException' => $vendorDir . '/symfony/cache/Exception/CacheException.php',
     'Symfony\\Component\\Cache\\Exception\\InvalidArgumentException' => $vendorDir . '/symfony/cache/Exception/InvalidArgumentException.php',
+    'Symfony\\Component\\Cache\\Exception\\LogicException' => $vendorDir . '/symfony/cache/Exception/LogicException.php',
+    'Symfony\\Component\\Cache\\LockRegistry' => $vendorDir . '/symfony/cache/LockRegistry.php',
+    'Symfony\\Component\\Cache\\Marshaller\\DefaultMarshaller' => $vendorDir . '/symfony/cache/Marshaller/DefaultMarshaller.php',
+    'Symfony\\Component\\Cache\\Marshaller\\DeflateMarshaller' => $vendorDir . '/symfony/cache/Marshaller/DeflateMarshaller.php',
+    'Symfony\\Component\\Cache\\Marshaller\\MarshallerInterface' => $vendorDir . '/symfony/cache/Marshaller/MarshallerInterface.php',
+    'Symfony\\Component\\Cache\\Marshaller\\TagAwareMarshaller' => $vendorDir . '/symfony/cache/Marshaller/TagAwareMarshaller.php',
     'Symfony\\Component\\Cache\\PruneableInterface' => $vendorDir . '/symfony/cache/PruneableInterface.php',
+    'Symfony\\Component\\Cache\\Psr16Cache' => $vendorDir . '/symfony/cache/Psr16Cache.php',
     'Symfony\\Component\\Cache\\ResettableInterface' => $vendorDir . '/symfony/cache/ResettableInterface.php',
     'Symfony\\Component\\Cache\\Simple\\AbstractCache' => $vendorDir . '/symfony/cache/Simple/AbstractCache.php',
     'Symfony\\Component\\Cache\\Simple\\ApcuCache' => $vendorDir . '/symfony/cache/Simple/ApcuCache.php',
@@ -172,17 +189,22 @@ return array(
     'Symfony\\Component\\Cache\\Simple\\RedisCache' => $vendorDir . '/symfony/cache/Simple/RedisCache.php',
     'Symfony\\Component\\Cache\\Simple\\TraceableCache' => $vendorDir . '/symfony/cache/Simple/TraceableCache.php',
     'Symfony\\Component\\Cache\\Simple\\TraceableCacheEvent' => $vendorDir . '/symfony/cache/Simple/TraceableCache.php',
+    'Symfony\\Component\\Cache\\Traits\\AbstractAdapterTrait' => $vendorDir . '/symfony/cache/Traits/AbstractAdapterTrait.php',
     'Symfony\\Component\\Cache\\Traits\\AbstractTrait' => $vendorDir . '/symfony/cache/Traits/AbstractTrait.php',
     'Symfony\\Component\\Cache\\Traits\\ApcuTrait' => $vendorDir . '/symfony/cache/Traits/ApcuTrait.php',
     'Symfony\\Component\\Cache\\Traits\\ArrayTrait' => $vendorDir . '/symfony/cache/Traits/ArrayTrait.php',
+    'Symfony\\Component\\Cache\\Traits\\ContractsTrait' => $vendorDir . '/symfony/cache/Traits/ContractsTrait.php',
     'Symfony\\Component\\Cache\\Traits\\DoctrineTrait' => $vendorDir . '/symfony/cache/Traits/DoctrineTrait.php',
     'Symfony\\Component\\Cache\\Traits\\FilesystemCommonTrait' => $vendorDir . '/symfony/cache/Traits/FilesystemCommonTrait.php',
     'Symfony\\Component\\Cache\\Traits\\FilesystemTrait' => $vendorDir . '/symfony/cache/Traits/FilesystemTrait.php',
+    'Symfony\\Component\\Cache\\Traits\\LazyValue' => $vendorDir . '/symfony/cache/Traits/PhpFilesTrait.php',
     'Symfony\\Component\\Cache\\Traits\\MemcachedTrait' => $vendorDir . '/symfony/cache/Traits/MemcachedTrait.php',
     'Symfony\\Component\\Cache\\Traits\\PdoTrait' => $vendorDir . '/symfony/cache/Traits/PdoTrait.php',
     'Symfony\\Component\\Cache\\Traits\\PhpArrayTrait' => $vendorDir . '/symfony/cache/Traits/PhpArrayTrait.php',
     'Symfony\\Component\\Cache\\Traits\\PhpFilesTrait' => $vendorDir . '/symfony/cache/Traits/PhpFilesTrait.php',
     'Symfony\\Component\\Cache\\Traits\\ProxyTrait' => $vendorDir . '/symfony/cache/Traits/ProxyTrait.php',
+    'Symfony\\Component\\Cache\\Traits\\RedisClusterNodeProxy' => $vendorDir . '/symfony/cache/Traits/RedisClusterNodeProxy.php',
+    'Symfony\\Component\\Cache\\Traits\\RedisClusterProxy' => $vendorDir . '/symfony/cache/Traits/RedisClusterProxy.php',
     'Symfony\\Component\\Cache\\Traits\\RedisProxy' => $vendorDir . '/symfony/cache/Traits/RedisProxy.php',
     'Symfony\\Component\\Cache\\Traits\\RedisTrait' => $vendorDir . '/symfony/cache/Traits/RedisTrait.php',
     'Symfony\\Component\\ExpressionLanguage\\Compiler' => $vendorDir . '/symfony/expression-language/Compiler.php',
@@ -210,5 +232,32 @@ return array(
     'Symfony\\Component\\ExpressionLanguage\\SyntaxError' => $vendorDir . '/symfony/expression-language/SyntaxError.php',
     'Symfony\\Component\\ExpressionLanguage\\Token' => $vendorDir . '/symfony/expression-language/Token.php',
     'Symfony\\Component\\ExpressionLanguage\\TokenStream' => $vendorDir . '/symfony/expression-language/TokenStream.php',
-    'Symfony\\Polyfill\\Apcu\\Apcu' => $vendorDir . '/symfony/polyfill-apcu/Apcu.php',
+    'Symfony\\Component\\VarExporter\\Exception\\ClassNotFoundException' => $vendorDir . '/symfony/var-exporter/Exception/ClassNotFoundException.php',
+    'Symfony\\Component\\VarExporter\\Exception\\ExceptionInterface' => $vendorDir . '/symfony/var-exporter/Exception/ExceptionInterface.php',
+    'Symfony\\Component\\VarExporter\\Exception\\NotInstantiableTypeException' => $vendorDir . '/symfony/var-exporter/Exception/NotInstantiableTypeException.php',
+    'Symfony\\Component\\VarExporter\\Instantiator' => $vendorDir . '/symfony/var-exporter/Instantiator.php',
+    'Symfony\\Component\\VarExporter\\Internal\\Exporter' => $vendorDir . '/symfony/var-exporter/Internal/Exporter.php',
+    'Symfony\\Component\\VarExporter\\Internal\\Hydrator' => $vendorDir . '/symfony/var-exporter/Internal/Hydrator.php',
+    'Symfony\\Component\\VarExporter\\Internal\\Reference' => $vendorDir . '/symfony/var-exporter/Internal/Reference.php',
+    'Symfony\\Component\\VarExporter\\Internal\\Registry' => $vendorDir . '/symfony/var-exporter/Internal/Registry.php',
+    'Symfony\\Component\\VarExporter\\Internal\\Values' => $vendorDir . '/symfony/var-exporter/Internal/Values.php',
+    'Symfony\\Component\\VarExporter\\VarExporter' => $vendorDir . '/symfony/var-exporter/VarExporter.php',
+    'Symfony\\Contracts\\Cache\\CacheInterface' => $vendorDir . '/symfony/cache-contracts/CacheInterface.php',
+    'Symfony\\Contracts\\Cache\\CacheTrait' => $vendorDir . '/symfony/cache-contracts/CacheTrait.php',
+    'Symfony\\Contracts\\Cache\\CallbackInterface' => $vendorDir . '/symfony/cache-contracts/CallbackInterface.php',
+    'Symfony\\Contracts\\Cache\\ItemInterface' => $vendorDir . '/symfony/cache-contracts/ItemInterface.php',
+    'Symfony\\Contracts\\Cache\\TagAwareCacheInterface' => $vendorDir . '/symfony/cache-contracts/TagAwareCacheInterface.php',
+    'Symfony\\Contracts\\Service\\Attribute\\Required' => $vendorDir . '/symfony/service-contracts/Attribute/Required.php',
+    'Symfony\\Contracts\\Service\\Attribute\\SubscribedService' => $vendorDir . '/symfony/service-contracts/Attribute/SubscribedService.php',
+    'Symfony\\Contracts\\Service\\ResetInterface' => $vendorDir . '/symfony/service-contracts/ResetInterface.php',
+    'Symfony\\Contracts\\Service\\ServiceLocatorTrait' => $vendorDir . '/symfony/service-contracts/ServiceLocatorTrait.php',
+    'Symfony\\Contracts\\Service\\ServiceProviderInterface' => $vendorDir . '/symfony/service-contracts/ServiceProviderInterface.php',
+    'Symfony\\Contracts\\Service\\ServiceSubscriberInterface' => $vendorDir . '/symfony/service-contracts/ServiceSubscriberInterface.php',
+    'Symfony\\Contracts\\Service\\ServiceSubscriberTrait' => $vendorDir . '/symfony/service-contracts/ServiceSubscriberTrait.php',
+    'Symfony\\Contracts\\Service\\Test\\ServiceLocatorTest' => $vendorDir . '/symfony/service-contracts/Test/ServiceLocatorTest.php',
+    'Symfony\\Polyfill\\Php73\\Php73' => $vendorDir . '/symfony/polyfill-php73/Php73.php',
+    'Symfony\\Polyfill\\Php80\\Php80' => $vendorDir . '/symfony/polyfill-php80/Php80.php',
+    'Symfony\\Polyfill\\Php80\\PhpToken' => $vendorDir . '/symfony/polyfill-php80/PhpToken.php',
+    'UnhandledMatchError' => $vendorDir . '/symfony/polyfill-php80/Resources/stubs/UnhandledMatchError.php',
+    'ValueError' => $vendorDir . '/symfony/polyfill-php80/Resources/stubs/ValueError.php',
 );
index a6b8b352150ffe9083433b53214f49673c250f6a..a5d3b9642f5d91918de2959f20de56c4a1236a29 100644 (file)
@@ -6,6 +6,8 @@ $vendorDir = dirname(dirname(__FILE__));
 $baseDir = dirname($vendorDir);
 
 return array(
-    '32dcc8afd4335739640db7d200c1971d' => $vendorDir . '/symfony/polyfill-apcu/bootstrap.php',
+    'a4a119a56e50fbb293281d9a48007e0e' => $vendorDir . '/symfony/polyfill-php80/bootstrap.php',
+    '6e3fae29631ef280660b3cdad06f25a8' => $vendorDir . '/symfony/deprecation-contracts/function.php',
+    '0d59ee240a4cd96ddbb4ff164fccea4d' => $vendorDir . '/symfony/polyfill-php73/bootstrap.php',
     '253c157292f75eb38082b5acb06f3f01' => $vendorDir . '/nikic/fast-route/src/functions.php',
 );
index 876065857011c3a05324b374b5c4331ad8fbae59..3d716d5627629aa8ef2a6a81521098d0dfb4709a 100644 (file)
@@ -6,11 +6,14 @@ $vendorDir = dirname(dirname(__FILE__));
 $baseDir = dirname($vendorDir);
 
 return array(
-    'Symfony\\Polyfill\\Apcu\\' => array($vendorDir . '/symfony/polyfill-apcu'),
+    'Symfony\\Polyfill\\Php80\\' => array($vendorDir . '/symfony/polyfill-php80'),
+    'Symfony\\Polyfill\\Php73\\' => array($vendorDir . '/symfony/polyfill-php73'),
+    'Symfony\\Contracts\\Service\\' => array($vendorDir . '/symfony/service-contracts'),
+    'Symfony\\Contracts\\Cache\\' => array($vendorDir . '/symfony/cache-contracts'),
+    'Symfony\\Component\\VarExporter\\' => array($vendorDir . '/symfony/var-exporter'),
     'Symfony\\Component\\ExpressionLanguage\\' => array($vendorDir . '/symfony/expression-language'),
     'Symfony\\Component\\Cache\\' => array($vendorDir . '/symfony/cache'),
     'Slim\\' => array($vendorDir . '/slim/slim/Slim'),
-    'Psr\\SimpleCache\\' => array($vendorDir . '/psr/simple-cache/src'),
     'Psr\\Log\\' => array($vendorDir . '/psr/log/Psr/Log'),
     'Psr\\Http\\Server\\' => array($vendorDir . '/psr/http-server-handler/src', $vendorDir . '/psr/http-server-middleware/src'),
     'Psr\\Http\\Message\\' => array($vendorDir . '/psr/http-factory/src', $vendorDir . '/psr/http-message/src'),
index 917d3d90a8c38319d216f627f0dd5f1bbb187e12..57172a1a331a12ad66b0015562a6e56b3587cc98 100644 (file)
@@ -7,21 +7,26 @@ namespace Composer\Autoload;
 class ComposerStaticInitAdvancedContentFilterAddon
 {
     public static $files = array (
-        '32dcc8afd4335739640db7d200c1971d' => __DIR__ . '/..' . '/symfony/polyfill-apcu/bootstrap.php',
+        'a4a119a56e50fbb293281d9a48007e0e' => __DIR__ . '/..' . '/symfony/polyfill-php80/bootstrap.php',
+        '6e3fae29631ef280660b3cdad06f25a8' => __DIR__ . '/..' . '/symfony/deprecation-contracts/function.php',
+        '0d59ee240a4cd96ddbb4ff164fccea4d' => __DIR__ . '/..' . '/symfony/polyfill-php73/bootstrap.php',
         '253c157292f75eb38082b5acb06f3f01' => __DIR__ . '/..' . '/nikic/fast-route/src/functions.php',
     );
 
     public static $prefixLengthsPsr4 = array (
         'S' => 
         array (
-            'Symfony\\Polyfill\\Apcu\\' => 22,
+            'Symfony\\Polyfill\\Php80\\' => 23,
+            'Symfony\\Polyfill\\Php73\\' => 23,
+            'Symfony\\Contracts\\Service\\' => 26,
+            'Symfony\\Contracts\\Cache\\' => 24,
+            'Symfony\\Component\\VarExporter\\' => 30,
             'Symfony\\Component\\ExpressionLanguage\\' => 37,
             'Symfony\\Component\\Cache\\' => 24,
             'Slim\\' => 5,
         ),
         'P' => 
         array (
-            'Psr\\SimpleCache\\' => 16,
             'Psr\\Log\\' => 8,
             'Psr\\Http\\Server\\' => 16,
             'Psr\\Http\\Message\\' => 17,
@@ -35,9 +40,25 @@ class ComposerStaticInitAdvancedContentFilterAddon
     );
 
     public static $prefixDirsPsr4 = array (
-        'Symfony\\Polyfill\\Apcu\\' => 
+        'Symfony\\Polyfill\\Php80\\' => 
         array (
-            0 => __DIR__ . '/..' . '/symfony/polyfill-apcu',
+            0 => __DIR__ . '/..' . '/symfony/polyfill-php80',
+        ),
+        'Symfony\\Polyfill\\Php73\\' => 
+        array (
+            0 => __DIR__ . '/..' . '/symfony/polyfill-php73',
+        ),
+        'Symfony\\Contracts\\Service\\' => 
+        array (
+            0 => __DIR__ . '/..' . '/symfony/service-contracts',
+        ),
+        'Symfony\\Contracts\\Cache\\' => 
+        array (
+            0 => __DIR__ . '/..' . '/symfony/cache-contracts',
+        ),
+        'Symfony\\Component\\VarExporter\\' => 
+        array (
+            0 => __DIR__ . '/..' . '/symfony/var-exporter',
         ),
         'Symfony\\Component\\ExpressionLanguage\\' => 
         array (
@@ -51,10 +72,6 @@ class ComposerStaticInitAdvancedContentFilterAddon
         array (
             0 => __DIR__ . '/..' . '/slim/slim/Slim',
         ),
-        'Psr\\SimpleCache\\' => 
-        array (
-            0 => __DIR__ . '/..' . '/psr/simple-cache/src',
-        ),
         'Psr\\Log\\' => 
         array (
             0 => __DIR__ . '/..' . '/psr/log/Psr/Log',
@@ -84,6 +101,7 @@ class ComposerStaticInitAdvancedContentFilterAddon
     );
 
     public static $classMap = array (
+        'Attribute' => __DIR__ . '/..' . '/symfony/polyfill-php80/Resources/stubs/Attribute.php',
         'FastRoute\\BadRouteException' => __DIR__ . '/..' . '/nikic/fast-route/src/BadRouteException.php',
         'FastRoute\\DataGenerator' => __DIR__ . '/..' . '/nikic/fast-route/src/DataGenerator.php',
         'FastRoute\\DataGenerator\\CharCountBased' => __DIR__ . '/..' . '/nikic/fast-route/src/DataGenerator/CharCountBased.php',
@@ -101,6 +119,8 @@ class ComposerStaticInitAdvancedContentFilterAddon
         'FastRoute\\RouteCollector' => __DIR__ . '/..' . '/nikic/fast-route/src/RouteCollector.php',
         'FastRoute\\RouteParser' => __DIR__ . '/..' . '/nikic/fast-route/src/RouteParser.php',
         'FastRoute\\RouteParser\\Std' => __DIR__ . '/..' . '/nikic/fast-route/src/RouteParser/Std.php',
+        'JsonException' => __DIR__ . '/..' . '/symfony/polyfill-php73/Resources/stubs/JsonException.php',
+        'PhpToken' => __DIR__ . '/..' . '/symfony/polyfill-php80/Resources/stubs/PhpToken.php',
         'Psr\\Cache\\CacheException' => __DIR__ . '/..' . '/psr/cache/src/CacheException.php',
         'Psr\\Cache\\CacheItemInterface' => __DIR__ . '/..' . '/psr/cache/src/CacheItemInterface.php',
         'Psr\\Cache\\CacheItemPoolInterface' => __DIR__ . '/..' . '/psr/cache/src/CacheItemPoolInterface.php',
@@ -134,9 +154,6 @@ class ComposerStaticInitAdvancedContentFilterAddon
         'Psr\\Log\\Test\\DummyTest' => __DIR__ . '/..' . '/psr/log/Psr/Log/Test/DummyTest.php',
         'Psr\\Log\\Test\\LoggerInterfaceTest' => __DIR__ . '/..' . '/psr/log/Psr/Log/Test/LoggerInterfaceTest.php',
         'Psr\\Log\\Test\\TestLogger' => __DIR__ . '/..' . '/psr/log/Psr/Log/Test/TestLogger.php',
-        'Psr\\SimpleCache\\CacheException' => __DIR__ . '/..' . '/psr/simple-cache/src/CacheException.php',
-        'Psr\\SimpleCache\\CacheInterface' => __DIR__ . '/..' . '/psr/simple-cache/src/CacheInterface.php',
-        'Psr\\SimpleCache\\InvalidArgumentException' => __DIR__ . '/..' . '/psr/simple-cache/src/InvalidArgumentException.php',
         'Slim\\App' => __DIR__ . '/..' . '/slim/slim/Slim/App.php',
         'Slim\\CallableResolver' => __DIR__ . '/..' . '/slim/slim/Slim/CallableResolver.php',
         'Slim\\Error\\AbstractErrorRenderer' => __DIR__ . '/..' . '/slim/slim/Slim/Error/AbstractErrorRenderer.php',
@@ -153,6 +170,7 @@ class ComposerStaticInitAdvancedContentFilterAddon
         'Slim\\Exception\\HttpNotFoundException' => __DIR__ . '/..' . '/slim/slim/Slim/Exception/HttpNotFoundException.php',
         'Slim\\Exception\\HttpNotImplementedException' => __DIR__ . '/..' . '/slim/slim/Slim/Exception/HttpNotImplementedException.php',
         'Slim\\Exception\\HttpSpecializedException' => __DIR__ . '/..' . '/slim/slim/Slim/Exception/HttpSpecializedException.php',
+        'Slim\\Exception\\HttpTooManyRequestsException' => __DIR__ . '/..' . '/slim/slim/Slim/Exception/HttpTooManyRequestsException.php',
         'Slim\\Exception\\HttpUnauthorizedException' => __DIR__ . '/..' . '/slim/slim/Slim/Exception/HttpUnauthorizedException.php',
         'Slim\\Factory\\AppFactory' => __DIR__ . '/..' . '/slim/slim/Slim/Factory/AppFactory.php',
         'Slim\\Factory\\Psr17\\GuzzlePsr17Factory' => __DIR__ . '/..' . '/slim/slim/Slim/Factory/Psr17/GuzzlePsr17Factory.php',
@@ -208,20 +226,25 @@ class ComposerStaticInitAdvancedContentFilterAddon
         'Slim\\Routing\\RouteResolver' => __DIR__ . '/..' . '/slim/slim/Slim/Routing/RouteResolver.php',
         'Slim\\Routing\\RouteRunner' => __DIR__ . '/..' . '/slim/slim/Slim/Routing/RouteRunner.php',
         'Slim\\Routing\\RoutingResults' => __DIR__ . '/..' . '/slim/slim/Slim/Routing/RoutingResults.php',
+        'Stringable' => __DIR__ . '/..' . '/symfony/polyfill-php80/Resources/stubs/Stringable.php',
         'Symfony\\Component\\Cache\\Adapter\\AbstractAdapter' => __DIR__ . '/..' . '/symfony/cache/Adapter/AbstractAdapter.php',
+        'Symfony\\Component\\Cache\\Adapter\\AbstractTagAwareAdapter' => __DIR__ . '/..' . '/symfony/cache/Adapter/AbstractTagAwareAdapter.php',
         'Symfony\\Component\\Cache\\Adapter\\AdapterInterface' => __DIR__ . '/..' . '/symfony/cache/Adapter/AdapterInterface.php',
         'Symfony\\Component\\Cache\\Adapter\\ApcuAdapter' => __DIR__ . '/..' . '/symfony/cache/Adapter/ApcuAdapter.php',
         'Symfony\\Component\\Cache\\Adapter\\ArrayAdapter' => __DIR__ . '/..' . '/symfony/cache/Adapter/ArrayAdapter.php',
         'Symfony\\Component\\Cache\\Adapter\\ChainAdapter' => __DIR__ . '/..' . '/symfony/cache/Adapter/ChainAdapter.php',
         'Symfony\\Component\\Cache\\Adapter\\DoctrineAdapter' => __DIR__ . '/..' . '/symfony/cache/Adapter/DoctrineAdapter.php',
         'Symfony\\Component\\Cache\\Adapter\\FilesystemAdapter' => __DIR__ . '/..' . '/symfony/cache/Adapter/FilesystemAdapter.php',
+        'Symfony\\Component\\Cache\\Adapter\\FilesystemTagAwareAdapter' => __DIR__ . '/..' . '/symfony/cache/Adapter/FilesystemTagAwareAdapter.php',
         'Symfony\\Component\\Cache\\Adapter\\MemcachedAdapter' => __DIR__ . '/..' . '/symfony/cache/Adapter/MemcachedAdapter.php',
         'Symfony\\Component\\Cache\\Adapter\\NullAdapter' => __DIR__ . '/..' . '/symfony/cache/Adapter/NullAdapter.php',
         'Symfony\\Component\\Cache\\Adapter\\PdoAdapter' => __DIR__ . '/..' . '/symfony/cache/Adapter/PdoAdapter.php',
         'Symfony\\Component\\Cache\\Adapter\\PhpArrayAdapter' => __DIR__ . '/..' . '/symfony/cache/Adapter/PhpArrayAdapter.php',
         'Symfony\\Component\\Cache\\Adapter\\PhpFilesAdapter' => __DIR__ . '/..' . '/symfony/cache/Adapter/PhpFilesAdapter.php',
         'Symfony\\Component\\Cache\\Adapter\\ProxyAdapter' => __DIR__ . '/..' . '/symfony/cache/Adapter/ProxyAdapter.php',
+        'Symfony\\Component\\Cache\\Adapter\\Psr16Adapter' => __DIR__ . '/..' . '/symfony/cache/Adapter/Psr16Adapter.php',
         'Symfony\\Component\\Cache\\Adapter\\RedisAdapter' => __DIR__ . '/..' . '/symfony/cache/Adapter/RedisAdapter.php',
+        'Symfony\\Component\\Cache\\Adapter\\RedisTagAwareAdapter' => __DIR__ . '/..' . '/symfony/cache/Adapter/RedisTagAwareAdapter.php',
         'Symfony\\Component\\Cache\\Adapter\\SimpleCacheAdapter' => __DIR__ . '/..' . '/symfony/cache/Adapter/SimpleCacheAdapter.php',
         'Symfony\\Component\\Cache\\Adapter\\TagAwareAdapter' => __DIR__ . '/..' . '/symfony/cache/Adapter/TagAwareAdapter.php',
         'Symfony\\Component\\Cache\\Adapter\\TagAwareAdapterInterface' => __DIR__ . '/..' . '/symfony/cache/Adapter/TagAwareAdapterInterface.php',
@@ -230,10 +253,21 @@ class ComposerStaticInitAdvancedContentFilterAddon
         'Symfony\\Component\\Cache\\Adapter\\TraceableTagAwareAdapter' => __DIR__ . '/..' . '/symfony/cache/Adapter/TraceableTagAwareAdapter.php',
         'Symfony\\Component\\Cache\\CacheItem' => __DIR__ . '/..' . '/symfony/cache/CacheItem.php',
         'Symfony\\Component\\Cache\\DataCollector\\CacheDataCollector' => __DIR__ . '/..' . '/symfony/cache/DataCollector/CacheDataCollector.php',
+        'Symfony\\Component\\Cache\\DependencyInjection\\CacheCollectorPass' => __DIR__ . '/..' . '/symfony/cache/DependencyInjection/CacheCollectorPass.php',
+        'Symfony\\Component\\Cache\\DependencyInjection\\CachePoolClearerPass' => __DIR__ . '/..' . '/symfony/cache/DependencyInjection/CachePoolClearerPass.php',
+        'Symfony\\Component\\Cache\\DependencyInjection\\CachePoolPass' => __DIR__ . '/..' . '/symfony/cache/DependencyInjection/CachePoolPass.php',
+        'Symfony\\Component\\Cache\\DependencyInjection\\CachePoolPrunerPass' => __DIR__ . '/..' . '/symfony/cache/DependencyInjection/CachePoolPrunerPass.php',
         'Symfony\\Component\\Cache\\DoctrineProvider' => __DIR__ . '/..' . '/symfony/cache/DoctrineProvider.php',
         'Symfony\\Component\\Cache\\Exception\\CacheException' => __DIR__ . '/..' . '/symfony/cache/Exception/CacheException.php',
         'Symfony\\Component\\Cache\\Exception\\InvalidArgumentException' => __DIR__ . '/..' . '/symfony/cache/Exception/InvalidArgumentException.php',
+        'Symfony\\Component\\Cache\\Exception\\LogicException' => __DIR__ . '/..' . '/symfony/cache/Exception/LogicException.php',
+        'Symfony\\Component\\Cache\\LockRegistry' => __DIR__ . '/..' . '/symfony/cache/LockRegistry.php',
+        'Symfony\\Component\\Cache\\Marshaller\\DefaultMarshaller' => __DIR__ . '/..' . '/symfony/cache/Marshaller/DefaultMarshaller.php',
+        'Symfony\\Component\\Cache\\Marshaller\\DeflateMarshaller' => __DIR__ . '/..' . '/symfony/cache/Marshaller/DeflateMarshaller.php',
+        'Symfony\\Component\\Cache\\Marshaller\\MarshallerInterface' => __DIR__ . '/..' . '/symfony/cache/Marshaller/MarshallerInterface.php',
+        'Symfony\\Component\\Cache\\Marshaller\\TagAwareMarshaller' => __DIR__ . '/..' . '/symfony/cache/Marshaller/TagAwareMarshaller.php',
         'Symfony\\Component\\Cache\\PruneableInterface' => __DIR__ . '/..' . '/symfony/cache/PruneableInterface.php',
+        'Symfony\\Component\\Cache\\Psr16Cache' => __DIR__ . '/..' . '/symfony/cache/Psr16Cache.php',
         'Symfony\\Component\\Cache\\ResettableInterface' => __DIR__ . '/..' . '/symfony/cache/ResettableInterface.php',
         'Symfony\\Component\\Cache\\Simple\\AbstractCache' => __DIR__ . '/..' . '/symfony/cache/Simple/AbstractCache.php',
         'Symfony\\Component\\Cache\\Simple\\ApcuCache' => __DIR__ . '/..' . '/symfony/cache/Simple/ApcuCache.php',
@@ -250,17 +284,22 @@ class ComposerStaticInitAdvancedContentFilterAddon
         'Symfony\\Component\\Cache\\Simple\\RedisCache' => __DIR__ . '/..' . '/symfony/cache/Simple/RedisCache.php',
         'Symfony\\Component\\Cache\\Simple\\TraceableCache' => __DIR__ . '/..' . '/symfony/cache/Simple/TraceableCache.php',
         'Symfony\\Component\\Cache\\Simple\\TraceableCacheEvent' => __DIR__ . '/..' . '/symfony/cache/Simple/TraceableCache.php',
+        'Symfony\\Component\\Cache\\Traits\\AbstractAdapterTrait' => __DIR__ . '/..' . '/symfony/cache/Traits/AbstractAdapterTrait.php',
         'Symfony\\Component\\Cache\\Traits\\AbstractTrait' => __DIR__ . '/..' . '/symfony/cache/Traits/AbstractTrait.php',
         'Symfony\\Component\\Cache\\Traits\\ApcuTrait' => __DIR__ . '/..' . '/symfony/cache/Traits/ApcuTrait.php',
         'Symfony\\Component\\Cache\\Traits\\ArrayTrait' => __DIR__ . '/..' . '/symfony/cache/Traits/ArrayTrait.php',
+        'Symfony\\Component\\Cache\\Traits\\ContractsTrait' => __DIR__ . '/..' . '/symfony/cache/Traits/ContractsTrait.php',
         'Symfony\\Component\\Cache\\Traits\\DoctrineTrait' => __DIR__ . '/..' . '/symfony/cache/Traits/DoctrineTrait.php',
         'Symfony\\Component\\Cache\\Traits\\FilesystemCommonTrait' => __DIR__ . '/..' . '/symfony/cache/Traits/FilesystemCommonTrait.php',
         'Symfony\\Component\\Cache\\Traits\\FilesystemTrait' => __DIR__ . '/..' . '/symfony/cache/Traits/FilesystemTrait.php',
+        'Symfony\\Component\\Cache\\Traits\\LazyValue' => __DIR__ . '/..' . '/symfony/cache/Traits/PhpFilesTrait.php',
         'Symfony\\Component\\Cache\\Traits\\MemcachedTrait' => __DIR__ . '/..' . '/symfony/cache/Traits/MemcachedTrait.php',
         'Symfony\\Component\\Cache\\Traits\\PdoTrait' => __DIR__ . '/..' . '/symfony/cache/Traits/PdoTrait.php',
         'Symfony\\Component\\Cache\\Traits\\PhpArrayTrait' => __DIR__ . '/..' . '/symfony/cache/Traits/PhpArrayTrait.php',
         'Symfony\\Component\\Cache\\Traits\\PhpFilesTrait' => __DIR__ . '/..' . '/symfony/cache/Traits/PhpFilesTrait.php',
         'Symfony\\Component\\Cache\\Traits\\ProxyTrait' => __DIR__ . '/..' . '/symfony/cache/Traits/ProxyTrait.php',
+        'Symfony\\Component\\Cache\\Traits\\RedisClusterNodeProxy' => __DIR__ . '/..' . '/symfony/cache/Traits/RedisClusterNodeProxy.php',
+        'Symfony\\Component\\Cache\\Traits\\RedisClusterProxy' => __DIR__ . '/..' . '/symfony/cache/Traits/RedisClusterProxy.php',
         'Symfony\\Component\\Cache\\Traits\\RedisProxy' => __DIR__ . '/..' . '/symfony/cache/Traits/RedisProxy.php',
         'Symfony\\Component\\Cache\\Traits\\RedisTrait' => __DIR__ . '/..' . '/symfony/cache/Traits/RedisTrait.php',
         'Symfony\\Component\\ExpressionLanguage\\Compiler' => __DIR__ . '/..' . '/symfony/expression-language/Compiler.php',
@@ -288,7 +327,34 @@ class ComposerStaticInitAdvancedContentFilterAddon
         'Symfony\\Component\\ExpressionLanguage\\SyntaxError' => __DIR__ . '/..' . '/symfony/expression-language/SyntaxError.php',
         'Symfony\\Component\\ExpressionLanguage\\Token' => __DIR__ . '/..' . '/symfony/expression-language/Token.php',
         'Symfony\\Component\\ExpressionLanguage\\TokenStream' => __DIR__ . '/..' . '/symfony/expression-language/TokenStream.php',
-        'Symfony\\Polyfill\\Apcu\\Apcu' => __DIR__ . '/..' . '/symfony/polyfill-apcu/Apcu.php',
+        'Symfony\\Component\\VarExporter\\Exception\\ClassNotFoundException' => __DIR__ . '/..' . '/symfony/var-exporter/Exception/ClassNotFoundException.php',
+        'Symfony\\Component\\VarExporter\\Exception\\ExceptionInterface' => __DIR__ . '/..' . '/symfony/var-exporter/Exception/ExceptionInterface.php',
+        'Symfony\\Component\\VarExporter\\Exception\\NotInstantiableTypeException' => __DIR__ . '/..' . '/symfony/var-exporter/Exception/NotInstantiableTypeException.php',
+        'Symfony\\Component\\VarExporter\\Instantiator' => __DIR__ . '/..' . '/symfony/var-exporter/Instantiator.php',
+        'Symfony\\Component\\VarExporter\\Internal\\Exporter' => __DIR__ . '/..' . '/symfony/var-exporter/Internal/Exporter.php',
+        'Symfony\\Component\\VarExporter\\Internal\\Hydrator' => __DIR__ . '/..' . '/symfony/var-exporter/Internal/Hydrator.php',
+        'Symfony\\Component\\VarExporter\\Internal\\Reference' => __DIR__ . '/..' . '/symfony/var-exporter/Internal/Reference.php',
+        'Symfony\\Component\\VarExporter\\Internal\\Registry' => __DIR__ . '/..' . '/symfony/var-exporter/Internal/Registry.php',
+        'Symfony\\Component\\VarExporter\\Internal\\Values' => __DIR__ . '/..' . '/symfony/var-exporter/Internal/Values.php',
+        'Symfony\\Component\\VarExporter\\VarExporter' => __DIR__ . '/..' . '/symfony/var-exporter/VarExporter.php',
+        'Symfony\\Contracts\\Cache\\CacheInterface' => __DIR__ . '/..' . '/symfony/cache-contracts/CacheInterface.php',
+        'Symfony\\Contracts\\Cache\\CacheTrait' => __DIR__ . '/..' . '/symfony/cache-contracts/CacheTrait.php',
+        'Symfony\\Contracts\\Cache\\CallbackInterface' => __DIR__ . '/..' . '/symfony/cache-contracts/CallbackInterface.php',
+        'Symfony\\Contracts\\Cache\\ItemInterface' => __DIR__ . '/..' . '/symfony/cache-contracts/ItemInterface.php',
+        'Symfony\\Contracts\\Cache\\TagAwareCacheInterface' => __DIR__ . '/..' . '/symfony/cache-contracts/TagAwareCacheInterface.php',
+        'Symfony\\Contracts\\Service\\Attribute\\Required' => __DIR__ . '/..' . '/symfony/service-contracts/Attribute/Required.php',
+        'Symfony\\Contracts\\Service\\Attribute\\SubscribedService' => __DIR__ . '/..' . '/symfony/service-contracts/Attribute/SubscribedService.php',
+        'Symfony\\Contracts\\Service\\ResetInterface' => __DIR__ . '/..' . '/symfony/service-contracts/ResetInterface.php',
+        'Symfony\\Contracts\\Service\\ServiceLocatorTrait' => __DIR__ . '/..' . '/symfony/service-contracts/ServiceLocatorTrait.php',
+        'Symfony\\Contracts\\Service\\ServiceProviderInterface' => __DIR__ . '/..' . '/symfony/service-contracts/ServiceProviderInterface.php',
+        'Symfony\\Contracts\\Service\\ServiceSubscriberInterface' => __DIR__ . '/..' . '/symfony/service-contracts/ServiceSubscriberInterface.php',
+        'Symfony\\Contracts\\Service\\ServiceSubscriberTrait' => __DIR__ . '/..' . '/symfony/service-contracts/ServiceSubscriberTrait.php',
+        'Symfony\\Contracts\\Service\\Test\\ServiceLocatorTest' => __DIR__ . '/..' . '/symfony/service-contracts/Test/ServiceLocatorTest.php',
+        'Symfony\\Polyfill\\Php73\\Php73' => __DIR__ . '/..' . '/symfony/polyfill-php73/Php73.php',
+        'Symfony\\Polyfill\\Php80\\Php80' => __DIR__ . '/..' . '/symfony/polyfill-php80/Php80.php',
+        'Symfony\\Polyfill\\Php80\\PhpToken' => __DIR__ . '/..' . '/symfony/polyfill-php80/PhpToken.php',
+        'UnhandledMatchError' => __DIR__ . '/..' . '/symfony/polyfill-php80/Resources/stubs/UnhandledMatchError.php',
+        'ValueError' => __DIR__ . '/..' . '/symfony/polyfill-php80/Resources/stubs/ValueError.php',
     );
 
     public static function getInitializer(ClassLoader $loader)
index 1a84a8fdb06630fc694561fb5e915541adfccb01..07e02c7f1776d4603161c5aecf3adcd0bfc26642 100644 (file)
     },
     {
         "name": "psr/container",
-        "version": "2.0.2",
-        "version_normalized": "2.0.2.0",
+        "version": "1.1.2",
+        "version_normalized": "1.1.2.0",
         "source": {
             "type": "git",
             "url": "https://github.com/php-fig/container.git",
-            "reference": "c71ecc56dfe541dbd90c5360474fbc405f8d5963"
+            "reference": "513e0666f7216c7459170d56df27dfcefe1689ea"
         },
         "dist": {
             "type": "zip",
-            "url": "https://api.github.com/repos/php-fig/container/zipball/c71ecc56dfe541dbd90c5360474fbc405f8d5963",
-            "reference": "c71ecc56dfe541dbd90c5360474fbc405f8d5963",
+            "url": "https://api.github.com/repos/php-fig/container/zipball/513e0666f7216c7459170d56df27dfcefe1689ea",
+            "reference": "513e0666f7216c7459170d56df27dfcefe1689ea",
             "shasum": ""
         },
         "require": {
             "php": ">=7.4.0"
         },
-        "time": "2021-11-05T16:47:00+00:00",
+        "time": "2021-11-05T16:50:12+00:00",
         "type": "library",
-        "extra": {
-            "branch-alias": {
-                "dev-master": "2.0.x-dev"
-            }
-        },
         "installation-source": "dist",
         "autoload": {
             "psr-4": {
     },
     {
         "name": "psr/http-message",
-        "version": "1.1",
-        "version_normalized": "1.1.0.0",
+        "version": "2.0",
+        "version_normalized": "2.0.0.0",
         "source": {
             "type": "git",
             "url": "https://github.com/php-fig/http-message.git",
-            "reference": "cb6ce4845ce34a8ad9e68117c10ee90a29919eba"
+            "reference": "402d35bcb92c70c026d1a6a9883f06b2ead23d71"
         },
         "dist": {
             "type": "zip",
-            "url": "https://api.github.com/repos/php-fig/http-message/zipball/cb6ce4845ce34a8ad9e68117c10ee90a29919eba",
-            "reference": "cb6ce4845ce34a8ad9e68117c10ee90a29919eba",
+            "url": "https://api.github.com/repos/php-fig/http-message/zipball/402d35bcb92c70c026d1a6a9883f06b2ead23d71",
+            "reference": "402d35bcb92c70c026d1a6a9883f06b2ead23d71",
             "shasum": ""
         },
         "require": {
             "php": "^7.2 || ^8.0"
         },
-        "time": "2023-04-04T09:50:52+00:00",
+        "time": "2023-04-04T09:54:51+00:00",
         "type": "library",
         "extra": {
             "branch-alias": {
-                "dev-master": "1.1.x-dev"
+                "dev-master": "2.0.x-dev"
             }
         },
         "installation-source": "dist",
         "authors": [
             {
                 "name": "PHP-FIG",
-                "homepage": "http://www.php-fig.org/"
+                "homepage": "https://www.php-fig.org/"
             }
         ],
         "description": "Common interface for HTTP messages",
             "psr-3"
         ]
     },
-    {
-        "name": "psr/simple-cache",
-        "version": "1.0.1",
-        "version_normalized": "1.0.1.0",
-        "source": {
-            "type": "git",
-            "url": "https://github.com/php-fig/simple-cache.git",
-            "reference": "408d5eafb83c57f6365a3ca330ff23aa4a5fa39b"
-        },
-        "dist": {
-            "type": "zip",
-            "url": "https://api.github.com/repos/php-fig/simple-cache/zipball/408d5eafb83c57f6365a3ca330ff23aa4a5fa39b",
-            "reference": "408d5eafb83c57f6365a3ca330ff23aa4a5fa39b",
-            "shasum": ""
-        },
-        "require": {
-            "php": ">=5.3.0"
-        },
-        "time": "2017-10-23T01:57:42+00:00",
-        "type": "library",
-        "extra": {
-            "branch-alias": {
-                "dev-master": "1.0.x-dev"
-            }
-        },
-        "installation-source": "dist",
-        "autoload": {
-            "psr-4": {
-                "Psr\\SimpleCache\\": "src/"
-            }
-        },
-        "notification-url": "https://packagist.org/downloads/",
-        "license": [
-            "MIT"
-        ],
-        "authors": [
-            {
-                "name": "PHP-FIG",
-                "homepage": "http://www.php-fig.org/"
-            }
-        ],
-        "description": "Common interfaces for simple caching",
-        "keywords": [
-            "cache",
-            "caching",
-            "psr",
-            "psr-16",
-            "simple-cache"
-        ]
-    },
     {
         "name": "slim/slim",
-        "version": "4.12.0",
-        "version_normalized": "4.12.0.0",
+        "version": "4.13.0",
+        "version_normalized": "4.13.0.0",
         "source": {
             "type": "git",
             "url": "https://github.com/slimphp/Slim.git",
-            "reference": "e9e99c2b24398b967841c6c4c3048622cc7e2b18"
+            "reference": "038fd5713d5a41636fdff0e8dcceedecdd17fc17"
         },
         "dist": {
             "type": "zip",
-            "url": "https://api.github.com/repos/slimphp/Slim/zipball/e9e99c2b24398b967841c6c4c3048622cc7e2b18",
-            "reference": "e9e99c2b24398b967841c6c4c3048622cc7e2b18",
+            "url": "https://api.github.com/repos/slimphp/Slim/zipball/038fd5713d5a41636fdff0e8dcceedecdd17fc17",
+            "reference": "038fd5713d5a41636fdff0e8dcceedecdd17fc17",
             "shasum": ""
         },
         "require": {
             "php": "^7.4 || ^8.0",
             "psr/container": "^1.0 || ^2.0",
             "psr/http-factory": "^1.0",
-            "psr/http-message": "^1.1",
+            "psr/http-message": "^1.1 || ^2.0",
             "psr/http-server-handler": "^1.0",
             "psr/http-server-middleware": "^1.0",
             "psr/log": "^1.1 || ^2.0 || ^3.0"
         "require-dev": {
             "adriansuter/php-autoload-override": "^1.4",
             "ext-simplexml": "*",
-            "guzzlehttp/psr7": "^2.5",
+            "guzzlehttp/psr7": "^2.6",
             "httpsoft/http-message": "^1.1",
             "httpsoft/http-server-request": "^1.1",
-            "laminas/laminas-diactoros": "^2.17",
+            "laminas/laminas-diactoros": "^2.17 || ^3",
             "nyholm/psr7": "^1.8",
-            "nyholm/psr7-server": "^1.0",
-            "phpspec/prophecy": "^1.17",
-            "phpspec/prophecy-phpunit": "^2.0",
+            "nyholm/psr7-server": "^1.1",
+            "phpspec/prophecy": "^1.19",
+            "phpspec/prophecy-phpunit": "^2.1",
             "phpstan/phpstan": "^1.10",
             "phpunit/phpunit": "^9.6",
             "slim/http": "^1.3",
             "slim/psr7": "^1.6",
-            "squizlabs/php_codesniffer": "^3.7"
+            "squizlabs/php_codesniffer": "^3.9"
         },
         "suggest": {
             "ext-simplexml": "Needed to support XML format in BodyParsingMiddleware",
             "php-di/php-di": "PHP-DI is the recommended container library to be used with Slim",
             "slim/psr7": "Slim PSR-7 implementation. See https://www.slimframework.com/docs/v4/start/installation.html for more information."
         },
-        "time": "2023-07-23T04:54:29+00:00",
+        "time": "2024-03-03T21:25:30+00:00",
         "type": "library",
         "installation-source": "dist",
         "autoload": {
     },
     {
         "name": "symfony/cache",
-        "version": "v3.4.47",
-        "version_normalized": "3.4.47.0",
+        "version": "v4.4.48",
+        "version_normalized": "4.4.48.0",
         "source": {
             "type": "git",
             "url": "https://github.com/symfony/cache.git",
-            "reference": "a7a14c4832760bd1fbd31be2859ffedc9b6ff813"
+            "reference": "3b98ed664887ad197b8ede3da2432787212eb915"
         },
         "dist": {
             "type": "zip",
-            "url": "https://api.github.com/repos/symfony/cache/zipball/a7a14c4832760bd1fbd31be2859ffedc9b6ff813",
-            "reference": "a7a14c4832760bd1fbd31be2859ffedc9b6ff813",
+            "url": "https://api.github.com/repos/symfony/cache/zipball/3b98ed664887ad197b8ede3da2432787212eb915",
+            "reference": "3b98ed664887ad197b8ede3da2432787212eb915",
             "shasum": ""
         },
         "require": {
-            "php": "^5.5.9|>=7.0.8",
-            "psr/cache": "~1.0",
-            "psr/log": "~1.0",
-            "psr/simple-cache": "^1.0",
-            "symfony/polyfill-apcu": "~1.1"
+            "php": ">=7.1.3",
+            "psr/cache": "^1.0|^2.0",
+            "psr/log": "^1|^2|^3",
+            "symfony/cache-contracts": "^1.1.7|^2",
+            "symfony/polyfill-php73": "^1.9",
+            "symfony/polyfill-php80": "^1.16",
+            "symfony/service-contracts": "^1.1|^2",
+            "symfony/var-exporter": "^4.2|^5.0"
         },
         "conflict": {
-            "symfony/var-dumper": "<3.3"
+            "doctrine/dbal": "<2.7",
+            "symfony/dependency-injection": "<3.4",
+            "symfony/http-kernel": "<4.4|>=5.0",
+            "symfony/var-dumper": "<4.4"
         },
         "provide": {
-            "psr/cache-implementation": "1.0",
-            "psr/simple-cache-implementation": "1.0"
+            "psr/cache-implementation": "1.0|2.0",
+            "psr/simple-cache-implementation": "1.0|2.0",
+            "symfony/cache-implementation": "1.0|2.0"
         },
         "require-dev": {
             "cache/integration-tests": "dev-master",
-            "doctrine/cache": "^1.6",
-            "doctrine/dbal": "^2.4|^3.0",
-            "predis/predis": "^1.0"
-        },
-        "time": "2020-10-24T10:57:07+00:00",
+            "doctrine/cache": "^1.6|^2.0",
+            "doctrine/dbal": "^2.7|^3.0",
+            "predis/predis": "^1.1",
+            "psr/simple-cache": "^1.0|^2.0",
+            "symfony/config": "^4.2|^5.0",
+            "symfony/dependency-injection": "^3.4|^4.1|^5.0",
+            "symfony/filesystem": "^4.4|^5.0",
+            "symfony/http-kernel": "^4.4",
+            "symfony/var-dumper": "^4.4|^5.0"
+        },
+        "time": "2022-10-17T20:21:54+00:00",
         "type": "library",
         "installation-source": "dist",
         "autoload": {
                 "homepage": "https://symfony.com/contributors"
             }
         ],
-        "description": "Symfony Cache component with PSR-6, PSR-16, and tags",
+        "description": "Provides extended PSR-6, PSR-16 (and tags) implementations",
         "homepage": "https://symfony.com",
         "keywords": [
             "caching",
             }
         ]
     },
+    {
+        "name": "symfony/cache-contracts",
+        "version": "v2.5.2",
+        "version_normalized": "2.5.2.0",
+        "source": {
+            "type": "git",
+            "url": "https://github.com/symfony/cache-contracts.git",
+            "reference": "64be4a7acb83b6f2bf6de9a02cee6dad41277ebc"
+        },
+        "dist": {
+            "type": "zip",
+            "url": "https://api.github.com/repos/symfony/cache-contracts/zipball/64be4a7acb83b6f2bf6de9a02cee6dad41277ebc",
+            "reference": "64be4a7acb83b6f2bf6de9a02cee6dad41277ebc",
+            "shasum": ""
+        },
+        "require": {
+            "php": ">=7.2.5",
+            "psr/cache": "^1.0|^2.0|^3.0"
+        },
+        "suggest": {
+            "symfony/cache-implementation": ""
+        },
+        "time": "2022-01-02T09:53:40+00:00",
+        "type": "library",
+        "extra": {
+            "branch-alias": {
+                "dev-main": "2.5-dev"
+            },
+            "thanks": {
+                "name": "symfony/contracts",
+                "url": "https://github.com/symfony/contracts"
+            }
+        },
+        "installation-source": "dist",
+        "autoload": {
+            "psr-4": {
+                "Symfony\\Contracts\\Cache\\": ""
+            }
+        },
+        "notification-url": "https://packagist.org/downloads/",
+        "license": [
+            "MIT"
+        ],
+        "authors": [
+            {
+                "name": "Nicolas Grekas",
+                "email": "p@tchwork.com"
+            },
+            {
+                "name": "Symfony Community",
+                "homepage": "https://symfony.com/contributors"
+            }
+        ],
+        "description": "Generic abstractions related to caching",
+        "homepage": "https://symfony.com",
+        "keywords": [
+            "abstractions",
+            "contracts",
+            "decoupling",
+            "interfaces",
+            "interoperability",
+            "standards"
+        ],
+        "funding": [
+            {
+                "url": "https://symfony.com/sponsor",
+                "type": "custom"
+            },
+            {
+                "url": "https://github.com/fabpot",
+                "type": "github"
+            },
+            {
+                "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
+                "type": "tidelift"
+            }
+        ]
+    },
+    {
+        "name": "symfony/deprecation-contracts",
+        "version": "v2.5.2",
+        "version_normalized": "2.5.2.0",
+        "source": {
+            "type": "git",
+            "url": "https://github.com/symfony/deprecation-contracts.git",
+            "reference": "e8b495ea28c1d97b5e0c121748d6f9b53d075c66"
+        },
+        "dist": {
+            "type": "zip",
+            "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/e8b495ea28c1d97b5e0c121748d6f9b53d075c66",
+            "reference": "e8b495ea28c1d97b5e0c121748d6f9b53d075c66",
+            "shasum": ""
+        },
+        "require": {
+            "php": ">=7.1"
+        },
+        "time": "2022-01-02T09:53:40+00:00",
+        "type": "library",
+        "extra": {
+            "branch-alias": {
+                "dev-main": "2.5-dev"
+            },
+            "thanks": {
+                "name": "symfony/contracts",
+                "url": "https://github.com/symfony/contracts"
+            }
+        },
+        "installation-source": "dist",
+        "autoload": {
+            "files": [
+                "function.php"
+            ]
+        },
+        "notification-url": "https://packagist.org/downloads/",
+        "license": [
+            "MIT"
+        ],
+        "authors": [
+            {
+                "name": "Nicolas Grekas",
+                "email": "p@tchwork.com"
+            },
+            {
+                "name": "Symfony Community",
+                "homepage": "https://symfony.com/contributors"
+            }
+        ],
+        "description": "A generic function and convention to trigger deprecation notices",
+        "homepage": "https://symfony.com",
+        "funding": [
+            {
+                "url": "https://symfony.com/sponsor",
+                "type": "custom"
+            },
+            {
+                "url": "https://github.com/fabpot",
+                "type": "github"
+            },
+            {
+                "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
+                "type": "tidelift"
+            }
+        ]
+    },
     {
         "name": "symfony/expression-language",
         "version": "v3.4.47",
         ]
     },
     {
-        "name": "symfony/polyfill-apcu",
-        "version": "v1.28.0",
-        "version_normalized": "1.28.0.0",
+        "name": "symfony/polyfill-php70",
+        "version": "v1.20.0",
+        "version_normalized": "1.20.0.0",
         "source": {
             "type": "git",
-            "url": "https://github.com/symfony/polyfill-apcu.git",
-            "reference": "c6c2c0f5f4cb0b100c5dfea807ef5cd27bbe9899"
+            "url": "https://github.com/symfony/polyfill-php70.git",
+            "reference": "5f03a781d984aae42cebd18e7912fa80f02ee644"
         },
         "dist": {
             "type": "zip",
-            "url": "https://api.github.com/repos/symfony/polyfill-apcu/zipball/c6c2c0f5f4cb0b100c5dfea807ef5cd27bbe9899",
-            "reference": "c6c2c0f5f4cb0b100c5dfea807ef5cd27bbe9899",
+            "url": "https://api.github.com/repos/symfony/polyfill-php70/zipball/5f03a781d984aae42cebd18e7912fa80f02ee644",
+            "reference": "5f03a781d984aae42cebd18e7912fa80f02ee644",
             "shasum": ""
         },
         "require": {
             "php": ">=7.1"
         },
-        "time": "2023-01-26T09:26:14+00:00",
-        "type": "library",
+        "time": "2020-10-23T14:02:19+00:00",
+        "type": "metapackage",
         "extra": {
             "branch-alias": {
-                "dev-main": "1.28-dev"
+                "dev-main": "1.20-dev"
+            },
+            "thanks": {
+                "name": "symfony/polyfill",
+                "url": "https://github.com/symfony/polyfill"
+            }
+        },
+        "notification-url": "https://packagist.org/downloads/",
+        "license": [
+            "MIT"
+        ],
+        "authors": [
+            {
+                "name": "Nicolas Grekas",
+                "email": "p@tchwork.com"
+            },
+            {
+                "name": "Symfony Community",
+                "homepage": "https://symfony.com/contributors"
+            }
+        ],
+        "description": "Symfony polyfill backporting some PHP 7.0+ features to lower PHP versions",
+        "homepage": "https://symfony.com",
+        "keywords": [
+            "compatibility",
+            "polyfill",
+            "portable",
+            "shim"
+        ],
+        "funding": [
+            {
+                "url": "https://symfony.com/sponsor",
+                "type": "custom"
+            },
+            {
+                "url": "https://github.com/fabpot",
+                "type": "github"
             },
+            {
+                "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
+                "type": "tidelift"
+            }
+        ]
+    },
+    {
+        "name": "symfony/polyfill-php73",
+        "version": "v1.29.0",
+        "version_normalized": "1.29.0.0",
+        "source": {
+            "type": "git",
+            "url": "https://github.com/symfony/polyfill-php73.git",
+            "reference": "21bd091060673a1177ae842c0ef8fe30893114d2"
+        },
+        "dist": {
+            "type": "zip",
+            "url": "https://api.github.com/repos/symfony/polyfill-php73/zipball/21bd091060673a1177ae842c0ef8fe30893114d2",
+            "reference": "21bd091060673a1177ae842c0ef8fe30893114d2",
+            "shasum": ""
+        },
+        "require": {
+            "php": ">=7.1"
+        },
+        "time": "2024-01-29T20:11:03+00:00",
+        "type": "library",
+        "extra": {
             "thanks": {
                 "name": "symfony/polyfill",
                 "url": "https://github.com/symfony/polyfill"
                 "bootstrap.php"
             ],
             "psr-4": {
-                "Symfony\\Polyfill\\Apcu\\": ""
-            }
+                "Symfony\\Polyfill\\Php73\\": ""
+            },
+            "classmap": [
+                "Resources/stubs"
+            ]
         },
         "notification-url": "https://packagist.org/downloads/",
         "license": [
                 "homepage": "https://symfony.com/contributors"
             }
         ],
-        "description": "Symfony polyfill backporting apcu_* functions to lower PHP versions",
+        "description": "Symfony polyfill backporting some PHP 7.3+ features to lower PHP versions",
         "homepage": "https://symfony.com",
         "keywords": [
-            "apcu",
             "compatibility",
             "polyfill",
             "portable",
         ]
     },
     {
-        "name": "symfony/polyfill-php70",
-        "version": "v1.20.0",
-        "version_normalized": "1.20.0.0",
+        "name": "symfony/polyfill-php80",
+        "version": "v1.29.0",
+        "version_normalized": "1.29.0.0",
         "source": {
             "type": "git",
-            "url": "https://github.com/symfony/polyfill-php70.git",
-            "reference": "5f03a781d984aae42cebd18e7912fa80f02ee644"
+            "url": "https://github.com/symfony/polyfill-php80.git",
+            "reference": "87b68208d5c1188808dd7839ee1e6c8ec3b02f1b"
         },
         "dist": {
             "type": "zip",
-            "url": "https://api.github.com/repos/symfony/polyfill-php70/zipball/5f03a781d984aae42cebd18e7912fa80f02ee644",
-            "reference": "5f03a781d984aae42cebd18e7912fa80f02ee644",
+            "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/87b68208d5c1188808dd7839ee1e6c8ec3b02f1b",
+            "reference": "87b68208d5c1188808dd7839ee1e6c8ec3b02f1b",
             "shasum": ""
         },
         "require": {
             "php": ">=7.1"
         },
-        "time": "2020-10-23T14:02:19+00:00",
-        "type": "metapackage",
+        "time": "2024-01-29T20:11:03+00:00",
+        "type": "library",
         "extra": {
-            "branch-alias": {
-                "dev-main": "1.20-dev"
-            },
             "thanks": {
                 "name": "symfony/polyfill",
                 "url": "https://github.com/symfony/polyfill"
             }
         },
+        "installation-source": "dist",
+        "autoload": {
+            "files": [
+                "bootstrap.php"
+            ],
+            "psr-4": {
+                "Symfony\\Polyfill\\Php80\\": ""
+            },
+            "classmap": [
+                "Resources/stubs"
+            ]
+        },
         "notification-url": "https://packagist.org/downloads/",
         "license": [
             "MIT"
         ],
         "authors": [
+            {
+                "name": "Ion Bazan",
+                "email": "ion.bazan@gmail.com"
+            },
             {
                 "name": "Nicolas Grekas",
                 "email": "p@tchwork.com"
                 "homepage": "https://symfony.com/contributors"
             }
         ],
-        "description": "Symfony polyfill backporting some PHP 7.0+ features to lower PHP versions",
+        "description": "Symfony polyfill backporting some PHP 8.0+ features to lower PHP versions",
         "homepage": "https://symfony.com",
         "keywords": [
             "compatibility",
                 "type": "tidelift"
             }
         ]
+    },
+    {
+        "name": "symfony/service-contracts",
+        "version": "v2.5.2",
+        "version_normalized": "2.5.2.0",
+        "source": {
+            "type": "git",
+            "url": "https://github.com/symfony/service-contracts.git",
+            "reference": "4b426aac47d6427cc1a1d0f7e2ac724627f5966c"
+        },
+        "dist": {
+            "type": "zip",
+            "url": "https://api.github.com/repos/symfony/service-contracts/zipball/4b426aac47d6427cc1a1d0f7e2ac724627f5966c",
+            "reference": "4b426aac47d6427cc1a1d0f7e2ac724627f5966c",
+            "shasum": ""
+        },
+        "require": {
+            "php": ">=7.2.5",
+            "psr/container": "^1.1",
+            "symfony/deprecation-contracts": "^2.1|^3"
+        },
+        "conflict": {
+            "ext-psr": "<1.1|>=2"
+        },
+        "suggest": {
+            "symfony/service-implementation": ""
+        },
+        "time": "2022-05-30T19:17:29+00:00",
+        "type": "library",
+        "extra": {
+            "branch-alias": {
+                "dev-main": "2.5-dev"
+            },
+            "thanks": {
+                "name": "symfony/contracts",
+                "url": "https://github.com/symfony/contracts"
+            }
+        },
+        "installation-source": "dist",
+        "autoload": {
+            "psr-4": {
+                "Symfony\\Contracts\\Service\\": ""
+            }
+        },
+        "notification-url": "https://packagist.org/downloads/",
+        "license": [
+            "MIT"
+        ],
+        "authors": [
+            {
+                "name": "Nicolas Grekas",
+                "email": "p@tchwork.com"
+            },
+            {
+                "name": "Symfony Community",
+                "homepage": "https://symfony.com/contributors"
+            }
+        ],
+        "description": "Generic abstractions related to writing services",
+        "homepage": "https://symfony.com",
+        "keywords": [
+            "abstractions",
+            "contracts",
+            "decoupling",
+            "interfaces",
+            "interoperability",
+            "standards"
+        ],
+        "funding": [
+            {
+                "url": "https://symfony.com/sponsor",
+                "type": "custom"
+            },
+            {
+                "url": "https://github.com/fabpot",
+                "type": "github"
+            },
+            {
+                "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
+                "type": "tidelift"
+            }
+        ]
+    },
+    {
+        "name": "symfony/var-exporter",
+        "version": "v5.4.35",
+        "version_normalized": "5.4.35.0",
+        "source": {
+            "type": "git",
+            "url": "https://github.com/symfony/var-exporter.git",
+            "reference": "abb0a151b62d6b07e816487e20040464af96cae7"
+        },
+        "dist": {
+            "type": "zip",
+            "url": "https://api.github.com/repos/symfony/var-exporter/zipball/abb0a151b62d6b07e816487e20040464af96cae7",
+            "reference": "abb0a151b62d6b07e816487e20040464af96cae7",
+            "shasum": ""
+        },
+        "require": {
+            "php": ">=7.2.5",
+            "symfony/polyfill-php80": "^1.16"
+        },
+        "require-dev": {
+            "symfony/var-dumper": "^4.4.9|^5.0.9|^6.0"
+        },
+        "time": "2024-01-23T13:51:25+00:00",
+        "type": "library",
+        "installation-source": "dist",
+        "autoload": {
+            "psr-4": {
+                "Symfony\\Component\\VarExporter\\": ""
+            },
+            "exclude-from-classmap": [
+                "/Tests/"
+            ]
+        },
+        "notification-url": "https://packagist.org/downloads/",
+        "license": [
+            "MIT"
+        ],
+        "authors": [
+            {
+                "name": "Nicolas Grekas",
+                "email": "p@tchwork.com"
+            },
+            {
+                "name": "Symfony Community",
+                "homepage": "https://symfony.com/contributors"
+            }
+        ],
+        "description": "Allows exporting any serializable PHP data structure to plain PHP code",
+        "homepage": "https://symfony.com",
+        "keywords": [
+            "clone",
+            "construct",
+            "export",
+            "hydrate",
+            "instantiate",
+            "serialize"
+        ],
+        "funding": [
+            {
+                "url": "https://symfony.com/sponsor",
+                "type": "custom"
+            },
+            {
+                "url": "https://github.com/fabpot",
+                "type": "github"
+            },
+            {
+                "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
+                "type": "tidelift"
+            }
+        ]
     }
 ]
index baf6cd1a03befcff9914bda038c27edb5342e7a4..017f41ea6912a274b1bf20116adcf6f14ba0c1fa 100644 (file)
         "psr-4": {
             "Psr\\Container\\": "src/"
         }
-    },
-    "extra": {
-        "branch-alias": {
-            "dev-master": "2.0.x-dev"
-        }
     }
 }
index b2cad40153358d09f18631ac5044fa47ceb8d8fa..cf8e7fd330ffcac7259d2c908c26581736dcf4ae 100644 (file)
@@ -32,5 +32,5 @@ interface ContainerInterface
      *
      * @return bool
      */
-    public function has(string $id): bool;
+    public function has(string $id);
 }
index 56e8c0a6dbf7592669fd5dbf2f28ba3b08507da5..c66e5aba40c97459c9ec9cb21fcc6a52153afd9c 100644 (file)
@@ -7,7 +7,7 @@
     "authors": [
         {
             "name": "PHP-FIG",
-            "homepage": "http://www.php-fig.org/"
+            "homepage": "https://www.php-fig.org/"
         }
     ],
     "require": {
@@ -20,7 +20,7 @@
     },
     "extra": {
         "branch-alias": {
-            "dev-master": "1.1.x-dev"
+            "dev-master": "2.0.x-dev"
         }
     }
 }
index 8cdb4ed63af3c9ecffb39048360c166ce45ee91b..a83c98518d5496f87460f822473b84c8b85ea28c 100644 (file)
@@ -1,7 +1,5 @@
 <?php
 
-declare(strict_types=1);
-
 namespace Psr\Http\Message;
 
 /**
@@ -25,7 +23,7 @@ interface MessageInterface
      *
      * @return string HTTP protocol version.
      */
-    public function getProtocolVersion();
+    public function getProtocolVersion(): string;
 
     /**
      * Return an instance with the specified HTTP protocol version.
@@ -40,7 +38,7 @@ interface MessageInterface
      * @param string $version HTTP protocol version
      * @return static
      */
-    public function withProtocolVersion(string $version);
+    public function withProtocolVersion(string $version): MessageInterface;
 
     /**
      * Retrieves all message header values.
@@ -67,7 +65,7 @@ interface MessageInterface
      *     key MUST be a header name, and each value MUST be an array of strings
      *     for that header.
      */
-    public function getHeaders();
+    public function getHeaders(): array;
 
     /**
      * Checks if a header exists by the given case-insensitive name.
@@ -77,7 +75,7 @@ interface MessageInterface
      *     name using a case-insensitive string comparison. Returns false if
      *     no matching header name is found in the message.
      */
-    public function hasHeader(string $name);
+    public function hasHeader(string $name): bool;
 
     /**
      * Retrieves a message header value by the given case-insensitive name.
@@ -93,7 +91,7 @@ interface MessageInterface
      *    header. If the header does not appear in the message, this method MUST
      *    return an empty array.
      */
-    public function getHeader(string $name);
+    public function getHeader(string $name): array;
 
     /**
      * Retrieves a comma-separated string of the values for a single header.
@@ -114,7 +112,7 @@ interface MessageInterface
      *    concatenated together using a comma. If the header does not appear in
      *    the message, this method MUST return an empty string.
      */
-    public function getHeaderLine(string $name);
+    public function getHeaderLine(string $name): string;
 
     /**
      * Return an instance with the provided value replacing the specified header.
@@ -131,7 +129,7 @@ interface MessageInterface
      * @return static
      * @throws \InvalidArgumentException for invalid header names or values.
      */
-    public function withHeader(string $name, $value);
+    public function withHeader(string $name, $value): MessageInterface;
 
     /**
      * Return an instance with the specified header appended with the given value.
@@ -149,7 +147,7 @@ interface MessageInterface
      * @return static
      * @throws \InvalidArgumentException for invalid header names or values.
      */
-    public function withAddedHeader(string $name, $value);
+    public function withAddedHeader(string $name, $value): MessageInterface;
 
     /**
      * Return an instance without the specified header.
@@ -163,14 +161,14 @@ interface MessageInterface
      * @param string $name Case-insensitive header field name to remove.
      * @return static
      */
-    public function withoutHeader(string $name);
+    public function withoutHeader(string $name): MessageInterface;
 
     /**
      * Gets the body of the message.
      *
      * @return StreamInterface Returns the body as a stream.
      */
-    public function getBody();
+    public function getBody(): StreamInterface;
 
     /**
      * Return an instance with the specified message body.
@@ -185,5 +183,5 @@ interface MessageInterface
      * @return static
      * @throws \InvalidArgumentException When the body is not valid.
      */
-    public function withBody(StreamInterface $body);
+    public function withBody(StreamInterface $body): MessageInterface;
 }
index 38066df6bd3146689a570b721d37d746937648b5..33f85e559d0241e33d3b94bc3656441d188ac54a 100644 (file)
@@ -1,7 +1,5 @@
 <?php
 
-declare(strict_types=1);
-
 namespace Psr\Http\Message;
 
 /**
@@ -41,7 +39,7 @@ interface RequestInterface extends MessageInterface
      *
      * @return string
      */
-    public function getRequestTarget();
+    public function getRequestTarget(): string;
 
     /**
      * Return an instance with the specific request-target.
@@ -60,14 +58,15 @@ interface RequestInterface extends MessageInterface
      * @param string $requestTarget
      * @return static
      */
-    public function withRequestTarget(string $requestTarget);
+    public function withRequestTarget(string $requestTarget): RequestInterface;
+
 
     /**
      * Retrieves the HTTP method of the request.
      *
      * @return string Returns the request method.
      */
-    public function getMethod();
+    public function getMethod(): string;
 
     /**
      * Return an instance with the provided HTTP method.
@@ -84,7 +83,7 @@ interface RequestInterface extends MessageInterface
      * @return static
      * @throws \InvalidArgumentException for invalid HTTP methods.
      */
-    public function withMethod(string $method);
+    public function withMethod(string $method): RequestInterface;
 
     /**
      * Retrieves the URI instance.
@@ -95,7 +94,7 @@ interface RequestInterface extends MessageInterface
      * @return UriInterface Returns a UriInterface instance
      *     representing the URI of the request.
      */
-    public function getUri();
+    public function getUri(): UriInterface;
 
     /**
      * Returns an instance with the provided URI.
@@ -127,5 +126,5 @@ interface RequestInterface extends MessageInterface
      * @param bool $preserveHost Preserve the original state of the Host header.
      * @return static
      */
-    public function withUri(UriInterface $uri, bool $preserveHost = false);
+    public function withUri(UriInterface $uri, bool $preserveHost = false): RequestInterface;
 }
index f85ca48aadc66ab9a16e11d3433f8c63421b6664..e9299a91443f2d0e745a7bf8c1aa0e9f1249db4c 100644 (file)
@@ -1,7 +1,5 @@
 <?php
 
-declare(strict_types=1);
-
 namespace Psr\Http\Message;
 
 /**
@@ -29,7 +27,7 @@ interface ResponseInterface extends MessageInterface
      *
      * @return int Status code.
      */
-    public function getStatusCode();
+    public function getStatusCode(): int;
 
     /**
      * Return an instance with the specified status code and, optionally, reason phrase.
@@ -51,7 +49,7 @@ interface ResponseInterface extends MessageInterface
      * @return static
      * @throws \InvalidArgumentException For invalid status code arguments.
      */
-    public function withStatus(int $code, string $reasonPhrase = '');
+    public function withStatus(int $code, string $reasonPhrase = ''): ResponseInterface;
 
     /**
      * Gets the response reason phrase associated with the status code.
@@ -66,5 +64,5 @@ interface ResponseInterface extends MessageInterface
      * @link http://www.iana.org/assignments/http-status-codes/http-status-codes.xhtml
      * @return string Reason phrase; must return an empty string if none present.
      */
-    public function getReasonPhrase();
+    public function getReasonPhrase(): string;
 }
index 5e6d9649287a2767b82d370391864950ace41825..8625d0e100d93adf91ad364e35c7dcad02c1cfeb 100644 (file)
@@ -1,7 +1,5 @@
 <?php
 
-declare(strict_types=1);
-
 namespace Psr\Http\Message;
 
 /**
@@ -53,7 +51,7 @@ interface ServerRequestInterface extends RequestInterface
      *
      * @return array
      */
-    public function getServerParams();
+    public function getServerParams(): array;
 
     /**
      * Retrieve cookies.
@@ -65,7 +63,7 @@ interface ServerRequestInterface extends RequestInterface
      *
      * @return array
      */
-    public function getCookieParams();
+    public function getCookieParams(): array;
 
     /**
      * Return an instance with the specified cookies.
@@ -84,7 +82,7 @@ interface ServerRequestInterface extends RequestInterface
      * @param array $cookies Array of key/value pairs representing cookies.
      * @return static
      */
-    public function withCookieParams(array $cookies);
+    public function withCookieParams(array $cookies): ServerRequestInterface;
 
     /**
      * Retrieve query string arguments.
@@ -98,7 +96,7 @@ interface ServerRequestInterface extends RequestInterface
      *
      * @return array
      */
-    public function getQueryParams();
+    public function getQueryParams(): array;
 
     /**
      * Return an instance with the specified query string arguments.
@@ -122,7 +120,7 @@ interface ServerRequestInterface extends RequestInterface
      *     $_GET.
      * @return static
      */
-    public function withQueryParams(array $query);
+    public function withQueryParams(array $query): ServerRequestInterface;
 
     /**
      * Retrieve normalized file upload data.
@@ -136,7 +134,7 @@ interface ServerRequestInterface extends RequestInterface
      * @return array An array tree of UploadedFileInterface instances; an empty
      *     array MUST be returned if no data is present.
      */
-    public function getUploadedFiles();
+    public function getUploadedFiles(): array;
 
     /**
      * Create a new instance with the specified uploaded files.
@@ -149,7 +147,7 @@ interface ServerRequestInterface extends RequestInterface
      * @return static
      * @throws \InvalidArgumentException if an invalid structure is provided.
      */
-    public function withUploadedFiles(array $uploadedFiles);
+    public function withUploadedFiles(array $uploadedFiles): ServerRequestInterface;
 
     /**
      * Retrieve any parameters provided in the request body.
@@ -196,7 +194,7 @@ interface ServerRequestInterface extends RequestInterface
      * @throws \InvalidArgumentException if an unsupported argument type is
      *     provided.
      */
-    public function withParsedBody($data);
+    public function withParsedBody($data): ServerRequestInterface;
 
     /**
      * Retrieve attributes derived from the request.
@@ -209,7 +207,7 @@ interface ServerRequestInterface extends RequestInterface
      *
      * @return array Attributes derived from the request.
      */
-    public function getAttributes();
+    public function getAttributes(): array;
 
     /**
      * Retrieve a single derived request attribute.
@@ -243,7 +241,7 @@ interface ServerRequestInterface extends RequestInterface
      * @param mixed $value The value of the attribute.
      * @return static
      */
-    public function withAttribute(string $name, $value);
+    public function withAttribute(string $name, $value): ServerRequestInterface;
 
     /**
      * Return an instance that removes the specified derived request attribute.
@@ -259,5 +257,5 @@ interface ServerRequestInterface extends RequestInterface
      * @param string $name The attribute name.
      * @return static
      */
-    public function withoutAttribute(string $name);
+    public function withoutAttribute(string $name): ServerRequestInterface;
 }
index 592466390b9215dc66ba18ff392ca3241b143ac8..a62aabb8288b8d063ac2ebf746820a3292dfa7ec 100644 (file)
@@ -1,7 +1,5 @@
 <?php
 
-declare(strict_types=1);
-
 namespace Psr\Http\Message;
 
 /**
@@ -27,14 +25,14 @@ interface StreamInterface
      * @see http://php.net/manual/en/language.oop5.magic.php#object.tostring
      * @return string
      */
-    public function __toString();
+    public function __toString(): string;
 
     /**
      * Closes the stream and any underlying resources.
      *
      * @return void
      */
-    public function close();
+    public function close(): void;
 
     /**
      * Separates any underlying resources from the stream.
@@ -50,7 +48,7 @@ interface StreamInterface
      *
      * @return int|null Returns the size in bytes if known, or null if unknown.
      */
-    public function getSize();
+    public function getSize(): ?int;
 
     /**
      * Returns the current position of the file read/write pointer
@@ -58,21 +56,21 @@ interface StreamInterface
      * @return int Position of the file pointer
      * @throws \RuntimeException on error.
      */
-    public function tell();
+    public function tell(): int;
 
     /**
      * Returns true if the stream is at the end of the stream.
      *
      * @return bool
      */
-    public function eof();
+    public function eof(): bool;
 
     /**
      * Returns whether or not the stream is seekable.
      *
      * @return bool
      */
-    public function isSeekable();
+    public function isSeekable(): bool;
 
     /**
      * Seek to a position in the stream.
@@ -86,7 +84,7 @@ interface StreamInterface
      *     SEEK_END: Set position to end-of-stream plus offset.
      * @throws \RuntimeException on failure.
      */
-    public function seek(int $offset, int $whence = SEEK_SET);
+    public function seek(int $offset, int $whence = SEEK_SET): void;
 
     /**
      * Seek to the beginning of the stream.
@@ -98,14 +96,14 @@ interface StreamInterface
      * @link http://www.php.net/manual/en/function.fseek.php
      * @throws \RuntimeException on failure.
      */
-    public function rewind();
+    public function rewind(): void;
 
     /**
      * Returns whether or not the stream is writable.
      *
      * @return bool
      */
-    public function isWritable();
+    public function isWritable(): bool;
 
     /**
      * Write data to the stream.
@@ -114,14 +112,14 @@ interface StreamInterface
      * @return int Returns the number of bytes written to the stream.
      * @throws \RuntimeException on failure.
      */
-    public function write(string $string);
+    public function write(string $string): int;
 
     /**
      * Returns whether or not the stream is readable.
      *
      * @return bool
      */
-    public function isReadable();
+    public function isReadable(): bool;
 
     /**
      * Read data from the stream.
@@ -133,7 +131,7 @@ interface StreamInterface
      *     if no bytes are available.
      * @throws \RuntimeException if an error occurs.
      */
-    public function read(int $length);
+    public function read(int $length): string;
 
     /**
      * Returns the remaining contents in a string
@@ -142,7 +140,7 @@ interface StreamInterface
      * @throws \RuntimeException if unable to read or an error occurs while
      *     reading.
      */
-    public function getContents();
+    public function getContents(): string;
 
     /**
      * Get stream metadata as an associative array or retrieve a specific key.
index aba632158738a527900a1cb76a21039d0b22c0f0..dd19d653819f1881961257ef74424223aa2dc909 100644 (file)
@@ -1,7 +1,5 @@
 <?php
 
-declare(strict_types=1);
-
 namespace Psr\Http\Message;
 
 /**
@@ -30,7 +28,7 @@ interface UploadedFileInterface
      * @throws \RuntimeException in cases when no stream is available or can be
      *     created.
      */
-    public function getStream();
+    public function getStream(): StreamInterface;
 
     /**
      * Move the uploaded file to a new location.
@@ -64,7 +62,7 @@ interface UploadedFileInterface
      * @throws \RuntimeException on any error during the move operation, or on
      *     the second or subsequent call to the method.
      */
-    public function moveTo(string $targetPath);
+    public function moveTo(string $targetPath): void;
     
     /**
      * Retrieve the file size.
@@ -75,7 +73,7 @@ interface UploadedFileInterface
      *
      * @return int|null The file size in bytes or null if unknown.
      */
-    public function getSize();
+    public function getSize(): ?int;
     
     /**
      * Retrieve the error associated with the uploaded file.
@@ -91,7 +89,7 @@ interface UploadedFileInterface
      * @see http://php.net/manual/en/features.file-upload.errors.php
      * @return int One of PHP's UPLOAD_ERR_XXX constants.
      */
-    public function getError();
+    public function getError(): int;
     
     /**
      * Retrieve the filename sent by the client.
@@ -106,7 +104,7 @@ interface UploadedFileInterface
      * @return string|null The filename sent by the client or null if none
      *     was provided.
      */
-    public function getClientFilename();
+    public function getClientFilename(): ?string;
     
     /**
      * Retrieve the media type sent by the client.
@@ -121,5 +119,5 @@ interface UploadedFileInterface
      * @return string|null The media type sent by the client or null if none
      *     was provided.
      */
-    public function getClientMediaType();
+    public function getClientMediaType(): ?string;
 }
index d974de0de5c3f016af08cafe83d4937c9ef76580..15e2cf2862850b5b659440aa1e966debc2457ae4 100644 (file)
@@ -1,7 +1,5 @@
 <?php
 
-declare(strict_types=1);
-
 namespace Psr\Http\Message;
 
 /**
@@ -40,7 +38,7 @@ interface UriInterface
      * @see https://tools.ietf.org/html/rfc3986#section-3.1
      * @return string The URI scheme.
      */
-    public function getScheme();
+    public function getScheme(): string;
 
     /**
      * Retrieve the authority component of the URI.
@@ -60,7 +58,7 @@ interface UriInterface
      * @see https://tools.ietf.org/html/rfc3986#section-3.2
      * @return string The URI authority, in "[user-info@]host[:port]" format.
      */
-    public function getAuthority();
+    public function getAuthority(): string;
 
     /**
      * Retrieve the user information component of the URI.
@@ -77,7 +75,7 @@ interface UriInterface
      *
      * @return string The URI user information, in "username[:password]" format.
      */
-    public function getUserInfo();
+    public function getUserInfo(): string;
 
     /**
      * Retrieve the host component of the URI.
@@ -90,7 +88,7 @@ interface UriInterface
      * @see http://tools.ietf.org/html/rfc3986#section-3.2.2
      * @return string The URI host.
      */
-    public function getHost();
+    public function getHost(): string;
 
     /**
      * Retrieve the port component of the URI.
@@ -107,7 +105,7 @@ interface UriInterface
      *
      * @return null|int The URI port.
      */
-    public function getPort();
+    public function getPort(): ?int;
 
     /**
      * Retrieve the path component of the URI.
@@ -134,7 +132,7 @@ interface UriInterface
      * @see https://tools.ietf.org/html/rfc3986#section-3.3
      * @return string The URI path.
      */
-    public function getPath();
+    public function getPath(): string;
 
     /**
      * Retrieve the query string of the URI.
@@ -156,7 +154,7 @@ interface UriInterface
      * @see https://tools.ietf.org/html/rfc3986#section-3.4
      * @return string The URI query string.
      */
-    public function getQuery();
+    public function getQuery(): string;
 
     /**
      * Retrieve the fragment component of the URI.
@@ -174,7 +172,7 @@ interface UriInterface
      * @see https://tools.ietf.org/html/rfc3986#section-3.5
      * @return string The URI fragment.
      */
-    public function getFragment();
+    public function getFragment(): string;
 
     /**
      * Return an instance with the specified scheme.
@@ -191,7 +189,7 @@ interface UriInterface
      * @return static A new instance with the specified scheme.
      * @throws \InvalidArgumentException for invalid or unsupported schemes.
      */
-    public function withScheme(string $scheme);
+    public function withScheme(string $scheme): UriInterface;
 
     /**
      * Return an instance with the specified user information.
@@ -207,7 +205,7 @@ interface UriInterface
      * @param null|string $password The password associated with $user.
      * @return static A new instance with the specified user information.
      */
-    public function withUserInfo(string $user, ?string $password = null);
+    public function withUserInfo(string $user, ?string $password = null): UriInterface;
 
     /**
      * Return an instance with the specified host.
@@ -221,7 +219,7 @@ interface UriInterface
      * @return static A new instance with the specified host.
      * @throws \InvalidArgumentException for invalid hostnames.
      */
-    public function withHost(string $host);
+    public function withHost(string $host): UriInterface;
 
     /**
      * Return an instance with the specified port.
@@ -240,7 +238,7 @@ interface UriInterface
      * @return static A new instance with the specified port.
      * @throws \InvalidArgumentException for invalid ports.
      */
-    public function withPort(?int $port);
+    public function withPort(?int $port): UriInterface;
 
     /**
      * Return an instance with the specified path.
@@ -264,7 +262,7 @@ interface UriInterface
      * @return static A new instance with the specified path.
      * @throws \InvalidArgumentException for invalid paths.
      */
-    public function withPath(string $path);
+    public function withPath(string $path): UriInterface;
 
     /**
      * Return an instance with the specified query string.
@@ -281,7 +279,7 @@ interface UriInterface
      * @return static A new instance with the specified query string.
      * @throws \InvalidArgumentException for invalid query strings.
      */
-    public function withQuery(string $query);
+    public function withQuery(string $query): UriInterface;
 
     /**
      * Return an instance with the specified URI fragment.
@@ -297,7 +295,7 @@ interface UriInterface
      * @param string $fragment The fragment to use with the new instance.
      * @return static A new instance with the specified fragment.
      */
-    public function withFragment(string $fragment);
+    public function withFragment(string $fragment): UriInterface;
 
     /**
      * Return the string representation as a URI reference.
@@ -322,5 +320,5 @@ interface UriInterface
      * @see http://tools.ietf.org/html/rfc3986#section-4.1
      * @return string
      */
-    public function __toString();
+    public function __toString(): string;
 }
diff --git a/advancedcontentfilter/vendor/slim/slim/Slim/Exception/HttpTooManyRequestsException.php b/advancedcontentfilter/vendor/slim/slim/Slim/Exception/HttpTooManyRequestsException.php
new file mode 100644 (file)
index 0000000..be4b29b
--- /dev/null
@@ -0,0 +1,28 @@
+<?php
+
+/**
+ * Slim Framework (https://slimframework.com)
+ *
+ * @license https://github.com/slimphp/Slim/blob/4.x/LICENSE.md (MIT License)
+ */
+
+declare(strict_types=1);
+
+namespace Slim\Exception;
+
+class HttpTooManyRequestsException extends HttpSpecializedException
+{
+    /**
+     * @var int
+     */
+    protected $code = 429;
+
+    /**
+     * @var string
+     */
+    protected $message = 'Too many requests.';
+
+    protected string $title = '429 Too Many Requests';
+    protected string $description = 'The client application has surpassed its rate limit, ' .
+                                    'or number of requests they can send in a given period of time.';
+}
index 36c0c1d19d8c4f0eb79b76beaa19d6d544096706..f98064ff275d8dd98e874be30bae66e38b500afe 100644 (file)
@@ -48,7 +48,7 @@
         "nikic/fast-route": "^1.3",
         "psr/container": "^1.0 || ^2.0",
         "psr/http-factory": "^1.0",
-        "psr/http-message": "^1.1",
+        "psr/http-message": "^1.1 || ^2.0",
         "psr/http-server-handler": "^1.0",
         "psr/http-server-middleware": "^1.0",
         "psr/log": "^1.1 || ^2.0 || ^3.0"
     "require-dev": {
         "ext-simplexml": "*",
         "adriansuter/php-autoload-override": "^1.4",
-        "guzzlehttp/psr7": "^2.5",
+        "guzzlehttp/psr7": "^2.6",
         "httpsoft/http-message": "^1.1",
         "httpsoft/http-server-request": "^1.1",
-        "laminas/laminas-diactoros": "^2.17",
+        "laminas/laminas-diactoros": "^2.17 || ^3",
         "nyholm/psr7": "^1.8",
-        "nyholm/psr7-server": "^1.0",
-        "phpspec/prophecy": "^1.17",
-        "phpspec/prophecy-phpunit": "^2.0",
+        "nyholm/psr7-server": "^1.1",
+        "phpspec/prophecy": "^1.19",
+        "phpspec/prophecy-phpunit": "^2.1",
         "phpstan/phpstan": "^1.10",
         "phpunit/phpunit": "^9.6",
         "slim/http": "^1.3",
         "slim/psr7": "^1.6",
-        "squizlabs/php_codesniffer": "^3.7"
+        "squizlabs/php_codesniffer": "^3.9"
     },
     "autoload": {
         "psr-4": {
diff --git a/advancedcontentfilter/vendor/symfony/cache-contracts/.gitignore b/advancedcontentfilter/vendor/symfony/cache-contracts/.gitignore
new file mode 100644 (file)
index 0000000..c49a5d8
--- /dev/null
@@ -0,0 +1,3 @@
+vendor/
+composer.lock
+phpunit.xml
diff --git a/advancedcontentfilter/vendor/symfony/cache-contracts/CHANGELOG.md b/advancedcontentfilter/vendor/symfony/cache-contracts/CHANGELOG.md
new file mode 100644 (file)
index 0000000..7932e26
--- /dev/null
@@ -0,0 +1,5 @@
+CHANGELOG
+=========
+
+The changelog is maintained for all Symfony contracts at the following URL:
+https://github.com/symfony/contracts/blob/main/CHANGELOG.md
diff --git a/advancedcontentfilter/vendor/symfony/cache-contracts/CacheInterface.php b/advancedcontentfilter/vendor/symfony/cache-contracts/CacheInterface.php
new file mode 100644 (file)
index 0000000..67e4dfd
--- /dev/null
@@ -0,0 +1,57 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien@symfony.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Contracts\Cache;
+
+use Psr\Cache\CacheItemInterface;
+use Psr\Cache\InvalidArgumentException;
+
+/**
+ * Covers most simple to advanced caching needs.
+ *
+ * @author Nicolas Grekas <p@tchwork.com>
+ */
+interface CacheInterface
+{
+    /**
+     * Fetches a value from the pool or computes it if not found.
+     *
+     * On cache misses, a callback is called that should return the missing value.
+     * This callback is given a PSR-6 CacheItemInterface instance corresponding to the
+     * requested key, that could be used e.g. for expiration control. It could also
+     * be an ItemInterface instance when its additional features are needed.
+     *
+     * @param string                     $key       The key of the item to retrieve from the cache
+     * @param callable|CallbackInterface $callback  Should return the computed value for the given key/item
+     * @param float|null                 $beta      A float that, as it grows, controls the likeliness of triggering
+     *                                              early expiration. 0 disables it, INF forces immediate expiration.
+     *                                              The default (or providing null) is implementation dependent but should
+     *                                              typically be 1.0, which should provide optimal stampede protection.
+     *                                              See https://en.wikipedia.org/wiki/Cache_stampede#Probabilistic_early_expiration
+     * @param array                      &$metadata The metadata of the cached item {@see ItemInterface::getMetadata()}
+     *
+     * @return mixed
+     *
+     * @throws InvalidArgumentException When $key is not valid or when $beta is negative
+     */
+    public function get(string $key, callable $callback, float $beta = null, array &$metadata = null);
+
+    /**
+     * Removes an item from the pool.
+     *
+     * @param string $key The key to delete
+     *
+     * @throws InvalidArgumentException When $key is not valid
+     *
+     * @return bool True if the item was successfully removed, false if there was any error
+     */
+    public function delete(string $key): bool;
+}
diff --git a/advancedcontentfilter/vendor/symfony/cache-contracts/CacheTrait.php b/advancedcontentfilter/vendor/symfony/cache-contracts/CacheTrait.php
new file mode 100644 (file)
index 0000000..d340e06
--- /dev/null
@@ -0,0 +1,80 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien@symfony.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Contracts\Cache;
+
+use Psr\Cache\CacheItemPoolInterface;
+use Psr\Cache\InvalidArgumentException;
+use Psr\Log\LoggerInterface;
+
+// Help opcache.preload discover always-needed symbols
+class_exists(InvalidArgumentException::class);
+
+/**
+ * An implementation of CacheInterface for PSR-6 CacheItemPoolInterface classes.
+ *
+ * @author Nicolas Grekas <p@tchwork.com>
+ */
+trait CacheTrait
+{
+    /**
+     * {@inheritdoc}
+     *
+     * @return mixed
+     */
+    public function get(string $key, callable $callback, float $beta = null, array &$metadata = null)
+    {
+        return $this->doGet($this, $key, $callback, $beta, $metadata);
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function delete(string $key): bool
+    {
+        return $this->deleteItem($key);
+    }
+
+    private function doGet(CacheItemPoolInterface $pool, string $key, callable $callback, ?float $beta, array &$metadata = null, LoggerInterface $logger = null)
+    {
+        if (0 > $beta = $beta ?? 1.0) {
+            throw new class(sprintf('Argument "$beta" provided to "%s::get()" must be a positive number, %f given.', static::class, $beta)) extends \InvalidArgumentException implements InvalidArgumentException { };
+        }
+
+        $item = $pool->getItem($key);
+        $recompute = !$item->isHit() || \INF === $beta;
+        $metadata = $item instanceof ItemInterface ? $item->getMetadata() : [];
+
+        if (!$recompute && $metadata) {
+            $expiry = $metadata[ItemInterface::METADATA_EXPIRY] ?? false;
+            $ctime = $metadata[ItemInterface::METADATA_CTIME] ?? false;
+
+            if ($recompute = $ctime && $expiry && $expiry <= ($now = microtime(true)) - $ctime / 1000 * $beta * log(random_int(1, \PHP_INT_MAX) / \PHP_INT_MAX)) {
+                // force applying defaultLifetime to expiry
+                $item->expiresAt(null);
+                $logger && $logger->info('Item "{key}" elected for early recomputation {delta}s before its expiration', [
+                    'key' => $key,
+                    'delta' => sprintf('%.1f', $expiry - $now),
+                ]);
+            }
+        }
+
+        if ($recompute) {
+            $save = true;
+            $item->set($callback($item, $save));
+            if ($save) {
+                $pool->save($item);
+            }
+        }
+
+        return $item->get();
+    }
+}
diff --git a/advancedcontentfilter/vendor/symfony/cache-contracts/CallbackInterface.php b/advancedcontentfilter/vendor/symfony/cache-contracts/CallbackInterface.php
new file mode 100644 (file)
index 0000000..7dae2aa
--- /dev/null
@@ -0,0 +1,30 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien@symfony.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Contracts\Cache;
+
+use Psr\Cache\CacheItemInterface;
+
+/**
+ * Computes and returns the cached value of an item.
+ *
+ * @author Nicolas Grekas <p@tchwork.com>
+ */
+interface CallbackInterface
+{
+    /**
+     * @param CacheItemInterface|ItemInterface $item  The item to compute the value for
+     * @param bool                             &$save Should be set to false when the value should not be saved in the pool
+     *
+     * @return mixed The computed value for the passed item
+     */
+    public function __invoke(CacheItemInterface $item, bool &$save);
+}
diff --git a/advancedcontentfilter/vendor/symfony/cache-contracts/ItemInterface.php b/advancedcontentfilter/vendor/symfony/cache-contracts/ItemInterface.php
new file mode 100644 (file)
index 0000000..10c0488
--- /dev/null
@@ -0,0 +1,65 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien@symfony.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Contracts\Cache;
+
+use Psr\Cache\CacheException;
+use Psr\Cache\CacheItemInterface;
+use Psr\Cache\InvalidArgumentException;
+
+/**
+ * Augments PSR-6's CacheItemInterface with support for tags and metadata.
+ *
+ * @author Nicolas Grekas <p@tchwork.com>
+ */
+interface ItemInterface extends CacheItemInterface
+{
+    /**
+     * References the Unix timestamp stating when the item will expire.
+     */
+    public const METADATA_EXPIRY = 'expiry';
+
+    /**
+     * References the time the item took to be created, in milliseconds.
+     */
+    public const METADATA_CTIME = 'ctime';
+
+    /**
+     * References the list of tags that were assigned to the item, as string[].
+     */
+    public const METADATA_TAGS = 'tags';
+
+    /**
+     * Reserved characters that cannot be used in a key or tag.
+     */
+    public const RESERVED_CHARACTERS = '{}()/\@:';
+
+    /**
+     * Adds a tag to a cache item.
+     *
+     * Tags are strings that follow the same validation rules as keys.
+     *
+     * @param string|string[] $tags A tag or array of tags
+     *
+     * @return $this
+     *
+     * @throws InvalidArgumentException When $tag is not valid
+     * @throws CacheException           When the item comes from a pool that is not tag-aware
+     */
+    public function tag($tags): self;
+
+    /**
+     * Returns a list of metadata info that were saved alongside with the cached value.
+     *
+     * See ItemInterface::METADATA_* consts for keys potentially found in the returned array.
+     */
+    public function getMetadata(): array;
+}
diff --git a/advancedcontentfilter/vendor/symfony/cache-contracts/LICENSE b/advancedcontentfilter/vendor/symfony/cache-contracts/LICENSE
new file mode 100644 (file)
index 0000000..74cdc2d
--- /dev/null
@@ -0,0 +1,19 @@
+Copyright (c) 2018-2022 Fabien Potencier
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is furnished
+to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
diff --git a/advancedcontentfilter/vendor/symfony/cache-contracts/README.md b/advancedcontentfilter/vendor/symfony/cache-contracts/README.md
new file mode 100644 (file)
index 0000000..7085a69
--- /dev/null
@@ -0,0 +1,9 @@
+Symfony Cache Contracts
+=======================
+
+A set of abstractions extracted out of the Symfony components.
+
+Can be used to build on semantics that the Symfony components proved useful - and
+that already have battle tested implementations.
+
+See https://github.com/symfony/contracts/blob/main/README.md for more information.
diff --git a/advancedcontentfilter/vendor/symfony/cache-contracts/TagAwareCacheInterface.php b/advancedcontentfilter/vendor/symfony/cache-contracts/TagAwareCacheInterface.php
new file mode 100644 (file)
index 0000000..7c4cf11
--- /dev/null
@@ -0,0 +1,38 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien@symfony.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Contracts\Cache;
+
+use Psr\Cache\InvalidArgumentException;
+
+/**
+ * Allows invalidating cached items using tags.
+ *
+ * @author Nicolas Grekas <p@tchwork.com>
+ */
+interface TagAwareCacheInterface extends CacheInterface
+{
+    /**
+     * Invalidates cached items using tags.
+     *
+     * When implemented on a PSR-6 pool, invalidation should not apply
+     * to deferred items. Instead, they should be committed as usual.
+     * This allows replacing old tagged values by new ones without
+     * race conditions.
+     *
+     * @param string[] $tags An array of tags to invalidate
+     *
+     * @return bool True on success
+     *
+     * @throws InvalidArgumentException When $tags is not valid
+     */
+    public function invalidateTags(array $tags);
+}
diff --git a/advancedcontentfilter/vendor/symfony/cache-contracts/composer.json b/advancedcontentfilter/vendor/symfony/cache-contracts/composer.json
new file mode 100644 (file)
index 0000000..9f45e17
--- /dev/null
@@ -0,0 +1,38 @@
+{
+    "name": "symfony/cache-contracts",
+    "type": "library",
+    "description": "Generic abstractions related to caching",
+    "keywords": ["abstractions", "contracts", "decoupling", "interfaces", "interoperability", "standards"],
+    "homepage": "https://symfony.com",
+    "license": "MIT",
+    "authors": [
+        {
+            "name": "Nicolas Grekas",
+            "email": "p@tchwork.com"
+        },
+        {
+            "name": "Symfony Community",
+            "homepage": "https://symfony.com/contributors"
+        }
+    ],
+    "require": {
+        "php": ">=7.2.5",
+        "psr/cache": "^1.0|^2.0|^3.0"
+    },
+    "suggest": {
+        "symfony/cache-implementation": ""
+    },
+    "autoload": {
+        "psr-4": { "Symfony\\Contracts\\Cache\\": "" }
+    },
+    "minimum-stability": "dev",
+    "extra": {
+        "branch-alias": {
+            "dev-main": "2.5-dev"
+        },
+        "thanks": {
+            "name": "symfony/contracts",
+            "url": "https://github.com/symfony/contracts"
+        }
+    }
+}
index ab7dc9607fb955bf660ec9261e5702c57d5c7ba7..656474425335b3f1ce36fd51a290cabd96e867c4 100644 (file)
 
 namespace Symfony\Component\Cache\Adapter;
 
-use Psr\Cache\CacheItemInterface;
 use Psr\Log\LoggerAwareInterface;
 use Psr\Log\LoggerInterface;
 use Symfony\Component\Cache\CacheItem;
 use Symfony\Component\Cache\Exception\InvalidArgumentException;
 use Symfony\Component\Cache\ResettableInterface;
-use Symfony\Component\Cache\Traits\AbstractTrait;
+use Symfony\Component\Cache\Traits\AbstractAdapterTrait;
+use Symfony\Component\Cache\Traits\ContractsTrait;
+use Symfony\Contracts\Cache\CacheInterface;
 
 /**
  * @author Nicolas Grekas <p@tchwork.com>
  */
-abstract class AbstractAdapter implements AdapterInterface, LoggerAwareInterface, ResettableInterface
+abstract class AbstractAdapter implements AdapterInterface, CacheInterface, LoggerAwareInterface, ResettableInterface
 {
+    use AbstractAdapterTrait;
+    use ContractsTrait;
+
     /**
      * @internal
      */
-    const NS_SEPARATOR = ':';
-
-    use AbstractTrait;
+    protected const NS_SEPARATOR = ':';
 
     private static $apcuSupported;
     private static $phpFilesSupported;
 
-    private $createCacheItem;
-    private $mergeByLifetime;
-
-    /**
-     * @param string $namespace
-     * @param int    $defaultLifetime
-     */
-    protected function __construct($namespace = '', $defaultLifetime = 0)
+    protected function __construct(string $namespace = '', int $defaultLifetime = 0)
     {
         $this->namespace = '' === $namespace ? '' : CacheItem::validateKey($namespace).static::NS_SEPARATOR;
         if (null !== $this->maxIdLength && \strlen($namespace) > $this->maxIdLength - 24) {
@@ -51,31 +46,45 @@ abstract class AbstractAdapter implements AdapterInterface, LoggerAwareInterface
             static function ($key, $value, $isHit) {
                 $item = new CacheItem();
                 $item->key = $key;
-                $item->value = $value;
+                $item->value = $v = $value;
                 $item->isHit = $isHit;
+                // Detect wrapped values that encode for their expiry and creation duration
+                // For compactness, these values are packed in the key of an array using
+                // magic numbers in the form 9D-..-..-..-..-00-..-..-..-5F
+                if (\is_array($v) && 1 === \count($v) && 10 === \strlen($k = (string) array_key_first($v)) && "\x9D" === $k[0] && "\0" === $k[5] && "\x5F" === $k[9]) {
+                    $item->value = $v[$k];
+                    $v = unpack('Ve/Nc', substr($k, 1, -1));
+                    $item->metadata[CacheItem::METADATA_EXPIRY] = $v['e'] + CacheItem::METADATA_EXPIRY_OFFSET;
+                    $item->metadata[CacheItem::METADATA_CTIME] = $v['c'];
+                }
 
                 return $item;
             },
             null,
             CacheItem::class
         );
-        $getId = function ($key) { return $this->getId((string) $key); };
+        $getId = \Closure::fromCallable([$this, 'getId']);
         $this->mergeByLifetime = \Closure::bind(
             static function ($deferred, $namespace, &$expiredIds) use ($getId, $defaultLifetime) {
                 $byLifetime = [];
-                $now = time();
+                $now = microtime(true);
                 $expiredIds = [];
 
                 foreach ($deferred as $key => $item) {
+                    $key = (string) $key;
                     if (null === $item->expiry) {
-                        $byLifetime[0 < $defaultLifetime ? $defaultLifetime : 0][$getId($key)] = $item->value;
-                    } elseif (0 === $item->expiry) {
-                        $byLifetime[0][$getId($key)] = $item->value;
-                    } elseif ($item->expiry > $now) {
-                        $byLifetime[$item->expiry - $now][$getId($key)] = $item->value;
-                    } else {
+                        $ttl = 0 < $defaultLifetime ? $defaultLifetime : 0;
+                    } elseif (!$item->expiry) {
+                        $ttl = 0;
+                    } elseif (0 >= $ttl = (int) (0.1 + $item->expiry - $now)) {
                         $expiredIds[] = $getId($key);
+                        continue;
+                    }
+                    if (isset(($metadata = $item->newMetadata)[CacheItem::METADATA_TAGS])) {
+                        unset($metadata[CacheItem::METADATA_TAGS]);
                     }
+                    // For compactness, expiry and creation duration are packed in the key of an array, using magic numbers as separators
+                    $byLifetime[$ttl][$getId($key)] = $metadata ? ["\x9D".pack('VN', (int) (0.1 + $metadata[self::METADATA_EXPIRY] - self::METADATA_EXPIRY_OFFSET), $metadata[self::METADATA_CTIME])."\x5F" => $item->value] : $item->value;
                 }
 
                 return $byLifetime;
@@ -86,6 +95,10 @@ abstract class AbstractAdapter implements AdapterInterface, LoggerAwareInterface
     }
 
     /**
+     * Returns the best possible adapter that your runtime supports.
+     *
+     * Using ApcuAdapter makes system caches compatible with read-only filesystems.
+     *
      * @param string $namespace
      * @param int    $defaultLifetime
      * @param string $version
@@ -95,37 +108,25 @@ abstract class AbstractAdapter implements AdapterInterface, LoggerAwareInterface
      */
     public static function createSystemCache($namespace, $defaultLifetime, $version, $directory, LoggerInterface $logger = null)
     {
-        if (null === self::$apcuSupported) {
-            self::$apcuSupported = ApcuAdapter::isSupported();
-        }
-
-        if (!self::$apcuSupported && null === self::$phpFilesSupported) {
-            self::$phpFilesSupported = PhpFilesAdapter::isSupported();
+        $opcache = new PhpFilesAdapter($namespace, $defaultLifetime, $directory, true);
+        if (null !== $logger) {
+            $opcache->setLogger($logger);
         }
 
-        if (self::$phpFilesSupported) {
-            $opcache = new PhpFilesAdapter($namespace, $defaultLifetime, $directory);
-            if (null !== $logger) {
-                $opcache->setLogger($logger);
-            }
-
+        if (!self::$apcuSupported = self::$apcuSupported ?? ApcuAdapter::isSupported()) {
             return $opcache;
         }
 
-        $fs = new FilesystemAdapter($namespace, $defaultLifetime, $directory);
-        if (null !== $logger) {
-            $fs->setLogger($logger);
-        }
-        if (!self::$apcuSupported || (\in_array(\PHP_SAPI, ['cli', 'phpdbg'], true) && !filter_var(ini_get('apc.enable_cli'), \FILTER_VALIDATE_BOOLEAN))) {
-            return $fs;
+        if (\in_array(\PHP_SAPI, ['cli', 'phpdbg'], true) && !filter_var(\ini_get('apc.enable_cli'), \FILTER_VALIDATE_BOOLEAN)) {
+            return $opcache;
         }
 
-        $apcu = new ApcuAdapter($namespace, (int) $defaultLifetime / 5, $version);
+        $apcu = new ApcuAdapter($namespace, intdiv($defaultLifetime, 5), $version);
         if (null !== $logger) {
             $apcu->setLogger($logger);
         }
 
-        return new ChainAdapter([$apcu, $fs]);
+        return new ChainAdapter([$apcu, $opcache]);
     }
 
     public static function createConnection($dsn, array $options = [])
@@ -133,10 +134,10 @@ abstract class AbstractAdapter implements AdapterInterface, LoggerAwareInterface
         if (!\is_string($dsn)) {
             throw new InvalidArgumentException(sprintf('The "%s()" method expect argument #1 to be string, "%s" given.', __METHOD__, \gettype($dsn)));
         }
-        if (0 === strpos($dsn, 'redis://')) {
+        if (str_starts_with($dsn, 'redis:') || str_starts_with($dsn, 'rediss:')) {
             return RedisAdapter::createConnection($dsn, $options);
         }
-        if (0 === strpos($dsn, 'memcached://')) {
+        if (str_starts_with($dsn, 'memcached:')) {
             return MemcachedAdapter::createConnection($dsn, $options);
         }
 
@@ -145,81 +146,8 @@ abstract class AbstractAdapter implements AdapterInterface, LoggerAwareInterface
 
     /**
      * {@inheritdoc}
-     */
-    public function getItem($key)
-    {
-        if ($this->deferred) {
-            $this->commit();
-        }
-        $id = $this->getId($key);
-
-        $f = $this->createCacheItem;
-        $isHit = false;
-        $value = null;
-
-        try {
-            foreach ($this->doFetch([$id]) as $value) {
-                $isHit = true;
-            }
-        } catch (\Exception $e) {
-            CacheItem::log($this->logger, 'Failed to fetch key "{key}"', ['key' => $key, 'exception' => $e]);
-        }
-
-        return $f($key, $value, $isHit);
-    }
-
-    /**
-     * {@inheritdoc}
-     */
-    public function getItems(array $keys = [])
-    {
-        if ($this->deferred) {
-            $this->commit();
-        }
-        $ids = [];
-
-        foreach ($keys as $key) {
-            $ids[] = $this->getId($key);
-        }
-        try {
-            $items = $this->doFetch($ids);
-        } catch (\Exception $e) {
-            CacheItem::log($this->logger, 'Failed to fetch requested items', ['keys' => $keys, 'exception' => $e]);
-            $items = [];
-        }
-        $ids = array_combine($ids, $keys);
-
-        return $this->generateItems($items, $ids);
-    }
-
-    /**
-     * {@inheritdoc}
-     */
-    public function save(CacheItemInterface $item)
-    {
-        if (!$item instanceof CacheItem) {
-            return false;
-        }
-        $this->deferred[$item->getKey()] = $item;
-
-        return $this->commit();
-    }
-
-    /**
-     * {@inheritdoc}
-     */
-    public function saveDeferred(CacheItemInterface $item)
-    {
-        if (!$item instanceof CacheItem) {
-            return false;
-        }
-        $this->deferred[$item->getKey()] = $item;
-
-        return true;
-    }
-
-    /**
-     * {@inheritdoc}
+     *
+     * @return bool
      */
     public function commit()
     {
@@ -229,7 +157,12 @@ abstract class AbstractAdapter implements AdapterInterface, LoggerAwareInterface
         $retry = $this->deferred = [];
 
         if ($expiredIds) {
-            $this->doDelete($expiredIds);
+            try {
+                $this->doDelete($expiredIds);
+            } catch (\Exception $e) {
+                $ok = false;
+                CacheItem::log($this->logger, 'Failed to delete expired items: '.$e->getMessage(), ['exception' => $e, 'cache-adapter' => get_debug_type($this)]);
+            }
         }
         foreach ($byLifetime as $lifetime => $values) {
             try {
@@ -244,7 +177,8 @@ abstract class AbstractAdapter implements AdapterInterface, LoggerAwareInterface
                     $ok = false;
                     $v = $values[$id];
                     $type = \is_object($v) ? \get_class($v) : \gettype($v);
-                    CacheItem::log($this->logger, 'Failed to save key "{key}" ({type})', ['key' => substr($id, \strlen($this->namespace)), 'type' => $type, 'exception' => $e instanceof \Exception ? $e : null]);
+                    $message = sprintf('Failed to save key "{key}" of type %s%s', $type, $e instanceof \Exception ? ': '.$e->getMessage() : '.');
+                    CacheItem::log($this->logger, $message, ['key' => substr($id, \strlen($this->namespace)), 'exception' => $e instanceof \Exception ? $e : null]);
                 }
             } else {
                 foreach ($values as $id => $v) {
@@ -266,49 +200,11 @@ abstract class AbstractAdapter implements AdapterInterface, LoggerAwareInterface
                 }
                 $ok = false;
                 $type = \is_object($v) ? \get_class($v) : \gettype($v);
-                CacheItem::log($this->logger, 'Failed to save key "{key}" ({type})', ['key' => substr($id, \strlen($this->namespace)), 'type' => $type, 'exception' => $e instanceof \Exception ? $e : null]);
+                $message = sprintf('Failed to save key "{key}" of type %s%s', $type, $e instanceof \Exception ? ': '.$e->getMessage() : '.');
+                CacheItem::log($this->logger, $message, ['key' => substr($id, \strlen($this->namespace)), 'exception' => $e instanceof \Exception ? $e : null]);
             }
         }
 
         return $ok;
     }
-
-    public function __sleep()
-    {
-        throw new \BadMethodCallException('Cannot serialize '.__CLASS__);
-    }
-
-    public function __wakeup()
-    {
-        throw new \BadMethodCallException('Cannot unserialize '.__CLASS__);
-    }
-
-    public function __destruct()
-    {
-        if ($this->deferred) {
-            $this->commit();
-        }
-    }
-
-    private function generateItems($items, &$keys)
-    {
-        $f = $this->createCacheItem;
-
-        try {
-            foreach ($items as $id => $value) {
-                if (!isset($keys[$id])) {
-                    $id = key($keys);
-                }
-                $key = $keys[$id];
-                unset($keys[$id]);
-                yield $key => $f($key, $value, true);
-            }
-        } catch (\Exception $e) {
-            CacheItem::log($this->logger, 'Failed to fetch requested items', ['keys' => array_values($keys), 'exception' => $e]);
-        }
-
-        foreach ($keys as $key) {
-            yield $key => $f($key, null, false);
-        }
-    }
 }
diff --git a/advancedcontentfilter/vendor/symfony/cache/Adapter/AbstractTagAwareAdapter.php b/advancedcontentfilter/vendor/symfony/cache/Adapter/AbstractTagAwareAdapter.php
new file mode 100644 (file)
index 0000000..6b62ae9
--- /dev/null
@@ -0,0 +1,334 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien@symfony.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Cache\Adapter;
+
+use Psr\Log\LoggerAwareInterface;
+use Symfony\Component\Cache\CacheItem;
+use Symfony\Component\Cache\Exception\InvalidArgumentException;
+use Symfony\Component\Cache\ResettableInterface;
+use Symfony\Component\Cache\Traits\AbstractAdapterTrait;
+use Symfony\Component\Cache\Traits\ContractsTrait;
+use Symfony\Contracts\Cache\TagAwareCacheInterface;
+
+/**
+ * Abstract for native TagAware adapters.
+ *
+ * To keep info on tags, the tags are both serialized as part of cache value and provided as tag ids
+ * to Adapters on operations when needed for storage to doSave(), doDelete() & doInvalidate().
+ *
+ * @author Nicolas Grekas <p@tchwork.com>
+ * @author André Rømcke <andre.romcke+symfony@gmail.com>
+ *
+ * @internal
+ */
+abstract class AbstractTagAwareAdapter implements TagAwareAdapterInterface, TagAwareCacheInterface, LoggerAwareInterface, ResettableInterface
+{
+    use AbstractAdapterTrait;
+    use ContractsTrait;
+
+    private const TAGS_PREFIX = "\0tags\0";
+
+    protected function __construct(string $namespace = '', int $defaultLifetime = 0)
+    {
+        $this->namespace = '' === $namespace ? '' : CacheItem::validateKey($namespace).':';
+        if (null !== $this->maxIdLength && \strlen($namespace) > $this->maxIdLength - 24) {
+            throw new InvalidArgumentException(sprintf('Namespace must be %d chars max, %d given ("%s").', $this->maxIdLength - 24, \strlen($namespace), $namespace));
+        }
+        $this->createCacheItem = \Closure::bind(
+            static function ($key, $value, $isHit) {
+                $item = new CacheItem();
+                $item->key = $key;
+                $item->isTaggable = true;
+                // If structure does not match what we expect return item as is (no value and not a hit)
+                if (!\is_array($value) || !\array_key_exists('value', $value)) {
+                    return $item;
+                }
+                $item->isHit = $isHit;
+                // Extract value, tags and meta data from the cache value
+                $item->value = $value['value'];
+                $item->metadata[CacheItem::METADATA_TAGS] = $value['tags'] ?? [];
+                if (isset($value['meta'])) {
+                    // For compactness these values are packed, & expiry is offset to reduce size
+                    $v = unpack('Ve/Nc', $value['meta']);
+                    $item->metadata[CacheItem::METADATA_EXPIRY] = $v['e'] + CacheItem::METADATA_EXPIRY_OFFSET;
+                    $item->metadata[CacheItem::METADATA_CTIME] = $v['c'];
+                }
+
+                return $item;
+            },
+            null,
+            CacheItem::class
+        );
+        $getId = \Closure::fromCallable([$this, 'getId']);
+        $tagPrefix = self::TAGS_PREFIX;
+        $this->mergeByLifetime = \Closure::bind(
+            static function ($deferred, &$expiredIds) use ($getId, $tagPrefix, $defaultLifetime) {
+                $byLifetime = [];
+                $now = microtime(true);
+                $expiredIds = [];
+
+                foreach ($deferred as $key => $item) {
+                    $key = (string) $key;
+                    if (null === $item->expiry) {
+                        $ttl = 0 < $defaultLifetime ? $defaultLifetime : 0;
+                    } elseif (!$item->expiry) {
+                        $ttl = 0;
+                    } elseif (0 >= $ttl = (int) (0.1 + $item->expiry - $now)) {
+                        $expiredIds[] = $getId($key);
+                        continue;
+                    }
+                    // Store Value and Tags on the cache value
+                    if (isset(($metadata = $item->newMetadata)[CacheItem::METADATA_TAGS])) {
+                        $value = ['value' => $item->value, 'tags' => $metadata[CacheItem::METADATA_TAGS]];
+                        unset($metadata[CacheItem::METADATA_TAGS]);
+                    } else {
+                        $value = ['value' => $item->value, 'tags' => []];
+                    }
+
+                    if ($metadata) {
+                        // For compactness, expiry and creation duration are packed, using magic numbers as separators
+                        $value['meta'] = pack('VN', (int) (0.1 + $metadata[self::METADATA_EXPIRY] - self::METADATA_EXPIRY_OFFSET), $metadata[self::METADATA_CTIME]);
+                    }
+
+                    // Extract tag changes, these should be removed from values in doSave()
+                    $value['tag-operations'] = ['add' => [], 'remove' => []];
+                    $oldTags = $item->metadata[CacheItem::METADATA_TAGS] ?? [];
+                    foreach (array_diff($value['tags'], $oldTags) as $addedTag) {
+                        $value['tag-operations']['add'][] = $getId($tagPrefix.$addedTag);
+                    }
+                    foreach (array_diff($oldTags, $value['tags']) as $removedTag) {
+                        $value['tag-operations']['remove'][] = $getId($tagPrefix.$removedTag);
+                    }
+
+                    $byLifetime[$ttl][$getId($key)] = $value;
+                    $item->metadata = $item->newMetadata;
+                }
+
+                return $byLifetime;
+            },
+            null,
+            CacheItem::class
+        );
+    }
+
+    /**
+     * Persists several cache items immediately.
+     *
+     * @param array   $values        The values to cache, indexed by their cache identifier
+     * @param int     $lifetime      The lifetime of the cached values, 0 for persisting until manual cleaning
+     * @param array[] $addTagData    Hash where key is tag id, and array value is list of cache id's to add to tag
+     * @param array[] $removeTagData Hash where key is tag id, and array value is list of cache id's to remove to tag
+     *
+     * @return array The identifiers that failed to be cached or a boolean stating if caching succeeded or not
+     */
+    abstract protected function doSave(array $values, int $lifetime, array $addTagData = [], array $removeTagData = []): array;
+
+    /**
+     * Removes multiple items from the pool and their corresponding tags.
+     *
+     * @param array $ids An array of identifiers that should be removed from the pool
+     *
+     * @return bool True if the items were successfully removed, false otherwise
+     */
+    abstract protected function doDelete(array $ids);
+
+    /**
+     * Removes relations between tags and deleted items.
+     *
+     * @param array $tagData Array of tag => key identifiers that should be removed from the pool
+     */
+    abstract protected function doDeleteTagRelations(array $tagData): bool;
+
+    /**
+     * Invalidates cached items using tags.
+     *
+     * @param string[] $tagIds An array of tags to invalidate, key is tag and value is tag id
+     *
+     * @return bool True on success
+     */
+    abstract protected function doInvalidate(array $tagIds): bool;
+
+    /**
+     * Delete items and yields the tags they were bound to.
+     */
+    protected function doDeleteYieldTags(array $ids): iterable
+    {
+        foreach ($this->doFetch($ids) as $id => $value) {
+            yield $id => \is_array($value) && \is_array($value['tags'] ?? null) ? $value['tags'] : [];
+        }
+
+        $this->doDelete($ids);
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function commit(): bool
+    {
+        $ok = true;
+        $byLifetime = $this->mergeByLifetime;
+        $byLifetime = $byLifetime($this->deferred, $expiredIds);
+        $retry = $this->deferred = [];
+
+        if ($expiredIds) {
+            // Tags are not cleaned up in this case, however that is done on invalidateTags().
+            try {
+                $this->doDelete($expiredIds);
+            } catch (\Exception $e) {
+                $ok = false;
+                CacheItem::log($this->logger, 'Failed to delete expired items: '.$e->getMessage(), ['exception' => $e, 'cache-adapter' => get_debug_type($this)]);
+            }
+        }
+        foreach ($byLifetime as $lifetime => $values) {
+            try {
+                $values = $this->extractTagData($values, $addTagData, $removeTagData);
+                $e = $this->doSave($values, $lifetime, $addTagData, $removeTagData);
+            } catch (\Exception $e) {
+            }
+            if (true === $e || [] === $e) {
+                continue;
+            }
+            if (\is_array($e) || 1 === \count($values)) {
+                foreach (\is_array($e) ? $e : array_keys($values) as $id) {
+                    $ok = false;
+                    $v = $values[$id];
+                    $type = \is_object($v) ? \get_class($v) : \gettype($v);
+                    $message = sprintf('Failed to save key "{key}" of type %s%s', $type, $e instanceof \Exception ? ': '.$e->getMessage() : '.');
+                    CacheItem::log($this->logger, $message, ['key' => substr($id, \strlen($this->namespace)), 'exception' => $e instanceof \Exception ? $e : null]);
+                }
+            } else {
+                foreach ($values as $id => $v) {
+                    $retry[$lifetime][] = $id;
+                }
+            }
+        }
+
+        // When bulk-save failed, retry each item individually
+        foreach ($retry as $lifetime => $ids) {
+            foreach ($ids as $id) {
+                try {
+                    $v = $byLifetime[$lifetime][$id];
+                    $values = $this->extractTagData([$id => $v], $addTagData, $removeTagData);
+                    $e = $this->doSave($values, $lifetime, $addTagData, $removeTagData);
+                } catch (\Exception $e) {
+                }
+                if (true === $e || [] === $e) {
+                    continue;
+                }
+                $ok = false;
+                $type = \is_object($v) ? \get_class($v) : \gettype($v);
+                $message = sprintf('Failed to save key "{key}" of type %s%s', $type, $e instanceof \Exception ? ': '.$e->getMessage() : '.');
+                CacheItem::log($this->logger, $message, ['key' => substr($id, \strlen($this->namespace)), 'exception' => $e instanceof \Exception ? $e : null]);
+            }
+        }
+
+        return $ok;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function deleteItems(array $keys): bool
+    {
+        if (!$keys) {
+            return true;
+        }
+
+        $ok = true;
+        $ids = [];
+        $tagData = [];
+
+        foreach ($keys as $key) {
+            $ids[$key] = $this->getId($key);
+            unset($this->deferred[$key]);
+        }
+
+        try {
+            foreach ($this->doDeleteYieldTags(array_values($ids)) as $id => $tags) {
+                foreach ($tags as $tag) {
+                    $tagData[$this->getId(self::TAGS_PREFIX.$tag)][] = $id;
+                }
+            }
+        } catch (\Exception $e) {
+            $ok = false;
+        }
+
+        try {
+            if ((!$tagData || $this->doDeleteTagRelations($tagData)) && $ok) {
+                return true;
+            }
+        } catch (\Exception $e) {
+        }
+
+        // When bulk-delete failed, retry each item individually
+        foreach ($ids as $key => $id) {
+            try {
+                $e = null;
+                if ($this->doDelete([$id])) {
+                    continue;
+                }
+            } catch (\Exception $e) {
+            }
+            $message = 'Failed to delete key "{key}"'.($e instanceof \Exception ? ': '.$e->getMessage() : '.');
+            CacheItem::log($this->logger, $message, ['key' => $key, 'exception' => $e]);
+            $ok = false;
+        }
+
+        return $ok;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function invalidateTags(array $tags)
+    {
+        if (empty($tags)) {
+            return false;
+        }
+
+        $tagIds = [];
+        foreach (array_unique($tags) as $tag) {
+            $tagIds[] = $this->getId(self::TAGS_PREFIX.$tag);
+        }
+
+        try {
+            if ($this->doInvalidate($tagIds)) {
+                return true;
+            }
+        } catch (\Exception $e) {
+            CacheItem::log($this->logger, 'Failed to invalidate tags: '.$e->getMessage(), ['exception' => $e, 'cache-adapter' => get_debug_type($this)]);
+        }
+
+        return false;
+    }
+
+    /**
+     * Extracts tags operation data from $values set in mergeByLifetime, and returns values without it.
+     */
+    private function extractTagData(array $values, ?array &$addTagData, ?array &$removeTagData): array
+    {
+        $addTagData = $removeTagData = [];
+        foreach ($values as $id => $value) {
+            foreach ($value['tag-operations']['add'] as $tag => $tagId) {
+                $addTagData[$tagId][] = $id;
+            }
+
+            foreach ($value['tag-operations']['remove'] as $tag => $tagId) {
+                $removeTagData[$tagId][] = $id;
+            }
+
+            unset($values[$id]['tag-operations']);
+        }
+
+        return $values;
+    }
+}
index 85fe07684fb3cd7b2fa6746648d6b5ec7bc78802..9e359e17e0a870ee1c63c644df7f64aadda6175d 100644 (file)
@@ -14,6 +14,9 @@ namespace Symfony\Component\Cache\Adapter;
 use Psr\Cache\CacheItemPoolInterface;
 use Symfony\Component\Cache\CacheItem;
 
+// Help opcache.preload discover always-needed symbols
+class_exists(CacheItem::class);
+
 /**
  * Interface for adapters managing instances of Symfony's CacheItem.
  *
@@ -34,4 +37,13 @@ interface AdapterInterface extends CacheItemPoolInterface
      * @return \Traversable|CacheItem[]
      */
     public function getItems(array $keys = []);
+
+    /**
+     * {@inheritdoc}
+     *
+     * @param string $prefix
+     *
+     * @return bool
+     */
+    public function clear(/* string $prefix = '' */);
 }
index 50554ed688309f2fd27a35a0d4764275b7d10f5e..7db39565880267134d57f150e5545219b87fa8cf 100644 (file)
@@ -18,13 +18,9 @@ class ApcuAdapter extends AbstractAdapter
     use ApcuTrait;
 
     /**
-     * @param string      $namespace
-     * @param int         $defaultLifetime
-     * @param string|null $version
-     *
      * @throws CacheException if APCu is not enabled
      */
-    public function __construct($namespace = '', $defaultLifetime = 0, $version = null)
+    public function __construct(string $namespace = '', int $defaultLifetime = 0, string $version = null)
     {
         $this->init($namespace, $defaultLifetime, $version);
     }
index 33f55a869fcf537c0692ec6d004f961002400409..20043dec18c5e27d5cead77f3dab014de01e6474 100644 (file)
@@ -16,11 +16,12 @@ use Psr\Log\LoggerAwareInterface;
 use Symfony\Component\Cache\CacheItem;
 use Symfony\Component\Cache\ResettableInterface;
 use Symfony\Component\Cache\Traits\ArrayTrait;
+use Symfony\Contracts\Cache\CacheInterface;
 
 /**
  * @author Nicolas Grekas <p@tchwork.com>
  */
-class ArrayAdapter implements AdapterInterface, LoggerAwareInterface, ResettableInterface
+class ArrayAdapter implements AdapterInterface, CacheInterface, LoggerAwareInterface, ResettableInterface
 {
     use ArrayTrait;
 
@@ -28,10 +29,9 @@ class ArrayAdapter implements AdapterInterface, LoggerAwareInterface, Resettable
     private $defaultLifetime;
 
     /**
-     * @param int  $defaultLifetime
      * @param bool $storeSerialized Disabling serialization can lead to cache corruptions when storing mutable values but increases performance otherwise
      */
-    public function __construct($defaultLifetime = 0, $storeSerialized = true)
+    public function __construct(int $defaultLifetime = 0, bool $storeSerialized = true)
     {
         $this->defaultLifetime = $defaultLifetime;
         $this->storeSerialized = $storeSerialized;
@@ -52,24 +52,32 @@ class ArrayAdapter implements AdapterInterface, LoggerAwareInterface, Resettable
     /**
      * {@inheritdoc}
      */
-    public function getItem($key)
+    public function get(string $key, callable $callback, float $beta = null, array &$metadata = null)
     {
-        $isHit = $this->hasItem($key);
-        try {
-            if (!$isHit) {
-                $this->values[$key] = $value = null;
-            } elseif (!$this->storeSerialized) {
-                $value = $this->values[$key];
-            } elseif ('b:0;' === $value = $this->values[$key]) {
-                $value = false;
-            } elseif (false === $value = unserialize($value)) {
-                $this->values[$key] = $value = null;
-                $isHit = false;
+        $item = $this->getItem($key);
+        $metadata = $item->getMetadata();
+
+        // ArrayAdapter works in memory, we don't care about stampede protection
+        if (\INF === $beta || !$item->isHit()) {
+            $save = true;
+            $item->set($callback($item, $save));
+            if ($save) {
+                $this->save($item);
             }
-        } catch (\Exception $e) {
-            CacheItem::log($this->logger, 'Failed to unserialize key "{key}"', ['key' => $key, 'exception' => $e]);
+        }
+
+        return $item->get();
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function getItem($key)
+    {
+        if (!$isHit = $this->hasItem($key)) {
             $this->values[$key] = $value = null;
-            $isHit = false;
+        } else {
+            $value = $this->storeSerialized ? $this->unfreeze($key, $isHit) : $this->values[$key];
         }
         $f = $this->createCacheItem;
 
@@ -82,14 +90,18 @@ class ArrayAdapter implements AdapterInterface, LoggerAwareInterface, Resettable
     public function getItems(array $keys = [])
     {
         foreach ($keys as $key) {
-            CacheItem::validateKey($key);
+            if (!\is_string($key) || !isset($this->expiries[$key])) {
+                CacheItem::validateKey($key);
+            }
         }
 
-        return $this->generateItems($keys, time(), $this->createCacheItem);
+        return $this->generateItems($keys, microtime(true), $this->createCacheItem);
     }
 
     /**
      * {@inheritdoc}
+     *
+     * @return bool
      */
     public function deleteItems(array $keys)
     {
@@ -102,6 +114,8 @@ class ArrayAdapter implements AdapterInterface, LoggerAwareInterface, Resettable
 
     /**
      * {@inheritdoc}
+     *
+     * @return bool
      */
     public function save(CacheItemInterface $item)
     {
@@ -113,37 +127,32 @@ class ArrayAdapter implements AdapterInterface, LoggerAwareInterface, Resettable
         $value = $item["\0*\0value"];
         $expiry = $item["\0*\0expiry"];
 
-        if (0 === $expiry) {
-            $expiry = \PHP_INT_MAX;
-        }
+        if (null !== $expiry) {
+            if (!$expiry) {
+                $expiry = \PHP_INT_MAX;
+            } elseif ($expiry <= microtime(true)) {
+                $this->deleteItem($key);
 
-        if (null !== $expiry && $expiry <= time()) {
-            $this->deleteItem($key);
-
-            return true;
-        }
-        if ($this->storeSerialized) {
-            try {
-                $value = serialize($value);
-            } catch (\Exception $e) {
-                $type = \is_object($value) ? \get_class($value) : \gettype($value);
-                CacheItem::log($this->logger, 'Failed to save key "{key}" ({type})', ['key' => $key, 'type' => $type, 'exception' => $e]);
-
-                return false;
+                return true;
             }
         }
+        if ($this->storeSerialized && null === $value = $this->freeze($value, $key)) {
+            return false;
+        }
         if (null === $expiry && 0 < $this->defaultLifetime) {
-            $expiry = time() + $this->defaultLifetime;
+            $expiry = microtime(true) + $this->defaultLifetime;
         }
 
         $this->values[$key] = $value;
-        $this->expiries[$key] = null !== $expiry ? $expiry : \PHP_INT_MAX;
+        $this->expiries[$key] = $expiry ?? \PHP_INT_MAX;
 
         return true;
     }
 
     /**
      * {@inheritdoc}
+     *
+     * @return bool
      */
     public function saveDeferred(CacheItemInterface $item)
     {
@@ -152,9 +161,19 @@ class ArrayAdapter implements AdapterInterface, LoggerAwareInterface, Resettable
 
     /**
      * {@inheritdoc}
+     *
+     * @return bool
      */
     public function commit()
     {
         return true;
     }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function delete(string $key): bool
+    {
+        return $this->deleteItem($key);
+    }
 }
index fdb28846f1629a8c61ca271f88b8278ce343035e..57fb096bff37773ff5510ce7dadc5dbd439d8887 100644 (file)
@@ -17,6 +17,9 @@ use Symfony\Component\Cache\CacheItem;
 use Symfony\Component\Cache\Exception\InvalidArgumentException;
 use Symfony\Component\Cache\PruneableInterface;
 use Symfony\Component\Cache\ResettableInterface;
+use Symfony\Component\Cache\Traits\ContractsTrait;
+use Symfony\Contracts\Cache\CacheInterface;
+use Symfony\Contracts\Service\ResetInterface;
 
 /**
  * Chains several adapters together.
@@ -26,8 +29,10 @@ use Symfony\Component\Cache\ResettableInterface;
  *
  * @author Kévin Dunglas <dunglas@gmail.com>
  */
-class ChainAdapter implements AdapterInterface, PruneableInterface, ResettableInterface
+class ChainAdapter implements AdapterInterface, CacheInterface, PruneableInterface, ResettableInterface
 {
+    use ContractsTrait;
+
     private $adapters = [];
     private $adapterCount;
     private $syncItem;
@@ -36,7 +41,7 @@ class ChainAdapter implements AdapterInterface, PruneableInterface, ResettableIn
      * @param CacheItemPoolInterface[] $adapters        The ordered list of adapters used to fetch cached items
      * @param int                      $defaultLifetime The default lifetime of items propagated from lower adapters to upper ones
      */
-    public function __construct(array $adapters, $defaultLifetime = 0)
+    public function __construct(array $adapters, int $defaultLifetime = 0)
     {
         if (!$adapters) {
             throw new InvalidArgumentException('At least one adapter must be specified.');
@@ -46,7 +51,7 @@ class ChainAdapter implements AdapterInterface, PruneableInterface, ResettableIn
             if (!$adapter instanceof CacheItemPoolInterface) {
                 throw new InvalidArgumentException(sprintf('The class "%s" does not implement the "%s" interface.', \get_class($adapter), CacheItemPoolInterface::class));
             }
-            if (\in_array(\PHP_SAPI, ['cli', 'phpdbg'], true) && $adapter instanceof ApcuAdapter && !filter_var(ini_get('apc.enable_cli'), \FILTER_VALIDATE_BOOLEAN)) {
+            if (\in_array(\PHP_SAPI, ['cli', 'phpdbg'], true) && $adapter instanceof ApcuAdapter && !filter_var(\ini_get('apc.enable_cli'), \FILTER_VALIDATE_BOOLEAN)) {
                 continue; // skip putting APCu in the chain when the backend is disabled
             }
 
@@ -59,11 +64,18 @@ class ChainAdapter implements AdapterInterface, PruneableInterface, ResettableIn
         $this->adapterCount = \count($this->adapters);
 
         $this->syncItem = \Closure::bind(
-            static function ($sourceItem, $item) use ($defaultLifetime) {
+            static function ($sourceItem, $item, $sourceMetadata = null) use ($defaultLifetime) {
+                $sourceItem->isTaggable = false;
+                $sourceMetadata = $sourceMetadata ?? $sourceItem->metadata;
+                unset($sourceMetadata[CacheItem::METADATA_TAGS]);
+
                 $item->value = $sourceItem->value;
                 $item->isHit = $sourceItem->isHit;
+                $item->metadata = $item->newMetadata = $sourceItem->metadata = $sourceMetadata;
 
-                if (0 < $defaultLifetime) {
+                if (isset($item->metadata[CacheItem::METADATA_EXPIRY])) {
+                    $item->expiresAt(\DateTime::createFromFormat('U.u', sprintf('%.6F', $item->metadata[CacheItem::METADATA_EXPIRY])));
+                } elseif (0 < $defaultLifetime) {
                     $item->expiresAfter($defaultLifetime);
                 }
 
@@ -74,6 +86,43 @@ class ChainAdapter implements AdapterInterface, PruneableInterface, ResettableIn
         );
     }
 
+    /**
+     * {@inheritdoc}
+     */
+    public function get(string $key, callable $callback, float $beta = null, array &$metadata = null)
+    {
+        $doSave = true;
+        $callback = static function (CacheItem $item, bool &$save) use ($callback, &$doSave) {
+            $value = $callback($item, $save);
+            $doSave = $save;
+
+            return $value;
+        };
+
+        $lastItem = null;
+        $i = 0;
+        $wrap = function (CacheItem $item = null, bool &$save = true) use ($key, $callback, $beta, &$wrap, &$i, &$doSave, &$lastItem, &$metadata) {
+            $adapter = $this->adapters[$i];
+            if (isset($this->adapters[++$i])) {
+                $callback = $wrap;
+                $beta = \INF === $beta ? \INF : 0;
+            }
+            if ($adapter instanceof CacheInterface) {
+                $value = $adapter->get($key, $callback, $beta, $metadata);
+            } else {
+                $value = $this->doGet($adapter, $key, $callback, $beta, $metadata);
+            }
+            if (null !== $item) {
+                ($this->syncItem)($lastItem = $lastItem ?? $item, $item, $metadata);
+            }
+            $save = $doSave;
+
+            return $value;
+        };
+
+        return $wrap();
+    }
+
     /**
      * {@inheritdoc}
      */
@@ -107,12 +156,12 @@ class ChainAdapter implements AdapterInterface, PruneableInterface, ResettableIn
         return $this->generateItems($this->adapters[0]->getItems($keys), 0);
     }
 
-    private function generateItems($items, $adapterIndex)
+    private function generateItems(iterable $items, int $adapterIndex)
     {
         $missing = [];
         $misses = [];
         $nextAdapterIndex = $adapterIndex + 1;
-        $nextAdapter = isset($this->adapters[$nextAdapterIndex]) ? $this->adapters[$nextAdapterIndex] : null;
+        $nextAdapter = $this->adapters[$nextAdapterIndex] ?? null;
 
         foreach ($items as $k => $item) {
             if (!$nextAdapter || $item->isHit()) {
@@ -140,6 +189,8 @@ class ChainAdapter implements AdapterInterface, PruneableInterface, ResettableIn
 
     /**
      * {@inheritdoc}
+     *
+     * @return bool
      */
     public function hasItem($key)
     {
@@ -154,14 +205,23 @@ class ChainAdapter implements AdapterInterface, PruneableInterface, ResettableIn
 
     /**
      * {@inheritdoc}
+     *
+     * @param string $prefix
+     *
+     * @return bool
      */
-    public function clear()
+    public function clear(/* string $prefix = '' */)
     {
+        $prefix = 0 < \func_num_args() ? (string) func_get_arg(0) : '';
         $cleared = true;
         $i = $this->adapterCount;
 
         while ($i--) {
-            $cleared = $this->adapters[$i]->clear() && $cleared;
+            if ($this->adapters[$i] instanceof AdapterInterface) {
+                $cleared = $this->adapters[$i]->clear($prefix) && $cleared;
+            } else {
+                $cleared = $this->adapters[$i]->clear() && $cleared;
+            }
         }
 
         return $cleared;
@@ -169,6 +229,8 @@ class ChainAdapter implements AdapterInterface, PruneableInterface, ResettableIn
 
     /**
      * {@inheritdoc}
+     *
+     * @return bool
      */
     public function deleteItem($key)
     {
@@ -184,6 +246,8 @@ class ChainAdapter implements AdapterInterface, PruneableInterface, ResettableIn
 
     /**
      * {@inheritdoc}
+     *
+     * @return bool
      */
     public function deleteItems(array $keys)
     {
@@ -199,6 +263,8 @@ class ChainAdapter implements AdapterInterface, PruneableInterface, ResettableIn
 
     /**
      * {@inheritdoc}
+     *
+     * @return bool
      */
     public function save(CacheItemInterface $item)
     {
@@ -214,6 +280,8 @@ class ChainAdapter implements AdapterInterface, PruneableInterface, ResettableIn
 
     /**
      * {@inheritdoc}
+     *
+     * @return bool
      */
     public function saveDeferred(CacheItemInterface $item)
     {
@@ -229,6 +297,8 @@ class ChainAdapter implements AdapterInterface, PruneableInterface, ResettableIn
 
     /**
      * {@inheritdoc}
+     *
+     * @return bool
      */
     public function commit()
     {
@@ -264,7 +334,7 @@ class ChainAdapter implements AdapterInterface, PruneableInterface, ResettableIn
     public function reset()
     {
         foreach ($this->adapters as $adapter) {
-            if ($adapter instanceof ResettableInterface) {
+            if ($adapter instanceof ResetInterface) {
                 $adapter->reset();
             }
         }
index 8081d7dc32a566f20125f9147bbe965ee76bac8a..75ae4cb7015c81057766651b0045e809ab282153 100644 (file)
@@ -18,11 +18,7 @@ class DoctrineAdapter extends AbstractAdapter
 {
     use DoctrineTrait;
 
-    /**
-     * @param string $namespace
-     * @param int    $defaultLifetime
-     */
-    public function __construct(CacheProvider $provider, $namespace = '', $defaultLifetime = 0)
+    public function __construct(CacheProvider $provider, string $namespace = '', int $defaultLifetime = 0)
     {
         parent::__construct('', $defaultLifetime);
         $this->provider = $provider;
index d071964ec2c5cf0bc8e44a57e7f3dcdc916d2557..7185dd4877e423ad5adc99f2ac07bcdbd5be2428 100644 (file)
@@ -11,6 +11,8 @@
 
 namespace Symfony\Component\Cache\Adapter;
 
+use Symfony\Component\Cache\Marshaller\DefaultMarshaller;
+use Symfony\Component\Cache\Marshaller\MarshallerInterface;
 use Symfony\Component\Cache\PruneableInterface;
 use Symfony\Component\Cache\Traits\FilesystemTrait;
 
@@ -18,13 +20,9 @@ class FilesystemAdapter extends AbstractAdapter implements PruneableInterface
 {
     use FilesystemTrait;
 
-    /**
-     * @param string      $namespace
-     * @param int         $defaultLifetime
-     * @param string|null $directory
-     */
-    public function __construct($namespace = '', $defaultLifetime = 0, $directory = null)
+    public function __construct(string $namespace = '', int $defaultLifetime = 0, string $directory = null, MarshallerInterface $marshaller = null)
     {
+        $this->marshaller = $marshaller ?? new DefaultMarshaller();
         parent::__construct('', $defaultLifetime);
         $this->init($namespace, $directory);
     }
diff --git a/advancedcontentfilter/vendor/symfony/cache/Adapter/FilesystemTagAwareAdapter.php b/advancedcontentfilter/vendor/symfony/cache/Adapter/FilesystemTagAwareAdapter.php
new file mode 100644 (file)
index 0000000..6dccbf0
--- /dev/null
@@ -0,0 +1,239 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien@symfony.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Cache\Adapter;
+
+use Symfony\Component\Cache\Marshaller\MarshallerInterface;
+use Symfony\Component\Cache\Marshaller\TagAwareMarshaller;
+use Symfony\Component\Cache\PruneableInterface;
+use Symfony\Component\Cache\Traits\FilesystemTrait;
+
+/**
+ * Stores tag id <> cache id relationship as a symlink, and lookup on invalidation calls.
+ *
+ * @author Nicolas Grekas <p@tchwork.com>
+ * @author André Rømcke <andre.romcke+symfony@gmail.com>
+ */
+class FilesystemTagAwareAdapter extends AbstractTagAwareAdapter implements PruneableInterface
+{
+    use FilesystemTrait {
+        doClear as private doClearCache;
+        doSave as private doSaveCache;
+    }
+
+    /**
+     * Folder used for tag symlinks.
+     */
+    private const TAG_FOLDER = 'tags';
+
+    public function __construct(string $namespace = '', int $defaultLifetime = 0, string $directory = null, MarshallerInterface $marshaller = null)
+    {
+        $this->marshaller = new TagAwareMarshaller($marshaller);
+        parent::__construct('', $defaultLifetime);
+        $this->init($namespace, $directory);
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    protected function doClear($namespace)
+    {
+        $ok = $this->doClearCache($namespace);
+
+        if ('' !== $namespace) {
+            return $ok;
+        }
+
+        set_error_handler(static function () {});
+        $chars = '+-ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
+
+        try {
+            foreach ($this->scanHashDir($this->directory.self::TAG_FOLDER.\DIRECTORY_SEPARATOR) as $dir) {
+                if (rename($dir, $renamed = substr_replace($dir, bin2hex(random_bytes(4)), -8))) {
+                    $dir = $renamed.\DIRECTORY_SEPARATOR;
+                } else {
+                    $dir .= \DIRECTORY_SEPARATOR;
+                    $renamed = null;
+                }
+
+                for ($i = 0; $i < 38; ++$i) {
+                    if (!file_exists($dir.$chars[$i])) {
+                        continue;
+                    }
+                    for ($j = 0; $j < 38; ++$j) {
+                        if (!file_exists($d = $dir.$chars[$i].\DIRECTORY_SEPARATOR.$chars[$j])) {
+                            continue;
+                        }
+                        foreach (scandir($d, \SCANDIR_SORT_NONE) ?: [] as $link) {
+                            if ('.' !== $link && '..' !== $link && (null !== $renamed || !realpath($d.\DIRECTORY_SEPARATOR.$link))) {
+                                unlink($d.\DIRECTORY_SEPARATOR.$link);
+                            }
+                        }
+                        null === $renamed ?: rmdir($d);
+                    }
+                    null === $renamed ?: rmdir($dir.$chars[$i]);
+                }
+                null === $renamed ?: rmdir($renamed);
+            }
+        } finally {
+            restore_error_handler();
+        }
+
+        return $ok;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    protected function doSave(array $values, int $lifetime, array $addTagData = [], array $removeTagData = []): array
+    {
+        $failed = $this->doSaveCache($values, $lifetime);
+
+        // Add Tags as symlinks
+        foreach ($addTagData as $tagId => $ids) {
+            $tagFolder = $this->getTagFolder($tagId);
+            foreach ($ids as $id) {
+                if ($failed && \in_array($id, $failed, true)) {
+                    continue;
+                }
+
+                $file = $this->getFile($id);
+
+                if (!@symlink($file, $tagLink = $this->getFile($id, true, $tagFolder)) && !is_link($tagLink)) {
+                    @unlink($file);
+                    $failed[] = $id;
+                }
+            }
+        }
+
+        // Unlink removed Tags
+        foreach ($removeTagData as $tagId => $ids) {
+            $tagFolder = $this->getTagFolder($tagId);
+            foreach ($ids as $id) {
+                if ($failed && \in_array($id, $failed, true)) {
+                    continue;
+                }
+
+                @unlink($this->getFile($id, false, $tagFolder));
+            }
+        }
+
+        return $failed;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    protected function doDeleteYieldTags(array $ids): iterable
+    {
+        foreach ($ids as $id) {
+            $file = $this->getFile($id);
+            if (!file_exists($file) || !$h = @fopen($file, 'r')) {
+                continue;
+            }
+
+            if ((\PHP_VERSION_ID >= 70300 || '\\' !== \DIRECTORY_SEPARATOR) && !@unlink($file)) {
+                fclose($h);
+                continue;
+            }
+
+            $meta = explode("\n", fread($h, 4096), 3)[2] ?? '';
+
+            // detect the compact format used in marshall() using magic numbers in the form 9D-..-..-..-..-00-..-..-..-5F
+            if (13 < \strlen($meta) && "\x9D" === $meta[0] && "\0" === $meta[5] && "\x5F" === $meta[9]) {
+                $meta[9] = "\0";
+                $tagLen = unpack('Nlen', $meta, 9)['len'];
+                $meta = substr($meta, 13, $tagLen);
+
+                if (0 < $tagLen -= \strlen($meta)) {
+                    $meta .= fread($h, $tagLen);
+                }
+
+                try {
+                    yield $id => '' === $meta ? [] : $this->marshaller->unmarshall($meta);
+                } catch (\Exception $e) {
+                    yield $id => [];
+                }
+            }
+
+            fclose($h);
+
+            if (\PHP_VERSION_ID < 70300 && '\\' === \DIRECTORY_SEPARATOR) {
+                @unlink($file);
+            }
+        }
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    protected function doDeleteTagRelations(array $tagData): bool
+    {
+        foreach ($tagData as $tagId => $idList) {
+            $tagFolder = $this->getTagFolder($tagId);
+            foreach ($idList as $id) {
+                @unlink($this->getFile($id, false, $tagFolder));
+            }
+        }
+
+        return true;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    protected function doInvalidate(array $tagIds): bool
+    {
+        foreach ($tagIds as $tagId) {
+            if (!file_exists($tagFolder = $this->getTagFolder($tagId))) {
+                continue;
+            }
+
+            set_error_handler(static function () {});
+
+            try {
+                if (rename($tagFolder, $renamed = substr_replace($tagFolder, bin2hex(random_bytes(4)), -9))) {
+                    $tagFolder = $renamed.\DIRECTORY_SEPARATOR;
+                } else {
+                    $renamed = null;
+                }
+
+                foreach ($this->scanHashDir($tagFolder) as $itemLink) {
+                    unlink(realpath($itemLink) ?: $itemLink);
+                    unlink($itemLink);
+                }
+
+                if (null === $renamed) {
+                    continue;
+                }
+
+                $chars = '+-ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
+
+                for ($i = 0; $i < 38; ++$i) {
+                    for ($j = 0; $j < 38; ++$j) {
+                        rmdir($tagFolder.$chars[$i].\DIRECTORY_SEPARATOR.$chars[$j]);
+                    }
+                    rmdir($tagFolder.$chars[$i]);
+                }
+                rmdir($renamed);
+            } finally {
+                restore_error_handler();
+            }
+        }
+
+        return true;
+    }
+
+    private function getTagFolder(string $tagId): string
+    {
+        return $this->getFile($tagId, false, $this->directory.self::TAG_FOLDER.\DIRECTORY_SEPARATOR).\DIRECTORY_SEPARATOR;
+    }
+}
index 5637141a77a89d5dc1525772e4c2958358b642fb..b678bb5d8883ed932028c54198d80d8b8b187879 100644 (file)
@@ -11,6 +11,7 @@
 
 namespace Symfony\Component\Cache\Adapter;
 
+use Symfony\Component\Cache\Marshaller\MarshallerInterface;
 use Symfony\Component\Cache\Traits\MemcachedTrait;
 
 class MemcachedAdapter extends AbstractAdapter
@@ -29,8 +30,8 @@ class MemcachedAdapter extends AbstractAdapter
      *
      * Using a MemcachedAdapter as a pure items store is fine.
      */
-    public function __construct(\Memcached $client, $namespace = '', $defaultLifetime = 0)
+    public function __construct(\Memcached $client, string $namespace = '', int $defaultLifetime = 0, MarshallerInterface $marshaller = null)
     {
-        $this->init($client, $namespace, $defaultLifetime);
+        $this->init($client, $namespace, $defaultLifetime, $marshaller);
     }
 }
index c81a1cd64661001167b075a5269dc7c98d2fa413..3c2979bd2a5ad0a6eafc41e002c3790958d7e74d 100644 (file)
@@ -13,11 +13,12 @@ namespace Symfony\Component\Cache\Adapter;
 
 use Psr\Cache\CacheItemInterface;
 use Symfony\Component\Cache\CacheItem;
+use Symfony\Contracts\Cache\CacheInterface;
 
 /**
  * @author Titouan Galopin <galopintitouan@gmail.com>
  */
-class NullAdapter implements AdapterInterface
+class NullAdapter implements AdapterInterface, CacheInterface
 {
     private $createCacheItem;
 
@@ -36,6 +37,16 @@ class NullAdapter implements AdapterInterface
         );
     }
 
+    /**
+     * {@inheritdoc}
+     */
+    public function get(string $key, callable $callback, float $beta = null, array &$metadata = null)
+    {
+        $save = true;
+
+        return $callback(($this->createCacheItem)($key), $save);
+    }
+
     /**
      * {@inheritdoc}
      */
@@ -56,6 +67,8 @@ class NullAdapter implements AdapterInterface
 
     /**
      * {@inheritdoc}
+     *
+     * @return bool
      */
     public function hasItem($key)
     {
@@ -64,14 +77,20 @@ class NullAdapter implements AdapterInterface
 
     /**
      * {@inheritdoc}
+     *
+     * @param string $prefix
+     *
+     * @return bool
      */
-    public function clear()
+    public function clear(/* string $prefix = '' */)
     {
         return true;
     }
 
     /**
      * {@inheritdoc}
+     *
+     * @return bool
      */
     public function deleteItem($key)
     {
@@ -80,6 +99,8 @@ class NullAdapter implements AdapterInterface
 
     /**
      * {@inheritdoc}
+     *
+     * @return bool
      */
     public function deleteItems(array $keys)
     {
@@ -88,26 +109,40 @@ class NullAdapter implements AdapterInterface
 
     /**
      * {@inheritdoc}
+     *
+     * @return bool
      */
     public function save(CacheItemInterface $item)
     {
-        return false;
+        return true;
     }
 
     /**
      * {@inheritdoc}
+     *
+     * @return bool
      */
     public function saveDeferred(CacheItemInterface $item)
     {
-        return false;
+        return true;
     }
 
     /**
      * {@inheritdoc}
+     *
+     * @return bool
      */
     public function commit()
     {
-        return false;
+        return true;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function delete(string $key): bool
+    {
+        return $this->deleteItem($key);
     }
 
     private function generateItems(array $keys)
index 5903867942577df1082d4c9d11539283c4ba51cb..d118736aec067db83a1d71524027463a945c4cf6 100644 (file)
@@ -13,6 +13,7 @@ namespace Symfony\Component\Cache\Adapter;
 
 use Doctrine\DBAL\Connection;
 use Symfony\Component\Cache\Exception\InvalidArgumentException;
+use Symfony\Component\Cache\Marshaller\MarshallerInterface;
 use Symfony\Component\Cache\PruneableInterface;
 use Symfony\Component\Cache\Traits\PdoTrait;
 
@@ -27,6 +28,9 @@ class PdoAdapter extends AbstractAdapter implements PruneableInterface
      * a Doctrine DBAL Connection or a DSN string that will be used to
      * lazy-connect to the database when the cache is actually used.
      *
+     * When a Doctrine DBAL Connection is passed, the cache table is created
+     * automatically when possible. Otherwise, use the createTable() method.
+     *
      * List of available options:
      *  * db_table: The name of the table [default: cache_items]
      *  * db_id_col: The column where to store the cache id [default: item_id]
@@ -37,17 +41,14 @@ class PdoAdapter extends AbstractAdapter implements PruneableInterface
      *  * db_password: The password when lazy-connect [default: '']
      *  * db_connection_options: An array of driver-specific connection options [default: []]
      *
-     * @param \PDO|Connection|string $connOrDsn       A \PDO or Connection instance or DSN string or null
-     * @param string                 $namespace
-     * @param int                    $defaultLifetime
-     * @param array                  $options         An associative array of options
+     * @param \PDO|Connection|string $connOrDsn a \PDO or Connection instance or DSN string or null
      *
      * @throws InvalidArgumentException When first argument is not PDO nor Connection nor string
      * @throws InvalidArgumentException When PDO error mode is not PDO::ERRMODE_EXCEPTION
      * @throws InvalidArgumentException When namespace contains invalid characters
      */
-    public function __construct($connOrDsn, $namespace = '', $defaultLifetime = 0, array $options = [])
+    public function __construct($connOrDsn, string $namespace = '', int $defaultLifetime = 0, array $options = [], MarshallerInterface $marshaller = null)
     {
-        $this->init($connOrDsn, $namespace, $defaultLifetime, $options);
+        $this->init($connOrDsn, $namespace, $defaultLifetime, $options, $marshaller);
     }
 }
index 47a259c136fa2d65183aebb06070f02cc8f4730a..bdce6e1a24592bc744c2fbd219693b3c1685dadd 100644 (file)
@@ -17,7 +17,9 @@ use Symfony\Component\Cache\CacheItem;
 use Symfony\Component\Cache\Exception\InvalidArgumentException;
 use Symfony\Component\Cache\PruneableInterface;
 use Symfony\Component\Cache\ResettableInterface;
+use Symfony\Component\Cache\Traits\ContractsTrait;
 use Symfony\Component\Cache\Traits\PhpArrayTrait;
+use Symfony\Contracts\Cache\CacheInterface;
 
 /**
  * Caches items at warm up time using a PHP array that is stored in shared memory by OPCache since PHP 7.0.
@@ -26,8 +28,9 @@ use Symfony\Component\Cache\Traits\PhpArrayTrait;
  * @author Titouan Galopin <galopintitouan@gmail.com>
  * @author Nicolas Grekas <p@tchwork.com>
  */
-class PhpArrayAdapter implements AdapterInterface, PruneableInterface, ResettableInterface
+class PhpArrayAdapter implements AdapterInterface, CacheInterface, PruneableInterface, ResettableInterface
 {
+    use ContractsTrait;
     use PhpArrayTrait;
 
     private $createCacheItem;
@@ -36,11 +39,10 @@ class PhpArrayAdapter implements AdapterInterface, PruneableInterface, Resettabl
      * @param string           $file         The PHP file were values are cached
      * @param AdapterInterface $fallbackPool A pool to fallback on when an item is not hit
      */
-    public function __construct($file, AdapterInterface $fallbackPool)
+    public function __construct(string $file, AdapterInterface $fallbackPool)
     {
         $this->file = $file;
         $this->pool = $fallbackPool;
-        $this->zendDetectUnicode = filter_var(ini_get('zend.detect_unicode'), \FILTER_VALIDATE_BOOLEAN);
         $this->createCacheItem = \Closure::bind(
             static function ($key, $value, $isHit) {
                 $item = new CacheItem();
@@ -56,9 +58,7 @@ class PhpArrayAdapter implements AdapterInterface, PruneableInterface, Resettabl
     }
 
     /**
-     * This adapter should only be used on PHP 7.0+ to take advantage of how PHP
-     * stores arrays in its latest versions. This factory method decorates the given
-     * fallback pool with this adapter only if the current PHP version is supported.
+     * This adapter takes advantage of how PHP stores arrays in its latest versions.
      *
      * @param string                 $file         The PHP file were values are cached
      * @param CacheItemPoolInterface $fallbackPool A pool to fallback on when an item is not hit
@@ -67,15 +67,44 @@ class PhpArrayAdapter implements AdapterInterface, PruneableInterface, Resettabl
      */
     public static function create($file, CacheItemPoolInterface $fallbackPool)
     {
-        if (\PHP_VERSION_ID >= 70000) {
-            if (!$fallbackPool instanceof AdapterInterface) {
-                $fallbackPool = new ProxyAdapter($fallbackPool);
+        if (!$fallbackPool instanceof AdapterInterface) {
+            $fallbackPool = new ProxyAdapter($fallbackPool);
+        }
+
+        return new static($file, $fallbackPool);
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function get(string $key, callable $callback, float $beta = null, array &$metadata = null)
+    {
+        if (null === $this->values) {
+            $this->initialize();
+        }
+        if (!isset($this->keys[$key])) {
+            get_from_pool:
+            if ($this->pool instanceof CacheInterface) {
+                return $this->pool->get($key, $callback, $beta, $metadata);
             }
 
-            return new static($file, $fallbackPool);
+            return $this->doGet($this->pool, $key, $callback, $beta, $metadata);
         }
+        $value = $this->values[$this->keys[$key]];
 
-        return $fallbackPool;
+        if ('N;' === $value) {
+            return null;
+        }
+        try {
+            if ($value instanceof \Closure) {
+                return $value();
+            }
+        } catch (\Throwable $e) {
+            unset($this->keys[$key]);
+            goto get_from_pool;
+        }
+
+        return $value;
     }
 
     /**
@@ -89,23 +118,19 @@ class PhpArrayAdapter implements AdapterInterface, PruneableInterface, Resettabl
         if (null === $this->values) {
             $this->initialize();
         }
-        if (!isset($this->values[$key])) {
+        if (!isset($this->keys[$key])) {
             return $this->pool->getItem($key);
         }
 
-        $value = $this->values[$key];
+        $value = $this->values[$this->keys[$key]];
         $isHit = true;
 
         if ('N;' === $value) {
             $value = null;
-        } elseif (\is_string($value) && isset($value[2]) && ':' === $value[1]) {
+        } elseif ($value instanceof \Closure) {
             try {
-                $e = null;
-                $value = unserialize($value);
-            } catch (\Error $e) {
-            } catch (\Exception $e) {
-            }
-            if (null !== $e) {
+                $value = $value();
+            } catch (\Throwable $e) {
                 $value = null;
                 $isHit = false;
             }
@@ -135,6 +160,8 @@ class PhpArrayAdapter implements AdapterInterface, PruneableInterface, Resettabl
 
     /**
      * {@inheritdoc}
+     *
+     * @return bool
      */
     public function hasItem($key)
     {
@@ -145,11 +172,13 @@ class PhpArrayAdapter implements AdapterInterface, PruneableInterface, Resettabl
             $this->initialize();
         }
 
-        return isset($this->values[$key]) || $this->pool->hasItem($key);
+        return isset($this->keys[$key]) || $this->pool->hasItem($key);
     }
 
     /**
      * {@inheritdoc}
+     *
+     * @return bool
      */
     public function deleteItem($key)
     {
@@ -160,11 +189,13 @@ class PhpArrayAdapter implements AdapterInterface, PruneableInterface, Resettabl
             $this->initialize();
         }
 
-        return !isset($this->values[$key]) && $this->pool->deleteItem($key);
+        return !isset($this->keys[$key]) && $this->pool->deleteItem($key);
     }
 
     /**
      * {@inheritdoc}
+     *
+     * @return bool
      */
     public function deleteItems(array $keys)
     {
@@ -176,7 +207,7 @@ class PhpArrayAdapter implements AdapterInterface, PruneableInterface, Resettabl
                 throw new InvalidArgumentException(sprintf('Cache key must be string, "%s" given.', \is_object($key) ? \get_class($key) : \gettype($key)));
             }
 
-            if (isset($this->values[$key])) {
+            if (isset($this->keys[$key])) {
                 $deleted = false;
             } else {
                 $fallbackKeys[] = $key;
@@ -195,6 +226,8 @@ class PhpArrayAdapter implements AdapterInterface, PruneableInterface, Resettabl
 
     /**
      * {@inheritdoc}
+     *
+     * @return bool
      */
     public function save(CacheItemInterface $item)
     {
@@ -202,11 +235,13 @@ class PhpArrayAdapter implements AdapterInterface, PruneableInterface, Resettabl
             $this->initialize();
         }
 
-        return !isset($this->values[$item->getKey()]) && $this->pool->save($item);
+        return !isset($this->keys[$item->getKey()]) && $this->pool->save($item);
     }
 
     /**
      * {@inheritdoc}
+     *
+     * @return bool
      */
     public function saveDeferred(CacheItemInterface $item)
     {
@@ -214,37 +249,34 @@ class PhpArrayAdapter implements AdapterInterface, PruneableInterface, Resettabl
             $this->initialize();
         }
 
-        return !isset($this->values[$item->getKey()]) && $this->pool->saveDeferred($item);
+        return !isset($this->keys[$item->getKey()]) && $this->pool->saveDeferred($item);
     }
 
     /**
      * {@inheritdoc}
+     *
+     * @return bool
      */
     public function commit()
     {
         return $this->pool->commit();
     }
 
-    /**
-     * @return \Generator
-     */
-    private function generateItems(array $keys)
+    private function generateItems(array $keys): \Generator
     {
         $f = $this->createCacheItem;
         $fallbackKeys = [];
 
         foreach ($keys as $key) {
-            if (isset($this->values[$key])) {
-                $value = $this->values[$key];
+            if (isset($this->keys[$key])) {
+                $value = $this->values[$this->keys[$key]];
 
                 if ('N;' === $value) {
                     yield $key => $f($key, null, true);
-                } elseif (\is_string($value) && isset($value[2]) && ':' === $value[1]) {
+                } elseif ($value instanceof \Closure) {
                     try {
-                        yield $key => $f($key, unserialize($value), true);
-                    } catch (\Error $e) {
-                        yield $key => $f($key, null, false);
-                    } catch (\Exception $e) {
+                        yield $key => $f($key, $value(), true);
+                    } catch (\Throwable $e) {
                         yield $key => $f($key, null, false);
                     }
                 } else {
@@ -256,9 +288,7 @@ class PhpArrayAdapter implements AdapterInterface, PruneableInterface, Resettabl
         }
 
         if ($fallbackKeys) {
-            foreach ($this->pool->getItems($fallbackKeys) as $key => $item) {
-                yield $key => $item;
-            }
+            yield from $this->pool->getItems($fallbackKeys);
         }
     }
 
index b56143c2c4f1ebb9dac74ef200d07e70aa49f268..10938a0a9e921c123b0b8829e9c22e9e62626241 100644 (file)
@@ -20,22 +20,19 @@ class PhpFilesAdapter extends AbstractAdapter implements PruneableInterface
     use PhpFilesTrait;
 
     /**
-     * @param string      $namespace
-     * @param int         $defaultLifetime
-     * @param string|null $directory
+     * @param $appendOnly Set to `true` to gain extra performance when the items stored in this pool never expire.
+     *                    Doing so is encouraged because it fits perfectly OPcache's memory model.
      *
      * @throws CacheException if OPcache is not enabled
      */
-    public function __construct($namespace = '', $defaultLifetime = 0, $directory = null)
+    public function __construct(string $namespace = '', int $defaultLifetime = 0, string $directory = null, bool $appendOnly = false)
     {
-        if (!static::isSupported()) {
-            throw new CacheException('OPcache is not enabled.');
-        }
+        $this->appendOnly = $appendOnly;
+        self::$startTime = self::$startTime ?? $_SERVER['REQUEST_TIME'] ?? time();
         parent::__construct('', $defaultLifetime);
         $this->init($namespace, $directory);
-
-        $e = new \Exception();
-        $this->includeHandler = function () use ($e) { throw $e; };
-        $this->zendDetectUnicode = filter_var(ini_get('zend.detect_unicode'), \FILTER_VALIDATE_BOOLEAN);
+        $this->includeHandler = static function ($type, $msg, $file, $line) {
+            throw new \ErrorException($msg, 0, $type, $file, $line);
+        };
     }
 }
index c89a760ed2c169379cf5619c48c1a29e77ba9703..e006ea01467512a22e0688bc464a67b0b92f478b 100644 (file)
@@ -16,26 +16,26 @@ use Psr\Cache\CacheItemPoolInterface;
 use Symfony\Component\Cache\CacheItem;
 use Symfony\Component\Cache\PruneableInterface;
 use Symfony\Component\Cache\ResettableInterface;
+use Symfony\Component\Cache\Traits\ContractsTrait;
 use Symfony\Component\Cache\Traits\ProxyTrait;
+use Symfony\Contracts\Cache\CacheInterface;
 
 /**
  * @author Nicolas Grekas <p@tchwork.com>
  */
-class ProxyAdapter implements AdapterInterface, PruneableInterface, ResettableInterface
+class ProxyAdapter implements AdapterInterface, CacheInterface, PruneableInterface, ResettableInterface
 {
+    use ContractsTrait;
     use ProxyTrait;
 
     private $namespace;
     private $namespaceLen;
     private $createCacheItem;
+    private $setInnerItem;
     private $poolHash;
     private $defaultLifetime;
 
-    /**
-     * @param string $namespace
-     * @param int    $defaultLifetime
-     */
-    public function __construct(CacheItemPoolInterface $pool, $namespace = '', $defaultLifetime = 0)
+    public function __construct(CacheItemPoolInterface $pool, string $namespace = '', int $defaultLifetime = 0)
     {
         $this->pool = $pool;
         $this->poolHash = $poolHash = spl_object_hash($pool);
@@ -46,20 +46,71 @@ class ProxyAdapter implements AdapterInterface, PruneableInterface, ResettableIn
             static function ($key, $innerItem) use ($poolHash) {
                 $item = new CacheItem();
                 $item->key = $key;
+
+                if (null === $innerItem) {
+                    return $item;
+                }
+
+                $item->value = $v = $innerItem->get();
+                $item->isHit = $innerItem->isHit();
+                $item->innerItem = $innerItem;
                 $item->poolHash = $poolHash;
 
-                if (null !== $innerItem) {
-                    $item->value = $innerItem->get();
-                    $item->isHit = $innerItem->isHit();
-                    $item->innerItem = $innerItem;
-                    $innerItem->set(null);
+                // Detect wrapped values that encode for their expiry and creation duration
+                // For compactness, these values are packed in the key of an array using
+                // magic numbers in the form 9D-..-..-..-..-00-..-..-..-5F
+                if (\is_array($v) && 1 === \count($v) && 10 === \strlen($k = (string) array_key_first($v)) && "\x9D" === $k[0] && "\0" === $k[5] && "\x5F" === $k[9]) {
+                    $item->value = $v[$k];
+                    $v = unpack('Ve/Nc', substr($k, 1, -1));
+                    $item->metadata[CacheItem::METADATA_EXPIRY] = $v['e'] + CacheItem::METADATA_EXPIRY_OFFSET;
+                    $item->metadata[CacheItem::METADATA_CTIME] = $v['c'];
+                } elseif ($innerItem instanceof CacheItem) {
+                    $item->metadata = $innerItem->metadata;
                 }
+                $innerItem->set(null);
 
                 return $item;
             },
             null,
             CacheItem::class
         );
+        $this->setInnerItem = \Closure::bind(
+            /**
+             * @param array $item A CacheItem cast to (array); accessing protected properties requires adding the "\0*\0" PHP prefix
+             */
+            static function (CacheItemInterface $innerItem, array $item) {
+                // Tags are stored separately, no need to account for them when considering this item's newly set metadata
+                if (isset(($metadata = $item["\0*\0newMetadata"])[CacheItem::METADATA_TAGS])) {
+                    unset($metadata[CacheItem::METADATA_TAGS]);
+                }
+                if ($metadata) {
+                    // For compactness, expiry and creation duration are packed in the key of an array, using magic numbers as separators
+                    $item["\0*\0value"] = ["\x9D".pack('VN', (int) (0.1 + $metadata[self::METADATA_EXPIRY] - self::METADATA_EXPIRY_OFFSET), $metadata[self::METADATA_CTIME])."\x5F" => $item["\0*\0value"]];
+                }
+                $innerItem->set($item["\0*\0value"]);
+                $innerItem->expiresAt(null !== $item["\0*\0expiry"] ? \DateTime::createFromFormat('U.u', sprintf('%.6F', $item["\0*\0expiry"])) : null);
+            },
+            null,
+            CacheItem::class
+        );
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function get(string $key, callable $callback, float $beta = null, array &$metadata = null)
+    {
+        if (!$this->pool instanceof CacheInterface) {
+            return $this->doGet($this, $key, $callback, $beta, $metadata);
+        }
+
+        return $this->pool->get($this->getId($key), function ($innerItem, bool &$save) use ($key, $callback) {
+            $item = ($this->createCacheItem)($key, $innerItem);
+            $item->set($value = $callback($item, $save));
+            ($this->setInnerItem)($innerItem, (array) $item);
+
+            return $value;
+        }, $beta, $metadata);
     }
 
     /**
@@ -89,6 +140,8 @@ class ProxyAdapter implements AdapterInterface, PruneableInterface, ResettableIn
 
     /**
      * {@inheritdoc}
+     *
+     * @return bool
      */
     public function hasItem($key)
     {
@@ -97,14 +150,26 @@ class ProxyAdapter implements AdapterInterface, PruneableInterface, ResettableIn
 
     /**
      * {@inheritdoc}
+     *
+     * @param string $prefix
+     *
+     * @return bool
      */
-    public function clear()
+    public function clear(/* string $prefix = '' */)
     {
+        $prefix = 0 < \func_num_args() ? (string) func_get_arg(0) : '';
+
+        if ($this->pool instanceof AdapterInterface) {
+            return $this->pool->clear($this->namespace.$prefix);
+        }
+
         return $this->pool->clear();
     }
 
     /**
      * {@inheritdoc}
+     *
+     * @return bool
      */
     public function deleteItem($key)
     {
@@ -113,6 +178,8 @@ class ProxyAdapter implements AdapterInterface, PruneableInterface, ResettableIn
 
     /**
      * {@inheritdoc}
+     *
+     * @return bool
      */
     public function deleteItems(array $keys)
     {
@@ -127,6 +194,8 @@ class ProxyAdapter implements AdapterInterface, PruneableInterface, ResettableIn
 
     /**
      * {@inheritdoc}
+     *
+     * @return bool
      */
     public function save(CacheItemInterface $item)
     {
@@ -135,6 +204,8 @@ class ProxyAdapter implements AdapterInterface, PruneableInterface, ResettableIn
 
     /**
      * {@inheritdoc}
+     *
+     * @return bool
      */
     public function saveDeferred(CacheItemInterface $item)
     {
@@ -143,21 +214,22 @@ class ProxyAdapter implements AdapterInterface, PruneableInterface, ResettableIn
 
     /**
      * {@inheritdoc}
+     *
+     * @return bool
      */
     public function commit()
     {
         return $this->pool->commit();
     }
 
-    private function doSave(CacheItemInterface $item, $method)
+    private function doSave(CacheItemInterface $item, string $method)
     {
         if (!$item instanceof CacheItem) {
             return false;
         }
         $item = (array) $item;
-        $expiry = $item["\0*\0expiry"];
-        if (null === $expiry && 0 < $this->defaultLifetime) {
-            $expiry = time() + $this->defaultLifetime;
+        if (null === $item["\0*\0expiry"] && 0 < $this->defaultLifetime) {
+            $item["\0*\0expiry"] = microtime(true) + $this->defaultLifetime;
         }
 
         if ($item["\0*\0poolHash"] === $this->poolHash && $item["\0*\0innerItem"]) {
@@ -171,13 +243,12 @@ class ProxyAdapter implements AdapterInterface, PruneableInterface, ResettableIn
             $innerItem = $this->pool->getItem($this->namespace.$item["\0*\0key"]);
         }
 
-        $innerItem->set($item["\0*\0value"]);
-        $innerItem->expiresAt(null !== $expiry ? \DateTime::createFromFormat('U', $expiry) : null);
+        ($this->setInnerItem)($innerItem, $item);
 
         return $this->pool->$method($innerItem);
     }
 
-    private function generateItems($items)
+    private function generateItems(iterable $items)
     {
         $f = $this->createCacheItem;
 
@@ -190,7 +261,7 @@ class ProxyAdapter implements AdapterInterface, PruneableInterface, ResettableIn
         }
     }
 
-    private function getId($key)
+    private function getId($key): string
     {
         CacheItem::validateKey($key);
 
diff --git a/advancedcontentfilter/vendor/symfony/cache/Adapter/Psr16Adapter.php b/advancedcontentfilter/vendor/symfony/cache/Adapter/Psr16Adapter.php
new file mode 100644 (file)
index 0000000..e959d78
--- /dev/null
@@ -0,0 +1,86 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien@symfony.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Cache\Adapter;
+
+use Psr\SimpleCache\CacheInterface;
+use Symfony\Component\Cache\PruneableInterface;
+use Symfony\Component\Cache\ResettableInterface;
+use Symfony\Component\Cache\Traits\ProxyTrait;
+
+/**
+ * Turns a PSR-16 cache into a PSR-6 one.
+ *
+ * @author Nicolas Grekas <p@tchwork.com>
+ */
+class Psr16Adapter extends AbstractAdapter implements PruneableInterface, ResettableInterface
+{
+    use ProxyTrait;
+
+    /**
+     * @internal
+     */
+    protected const NS_SEPARATOR = '_';
+
+    private $miss;
+
+    public function __construct(CacheInterface $pool, string $namespace = '', int $defaultLifetime = 0)
+    {
+        parent::__construct($namespace, $defaultLifetime);
+
+        $this->pool = $pool;
+        $this->miss = new \stdClass();
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    protected function doFetch(array $ids)
+    {
+        foreach ($this->pool->getMultiple($ids, $this->miss) as $key => $value) {
+            if ($this->miss !== $value) {
+                yield $key => $value;
+            }
+        }
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    protected function doHave($id)
+    {
+        return $this->pool->has($id);
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    protected function doClear($namespace)
+    {
+        return $this->pool->clear();
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    protected function doDelete(array $ids)
+    {
+        return $this->pool->deleteMultiple($ids);
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    protected function doSave(array $values, int $lifetime)
+    {
+        return $this->pool->setMultiple($values, 0 === $lifetime ? null : $lifetime);
+    }
+}
index c1e17997fb557534d371c920f353755398018621..eb5950e531677191a7a9db5cab3f418f9bd6f120 100644 (file)
@@ -11,6 +11,9 @@
 
 namespace Symfony\Component\Cache\Adapter;
 
+use Symfony\Component\Cache\Marshaller\MarshallerInterface;
+use Symfony\Component\Cache\Traits\RedisClusterProxy;
+use Symfony\Component\Cache\Traits\RedisProxy;
 use Symfony\Component\Cache\Traits\RedisTrait;
 
 class RedisAdapter extends AbstractAdapter
@@ -18,12 +21,12 @@ class RedisAdapter extends AbstractAdapter
     use RedisTrait;
 
     /**
-     * @param \Redis|\RedisArray|\RedisCluster|\Predis\Client $redisClient     The redis client
-     * @param string                                          $namespace       The default namespace
-     * @param int                                             $defaultLifetime The default lifetime
+     * @param \Redis|\RedisArray|\RedisCluster|\Predis\ClientInterface|RedisProxy|RedisClusterProxy $redis           The redis client
+     * @param string                                                                                $namespace       The default namespace
+     * @param int                                                                                   $defaultLifetime The default lifetime
      */
-    public function __construct($redisClient, $namespace = '', $defaultLifetime = 0)
+    public function __construct($redis, string $namespace = '', int $defaultLifetime = 0, MarshallerInterface $marshaller = null)
     {
-        $this->init($redisClient, $namespace, $defaultLifetime);
+        $this->init($redis, $namespace, $defaultLifetime, $marshaller);
     }
 }
diff --git a/advancedcontentfilter/vendor/symfony/cache/Adapter/RedisTagAwareAdapter.php b/advancedcontentfilter/vendor/symfony/cache/Adapter/RedisTagAwareAdapter.php
new file mode 100644 (file)
index 0000000..fd263da
--- /dev/null
@@ -0,0 +1,321 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien@symfony.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Cache\Adapter;
+
+use Predis\Connection\Aggregate\ClusterInterface;
+use Predis\Connection\Aggregate\PredisCluster;
+use Predis\Connection\Aggregate\ReplicationInterface;
+use Predis\Response\ErrorInterface;
+use Predis\Response\Status;
+use Symfony\Component\Cache\CacheItem;
+use Symfony\Component\Cache\Exception\InvalidArgumentException;
+use Symfony\Component\Cache\Exception\LogicException;
+use Symfony\Component\Cache\Marshaller\DeflateMarshaller;
+use Symfony\Component\Cache\Marshaller\MarshallerInterface;
+use Symfony\Component\Cache\Marshaller\TagAwareMarshaller;
+use Symfony\Component\Cache\Traits\RedisClusterProxy;
+use Symfony\Component\Cache\Traits\RedisProxy;
+use Symfony\Component\Cache\Traits\RedisTrait;
+
+/**
+ * Stores tag id <> cache id relationship as a Redis Set.
+ *
+ * Set (tag relation info) is stored without expiry (non-volatile), while cache always gets an expiry (volatile) even
+ * if not set by caller. Thus if you configure redis with the right eviction policy you can be safe this tag <> cache
+ * relationship survives eviction (cache cleanup when Redis runs out of memory).
+ *
+ * Redis server 2.8+ with any `volatile-*` eviction policy, OR `noeviction` if you're sure memory will NEVER fill up
+ *
+ * Design limitations:
+ *  - Max 4 billion cache keys per cache tag as limited by Redis Set datatype.
+ *    E.g. If you use a "all" items tag for expiry instead of clear(), that limits you to 4 billion cache items also.
+ *
+ * @see https://redis.io/topics/lru-cache#eviction-policies Documentation for Redis eviction policies.
+ * @see https://redis.io/topics/data-types#sets Documentation for Redis Set datatype.
+ *
+ * @author Nicolas Grekas <p@tchwork.com>
+ * @author André Rømcke <andre.romcke+symfony@gmail.com>
+ */
+class RedisTagAwareAdapter extends AbstractTagAwareAdapter
+{
+    use RedisTrait;
+
+    /**
+     * On cache items without a lifetime set, we set it to 100 days. This is to make sure cache items are
+     * preferred to be evicted over tag Sets, if eviction policy is configured according to requirements.
+     */
+    private const DEFAULT_CACHE_TTL = 8640000;
+
+    /**
+     * @var string|null detected eviction policy used on Redis server
+     */
+    private $redisEvictionPolicy;
+    private $namespace;
+
+    /**
+     * @param \Redis|\RedisArray|\RedisCluster|\Predis\ClientInterface|RedisProxy|RedisClusterProxy $redis           The redis client
+     * @param string                                                                                $namespace       The default namespace
+     * @param int                                                                                   $defaultLifetime The default lifetime
+     */
+    public function __construct($redis, string $namespace = '', int $defaultLifetime = 0, MarshallerInterface $marshaller = null)
+    {
+        if ($redis instanceof \Predis\ClientInterface && $redis->getConnection() instanceof ClusterInterface && !$redis->getConnection() instanceof PredisCluster) {
+            throw new InvalidArgumentException(sprintf('Unsupported Predis cluster connection: only "%s" is, "%s" given.', PredisCluster::class, \get_class($redis->getConnection())));
+        }
+
+        if (\defined('Redis::OPT_COMPRESSION') && ($redis instanceof \Redis || $redis instanceof \RedisArray || $redis instanceof \RedisCluster)) {
+            $compression = $redis->getOption(\Redis::OPT_COMPRESSION);
+
+            foreach (\is_array($compression) ? $compression : [$compression] as $c) {
+                if (\Redis::COMPRESSION_NONE !== $c) {
+                    throw new InvalidArgumentException(sprintf('phpredis compression must be disabled when using "%s", use "%s" instead.', static::class, DeflateMarshaller::class));
+                }
+            }
+        }
+
+        $this->init($redis, $namespace, $defaultLifetime, new TagAwareMarshaller($marshaller));
+        $this->namespace = $namespace;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    protected function doSave(array $values, int $lifetime, array $addTagData = [], array $delTagData = []): array
+    {
+        $eviction = $this->getRedisEvictionPolicy();
+        if ('noeviction' !== $eviction && !str_starts_with($eviction, 'volatile-')) {
+            throw new LogicException(sprintf('Redis maxmemory-policy setting "%s" is *not* supported by RedisTagAwareAdapter, use "noeviction" or "volatile-*" eviction policies.', $eviction));
+        }
+
+        // serialize values
+        if (!$serialized = $this->marshaller->marshall($values, $failed)) {
+            return $failed;
+        }
+
+        // While pipeline isn't supported on RedisCluster, other setups will at least benefit from doing this in one op
+        $results = $this->pipeline(static function () use ($serialized, $lifetime, $addTagData, $delTagData, $failed) {
+            // Store cache items, force a ttl if none is set, as there is no MSETEX we need to set each one
+            foreach ($serialized as $id => $value) {
+                yield 'setEx' => [
+                    $id,
+                    0 >= $lifetime ? self::DEFAULT_CACHE_TTL : $lifetime,
+                    $value,
+                ];
+            }
+
+            // Add and Remove Tags
+            foreach ($addTagData as $tagId => $ids) {
+                if (!$failed || $ids = array_diff($ids, $failed)) {
+                    yield 'sAdd' => array_merge([$tagId], $ids);
+                }
+            }
+
+            foreach ($delTagData as $tagId => $ids) {
+                if (!$failed || $ids = array_diff($ids, $failed)) {
+                    yield 'sRem' => array_merge([$tagId], $ids);
+                }
+            }
+        });
+
+        foreach ($results as $id => $result) {
+            // Skip results of SADD/SREM operations, they'll be 1 or 0 depending on if set value already existed or not
+            if (is_numeric($result)) {
+                continue;
+            }
+            // setEx results
+            if (true !== $result && (!$result instanceof Status || Status::get('OK') !== $result)) {
+                $failed[] = $id;
+            }
+        }
+
+        return $failed;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    protected function doDeleteYieldTags(array $ids): iterable
+    {
+        $lua = <<<'EOLUA'
+            local v = redis.call('GET', KEYS[1])
+            redis.call('DEL', KEYS[1])
+
+            if not v or v:len() <= 13 or v:byte(1) ~= 0x9D or v:byte(6) ~= 0 or v:byte(10) ~= 0x5F then
+                return ''
+            end
+
+            return v:sub(14, 13 + v:byte(13) + v:byte(12) * 256 + v:byte(11) * 65536)
+EOLUA;
+
+        $results = $this->pipeline(function () use ($ids, $lua) {
+            foreach ($ids as $id) {
+                yield 'eval' => $this->redis instanceof \Predis\ClientInterface ? [$lua, 1, $id] : [$lua, [$id], 1];
+            }
+        });
+
+        foreach ($results as $id => $result) {
+            if ($result instanceof \RedisException || $result instanceof ErrorInterface) {
+                CacheItem::log($this->logger, 'Failed to delete key "{key}": '.$result->getMessage(), ['key' => substr($id, \strlen($this->namespace)), 'exception' => $result]);
+
+                continue;
+            }
+
+            try {
+                yield $id => !\is_string($result) || '' === $result ? [] : $this->marshaller->unmarshall($result);
+            } catch (\Exception $e) {
+                yield $id => [];
+            }
+        }
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    protected function doDeleteTagRelations(array $tagData): bool
+    {
+        $results = $this->pipeline(static function () use ($tagData) {
+            foreach ($tagData as $tagId => $idList) {
+                array_unshift($idList, $tagId);
+                yield 'sRem' => $idList;
+            }
+        });
+        foreach ($results as $result) {
+            // no-op
+        }
+
+        return true;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    protected function doInvalidate(array $tagIds): bool
+    {
+        // This script scans the set of items linked to tag: it empties the set
+        // and removes the linked items. When the set is still not empty after
+        // the scan, it means we're in cluster mode and that the linked items
+        // are on other nodes: we move the links to a temporary set and we
+        // garbage collect that set from the client side.
+
+        $lua = <<<'EOLUA'
+            redis.replicate_commands()
+
+            local cursor = '0'
+            local id = KEYS[1]
+            repeat
+                local result = redis.call('SSCAN', id, cursor, 'COUNT', 5000);
+                cursor = result[1];
+                local rems = {}
+
+                for _, v in ipairs(result[2]) do
+                    local ok, _ = pcall(redis.call, 'DEL', ARGV[1]..v)
+                    if ok then
+                        table.insert(rems, v)
+                    end
+                end
+                if 0 < #rems then
+                    redis.call('SREM', id, unpack(rems))
+                end
+            until '0' == cursor;
+
+            redis.call('SUNIONSTORE', '{'..id..'}'..id, id)
+            redis.call('DEL', id)
+
+            return redis.call('SSCAN', '{'..id..'}'..id, '0', 'COUNT', 5000)
+EOLUA;
+
+        $results = $this->pipeline(function () use ($tagIds, $lua) {
+            if ($this->redis instanceof \Predis\ClientInterface) {
+                $prefix = $this->redis->getOptions()->prefix ? $this->redis->getOptions()->prefix->getPrefix() : '';
+            } elseif (\is_array($prefix = $this->redis->getOption(\Redis::OPT_PREFIX) ?? '')) {
+                $prefix = current($prefix);
+            }
+
+            foreach ($tagIds as $id) {
+                yield 'eval' => $this->redis instanceof \Predis\ClientInterface ? [$lua, 1, $id, $prefix] : [$lua, [$id, $prefix], 1];
+            }
+        });
+
+        $lua = <<<'EOLUA'
+            redis.replicate_commands()
+
+            local id = KEYS[1]
+            local cursor = table.remove(ARGV)
+            redis.call('SREM', '{'..id..'}'..id, unpack(ARGV))
+
+            return redis.call('SSCAN', '{'..id..'}'..id, cursor, 'COUNT', 5000)
+EOLUA;
+
+        $success = true;
+        foreach ($results as $id => $values) {
+            if ($values instanceof \RedisException || $values instanceof ErrorInterface) {
+                CacheItem::log($this->logger, 'Failed to invalidate key "{key}": '.$values->getMessage(), ['key' => substr($id, \strlen($this->namespace)), 'exception' => $values]);
+                $success = false;
+
+                continue;
+            }
+
+            [$cursor, $ids] = $values;
+
+            while ($ids || '0' !== $cursor) {
+                $this->doDelete($ids);
+
+                $evalArgs = [$id, $cursor];
+                array_splice($evalArgs, 1, 0, $ids);
+
+                if ($this->redis instanceof \Predis\ClientInterface) {
+                    array_unshift($evalArgs, $lua, 1);
+                } else {
+                    $evalArgs = [$lua, $evalArgs, 1];
+                }
+
+                $results = $this->pipeline(function () use ($evalArgs) {
+                    yield 'eval' => $evalArgs;
+                });
+
+                foreach ($results as [$cursor, $ids]) {
+                    // no-op
+                }
+            }
+        }
+
+        return $success;
+    }
+
+    private function getRedisEvictionPolicy(): string
+    {
+        if (null !== $this->redisEvictionPolicy) {
+            return $this->redisEvictionPolicy;
+        }
+
+        $hosts = $this->getHosts();
+        $host = reset($hosts);
+        if ($host instanceof \Predis\Client && $host->getConnection() instanceof ReplicationInterface) {
+            // Predis supports info command only on the master in replication environments
+            $hosts = [$host->getClientFor('master')];
+        }
+
+        foreach ($hosts as $host) {
+            $info = $host->info('Memory');
+
+            if ($info instanceof ErrorInterface) {
+                continue;
+            }
+
+            $info = $info['Memory'] ?? $info;
+
+            return $this->redisEvictionPolicy = $info['maxmemory_policy'];
+        }
+
+        return $this->redisEvictionPolicy = '';
+    }
+}
index d3d0ede648a8a173477e7c6f25510aef04de6071..5f14a85b045301b545bb0af94a9526ed61619c1f 100644 (file)
 
 namespace Symfony\Component\Cache\Adapter;
 
-use Psr\SimpleCache\CacheInterface;
-use Symfony\Component\Cache\PruneableInterface;
-use Symfony\Component\Cache\Traits\ProxyTrait;
+@trigger_error(sprintf('The "%s" class is @deprecated since Symfony 4.3, use "Psr16Adapter" instead.', SimpleCacheAdapter::class), \E_USER_DEPRECATED);
 
 /**
- * @author Nicolas Grekas <p@tchwork.com>
+ * @deprecated since Symfony 4.3, use Psr16Adapter instead.
  */
-class SimpleCacheAdapter extends AbstractAdapter implements PruneableInterface
+class SimpleCacheAdapter extends Psr16Adapter
 {
-    /**
-     * @internal
-     */
-    const NS_SEPARATOR = '_';
-
-    use ProxyTrait;
-
-    private $miss;
-
-    public function __construct(CacheInterface $pool, $namespace = '', $defaultLifetime = 0)
-    {
-        parent::__construct($namespace, $defaultLifetime);
-
-        $this->pool = $pool;
-        $this->miss = new \stdClass();
-    }
-
-    /**
-     * {@inheritdoc}
-     */
-    protected function doFetch(array $ids)
-    {
-        foreach ($this->pool->getMultiple($ids, $this->miss) as $key => $value) {
-            if ($this->miss !== $value) {
-                yield $key => $value;
-            }
-        }
-    }
-
-    /**
-     * {@inheritdoc}
-     */
-    protected function doHave($id)
-    {
-        return $this->pool->has($id);
-    }
-
-    /**
-     * {@inheritdoc}
-     */
-    protected function doClear($namespace)
-    {
-        return $this->pool->clear();
-    }
-
-    /**
-     * {@inheritdoc}
-     */
-    protected function doDelete(array $ids)
-    {
-        return $this->pool->deleteMultiple($ids);
-    }
-
-    /**
-     * {@inheritdoc}
-     */
-    protected function doSave(array $values, $lifetime)
-    {
-        return $this->pool->setMultiple($values, 0 === $lifetime ? null : $lifetime);
-    }
 }
index febe50900a7b71b585b00283d0ef9e1ba8266a68..105d4a64f9ba53d1f374f47d9477ad0f86383bc9 100644 (file)
@@ -13,20 +13,26 @@ namespace Symfony\Component\Cache\Adapter;
 
 use Psr\Cache\CacheItemInterface;
 use Psr\Cache\InvalidArgumentException;
+use Psr\Log\LoggerAwareInterface;
+use Psr\Log\LoggerAwareTrait;
 use Symfony\Component\Cache\CacheItem;
 use Symfony\Component\Cache\PruneableInterface;
 use Symfony\Component\Cache\ResettableInterface;
+use Symfony\Component\Cache\Traits\ContractsTrait;
 use Symfony\Component\Cache\Traits\ProxyTrait;
+use Symfony\Contracts\Cache\TagAwareCacheInterface;
 
 /**
  * @author Nicolas Grekas <p@tchwork.com>
  */
-class TagAwareAdapter implements TagAwareAdapterInterface, PruneableInterface, ResettableInterface
+class TagAwareAdapter implements TagAwareAdapterInterface, TagAwareCacheInterface, PruneableInterface, ResettableInterface, LoggerAwareInterface
 {
-    const TAGS_PREFIX = "\0tags\0";
-
+    use ContractsTrait;
+    use LoggerAwareTrait;
     use ProxyTrait;
 
+    public const TAGS_PREFIX = "\0tags\0";
+
     private $deferred = [];
     private $createCacheItem;
     private $setCacheItemTags;
@@ -36,7 +42,7 @@ class TagAwareAdapter implements TagAwareAdapterInterface, PruneableInterface, R
     private $knownTagVersions = [];
     private $knownTagVersionsTtl;
 
-    public function __construct(AdapterInterface $itemsPool, AdapterInterface $tagsPool = null, $knownTagVersionsTtl = 0.15)
+    public function __construct(AdapterInterface $itemsPool, AdapterInterface $tagsPool = null, float $knownTagVersionsTtl = 0.15)
     {
         $this->pool = $itemsPool;
         $this->tags = $tagsPool ?: $itemsPool;
@@ -56,12 +62,13 @@ class TagAwareAdapter implements TagAwareAdapterInterface, PruneableInterface, R
         );
         $this->setCacheItemTags = \Closure::bind(
             static function (CacheItem $item, $key, array &$itemTags) {
+                $item->isTaggable = true;
                 if (!$item->isHit) {
                     return $item;
                 }
                 if (isset($itemTags[$key])) {
                     foreach ($itemTags[$key] as $tag => $version) {
-                        $item->prevTags[$tag] = $tag;
+                        $item->metadata[CacheItem::METADATA_TAGS][$tag] = $tag;
                     }
                     unset($itemTags[$key]);
                 } else {
@@ -78,7 +85,8 @@ class TagAwareAdapter implements TagAwareAdapterInterface, PruneableInterface, R
             static function ($deferred) {
                 $tagsByKey = [];
                 foreach ($deferred as $key => $item) {
-                    $tagsByKey[$key] = $item->tags;
+                    $tagsByKey[$key] = $item->newMetadata[CacheItem::METADATA_TAGS] ?? [];
+                    $item->metadata = $item->newMetadata;
                 }
 
                 return $tagsByKey;
@@ -145,12 +153,15 @@ class TagAwareAdapter implements TagAwareAdapterInterface, PruneableInterface, R
 
     /**
      * {@inheritdoc}
+     *
+     * @return bool
      */
     public function hasItem($key)
     {
-        if ($this->deferred) {
+        if (\is_string($key) && isset($this->deferred[$key])) {
             $this->commit();
         }
+
         if (!$this->pool->hasItem($key)) {
             return false;
         }
@@ -166,9 +177,11 @@ class TagAwareAdapter implements TagAwareAdapterInterface, PruneableInterface, R
         }
 
         foreach ($this->getTagVersions([$itemTags]) as $tag => $version) {
-            if ($itemTags[$tag] !== $version && 1 !== $itemTags[$tag] - $version) {
-                return false;
+            if ($itemTags[$tag] === $version || \is_int($itemTags[$tag]) && \is_int($version) && 1 === $itemTags[$tag] - $version) {
+                continue;
             }
+
+            return false;
         }
 
         return true;
@@ -191,18 +204,21 @@ class TagAwareAdapter implements TagAwareAdapterInterface, PruneableInterface, R
      */
     public function getItems(array $keys = [])
     {
-        if ($this->deferred) {
-            $this->commit();
-        }
         $tagKeys = [];
+        $commit = false;
 
         foreach ($keys as $key) {
             if ('' !== $key && \is_string($key)) {
+                $commit = $commit || isset($this->deferred[$key]);
                 $key = static::TAGS_PREFIX.$key;
                 $tagKeys[$key] = $key;
             }
         }
 
+        if ($commit) {
+            $this->commit();
+        }
+
         try {
             $items = $this->pool->getItems($tagKeys + $keys);
         } catch (InvalidArgumentException $e) {
@@ -216,16 +232,36 @@ class TagAwareAdapter implements TagAwareAdapterInterface, PruneableInterface, R
 
     /**
      * {@inheritdoc}
+     *
+     * @param string $prefix
+     *
+     * @return bool
      */
-    public function clear()
+    public function clear(/* string $prefix = '' */)
     {
-        $this->deferred = [];
+        $prefix = 0 < \func_num_args() ? (string) func_get_arg(0) : '';
+
+        if ('' !== $prefix) {
+            foreach ($this->deferred as $key => $item) {
+                if (str_starts_with($key, $prefix)) {
+                    unset($this->deferred[$key]);
+                }
+            }
+        } else {
+            $this->deferred = [];
+        }
+
+        if ($this->pool instanceof AdapterInterface) {
+            return $this->pool->clear($prefix);
+        }
 
         return $this->pool->clear();
     }
 
     /**
      * {@inheritdoc}
+     *
+     * @return bool
      */
     public function deleteItem($key)
     {
@@ -234,6 +270,8 @@ class TagAwareAdapter implements TagAwareAdapterInterface, PruneableInterface, R
 
     /**
      * {@inheritdoc}
+     *
+     * @return bool
      */
     public function deleteItems(array $keys)
     {
@@ -248,6 +286,8 @@ class TagAwareAdapter implements TagAwareAdapterInterface, PruneableInterface, R
 
     /**
      * {@inheritdoc}
+     *
+     * @return bool
      */
     public function save(CacheItemInterface $item)
     {
@@ -261,6 +301,8 @@ class TagAwareAdapter implements TagAwareAdapterInterface, PruneableInterface, R
 
     /**
      * {@inheritdoc}
+     *
+     * @return bool
      */
     public function saveDeferred(CacheItemInterface $item)
     {
@@ -274,12 +316,17 @@ class TagAwareAdapter implements TagAwareAdapterInterface, PruneableInterface, R
 
     /**
      * {@inheritdoc}
+     *
+     * @return bool
      */
     public function commit()
     {
         return $this->invalidateTags([]);
     }
 
+    /**
+     * @return array
+     */
     public function __sleep()
     {
         throw new \BadMethodCallException('Cannot serialize '.__CLASS__);
@@ -295,7 +342,7 @@ class TagAwareAdapter implements TagAwareAdapterInterface, PruneableInterface, R
         $this->commit();
     }
 
-    private function generateItems($items, array $tagKeys)
+    private function generateItems(iterable $items, array $tagKeys)
     {
         $bufferedItems = $itemTags = [];
         $f = $this->setCacheItemTags;
@@ -321,10 +368,11 @@ class TagAwareAdapter implements TagAwareAdapterInterface, PruneableInterface, R
 
                 foreach ($itemTags as $key => $tags) {
                     foreach ($tags as $tag => $version) {
-                        if ($tagVersions[$tag] !== $version && 1 !== $version - $tagVersions[$tag]) {
-                            unset($itemTags[$key]);
-                            continue 2;
+                        if ($tagVersions[$tag] === $version || \is_int($version) && \is_int($tagVersions[$tag]) && 1 === $version - $tagVersions[$tag]) {
+                            continue;
                         }
+                        unset($itemTags[$key]);
+                        continue 2;
                     }
                 }
                 $tagVersions = $tagKeys = null;
@@ -363,7 +411,7 @@ class TagAwareAdapter implements TagAwareAdapterInterface, PruneableInterface, R
         $tags = [];
         foreach ($tagVersions as $tag => $version) {
             $tags[$tag.static::TAGS_PREFIX] = $tag;
-            if ($fetchTagVersions || !isset($this->knownTagVersions[$tag])) {
+            if ($fetchTagVersions || !isset($this->knownTagVersions[$tag]) || !\is_int($version)) {
                 $fetchTagVersions = true;
                 continue;
             }
@@ -385,6 +433,10 @@ class TagAwareAdapter implements TagAwareAdapterInterface, PruneableInterface, R
             if (isset($invalidatedTags[$tag])) {
                 $invalidatedTags[$tag] = $version->set(++$tagVersions[$tag]);
             }
+            if (!\is_int($tagVersions[$tag])) {
+                unset($this->knownTagVersions[$tag]);
+                continue;
+            }
             $this->knownTagVersions[$tag] = [$now, $tagVersions[$tag]];
         }
 
index cc855c132a83cc8000cd5631c4345ac7a90cd587..9e65b2ef986b36810b2c04d5626d72c88f8e7d22 100644 (file)
 namespace Symfony\Component\Cache\Adapter;
 
 use Psr\Cache\CacheItemInterface;
+use Symfony\Component\Cache\CacheItem;
 use Symfony\Component\Cache\PruneableInterface;
 use Symfony\Component\Cache\ResettableInterface;
+use Symfony\Contracts\Cache\CacheInterface;
+use Symfony\Contracts\Service\ResetInterface;
 
 /**
  * An adapter that collects data about all cache calls.
@@ -22,7 +25,7 @@ use Symfony\Component\Cache\ResettableInterface;
  * @author Tobias Nyholm <tobias.nyholm@gmail.com>
  * @author Nicolas Grekas <p@tchwork.com>
  */
-class TraceableAdapter implements AdapterInterface, PruneableInterface, ResettableInterface
+class TraceableAdapter implements AdapterInterface, CacheInterface, PruneableInterface, ResettableInterface
 {
     protected $pool;
     private $calls = [];
@@ -32,6 +35,38 @@ class TraceableAdapter implements AdapterInterface, PruneableInterface, Resettab
         $this->pool = $pool;
     }
 
+    /**
+     * {@inheritdoc}
+     */
+    public function get(string $key, callable $callback, float $beta = null, array &$metadata = null)
+    {
+        if (!$this->pool instanceof CacheInterface) {
+            throw new \BadMethodCallException(sprintf('Cannot call "%s::get()": this class doesn\'t implement "%s".', \get_class($this->pool), CacheInterface::class));
+        }
+
+        $isHit = true;
+        $callback = function (CacheItem $item, bool &$save) use ($callback, &$isHit) {
+            $isHit = $item->isHit();
+
+            return $callback($item, $save);
+        };
+
+        $event = $this->start(__FUNCTION__);
+        try {
+            $value = $this->pool->get($key, $callback, $beta, $metadata);
+            $event->result[$key] = \is_object($value) ? \get_class($value) : \gettype($value);
+        } finally {
+            $event->end = microtime(true);
+        }
+        if ($isHit) {
+            ++$event->hits;
+        } else {
+            ++$event->misses;
+        }
+
+        return $value;
+    }
+
     /**
      * {@inheritdoc}
      */
@@ -54,6 +89,8 @@ class TraceableAdapter implements AdapterInterface, PruneableInterface, Resettab
 
     /**
      * {@inheritdoc}
+     *
+     * @return bool
      */
     public function hasItem($key)
     {
@@ -67,6 +104,8 @@ class TraceableAdapter implements AdapterInterface, PruneableInterface, Resettab
 
     /**
      * {@inheritdoc}
+     *
+     * @return bool
      */
     public function deleteItem($key)
     {
@@ -80,6 +119,8 @@ class TraceableAdapter implements AdapterInterface, PruneableInterface, Resettab
 
     /**
      * {@inheritdoc}
+     *
+     * @return bool
      */
     public function save(CacheItemInterface $item)
     {
@@ -93,6 +134,8 @@ class TraceableAdapter implements AdapterInterface, PruneableInterface, Resettab
 
     /**
      * {@inheritdoc}
+     *
+     * @return bool
      */
     public function saveDeferred(CacheItemInterface $item)
     {
@@ -132,11 +175,20 @@ class TraceableAdapter implements AdapterInterface, PruneableInterface, Resettab
 
     /**
      * {@inheritdoc}
+     *
+     * @param string $prefix
+     *
+     * @return bool
      */
-    public function clear()
+    public function clear(/* string $prefix = '' */)
     {
+        $prefix = 0 < \func_num_args() ? (string) func_get_arg(0) : '';
         $event = $this->start(__FUNCTION__);
         try {
+            if ($this->pool instanceof AdapterInterface) {
+                return $event->result = $this->pool->clear($prefix);
+            }
+
             return $event->result = $this->pool->clear();
         } finally {
             $event->end = microtime(true);
@@ -145,6 +197,8 @@ class TraceableAdapter implements AdapterInterface, PruneableInterface, Resettab
 
     /**
      * {@inheritdoc}
+     *
+     * @return bool
      */
     public function deleteItems(array $keys)
     {
@@ -159,6 +213,8 @@ class TraceableAdapter implements AdapterInterface, PruneableInterface, Resettab
 
     /**
      * {@inheritdoc}
+     *
+     * @return bool
      */
     public function commit()
     {
@@ -191,13 +247,26 @@ class TraceableAdapter implements AdapterInterface, PruneableInterface, Resettab
      */
     public function reset()
     {
-        if ($this->pool instanceof ResettableInterface) {
+        if ($this->pool instanceof ResetInterface) {
             $this->pool->reset();
         }
 
         $this->clearCalls();
     }
 
+    /**
+     * {@inheritdoc}
+     */
+    public function delete(string $key): bool
+    {
+        $event = $this->start(__FUNCTION__);
+        try {
+            return $event->result[$key] = $this->pool->deleteItem($key);
+        } finally {
+            $event->end = microtime(true);
+        }
+    }
+
     public function getCalls()
     {
         return $this->calls;
index de68955d8e56de86e3a93d19d9fe87f71cff7b44..69461b8b6bb32c16a921275cf35b13341ad7124c 100644 (file)
 
 namespace Symfony\Component\Cache\Adapter;
 
+use Symfony\Contracts\Cache\TagAwareCacheInterface;
+
 /**
  * @author Robin Chalas <robin.chalas@gmail.com>
  */
-class TraceableTagAwareAdapter extends TraceableAdapter implements TagAwareAdapterInterface
+class TraceableTagAwareAdapter extends TraceableAdapter implements TagAwareAdapterInterface, TagAwareCacheInterface
 {
     public function __construct(TagAwareAdapterInterface $pool)
     {
index 11c1b9364ebd5f21f6e667e8c4ee5977ea467b63..435eaf3d9b67e10d272e76a469915964354bb47b 100644 (file)
@@ -1,6 +1,43 @@
 CHANGELOG
 =========
 
+4.4.0
+-----
+
+ * added support for connecting to Redis Sentinel clusters
+ * added argument `$prefix` to `AdapterInterface::clear()`
+ * improved `RedisTagAwareAdapter` to support Redis server >= 2.8 and up to 4B items per tag
+ * added `TagAwareMarshaller` for optimized data storage when using `AbstractTagAwareAdapter`
+ * added `DeflateMarshaller` to compress serialized values
+ * removed support for phpredis 4 `compression`
+ * [BC BREAK] `RedisTagAwareAdapter` is not compatible with `RedisCluster` from `Predis` anymore, use `phpredis` instead
+ * Marked the `CacheDataCollector` class as `@final`.
+
+4.3.0
+-----
+
+ * removed `psr/simple-cache` dependency, run `composer require psr/simple-cache` if you need it
+ * deprecated all PSR-16 adapters, use `Psr16Cache` or `Symfony\Contracts\Cache\CacheInterface` implementations instead
+ * deprecated `SimpleCacheAdapter`, use `Psr16Adapter` instead
+
+4.2.0
+-----
+
+ * added support for connecting to Redis clusters via DSN
+ * added support for configuring multiple Memcached servers via DSN
+ * added `MarshallerInterface` and `DefaultMarshaller` to allow changing the serializer and provide one that automatically uses igbinary when available
+ * implemented `CacheInterface`, which provides stampede protection via probabilistic early expiration and should become the preferred way to use a cache
+ * added sub-second expiry accuracy for backends that support it
+ * added support for phpredis 4 `compression` and `tcp_keepalive` options
+ * added automatic table creation when using Doctrine DBAL with PDO-based backends
+ * throw `LogicException` when `CacheItem::tag()` is called on an item coming from a non tag-aware pool
+ * deprecated `CacheItem::getPreviousTags()`, use `CacheItem::getMetadata()` instead
+ * deprecated the `AbstractAdapter::unserialize()` and `AbstractCache::unserialize()` methods
+ * added `CacheCollectorPass` (originally in `FrameworkBundle`)
+ * added `CachePoolClearerPass` (originally in `FrameworkBundle`)
+ * added `CachePoolPass` (originally in `FrameworkBundle`)
+ * added `CachePoolPrunerPass` (originally in `FrameworkBundle`)
+
 3.4.0
 -----
 
@@ -13,7 +50,7 @@ CHANGELOG
 3.3.0
 -----
 
- * [EXPERIMENTAL] added CacheItem::getPreviousTags() to get bound tags coming from the pool storage if any
+ * added CacheItem::getPreviousTags() to get bound tags coming from the pool storage if any
  * added PSR-16 "Simple Cache" implementations for all existing PSR-6 adapters
  * added Psr6Cache and SimpleCacheAdapter for bidirectional interoperability between PSR-6 and PSR-16
  * added MemcachedAdapter (PSR-6) and MemcachedCache (PSR-16)
index 7ae6568c2715d255d97a8feb429161192367eac0..4dd6fd7c54a27877fda429f670b586b718709850 100644 (file)
 
 namespace Symfony\Component\Cache;
 
-use Psr\Cache\CacheItemInterface;
 use Psr\Log\LoggerInterface;
 use Symfony\Component\Cache\Exception\InvalidArgumentException;
+use Symfony\Component\Cache\Exception\LogicException;
+use Symfony\Contracts\Cache\ItemInterface;
 
 /**
  * @author Nicolas Grekas <p@tchwork.com>
  */
-final class CacheItem implements CacheItemInterface
+final class CacheItem implements ItemInterface
 {
+    private const METADATA_EXPIRY_OFFSET = 1527506807;
+
     protected $key;
     protected $value;
     protected $isHit = false;
     protected $expiry;
-    protected $tags = [];
-    protected $prevTags = [];
+    protected $metadata = [];
+    protected $newMetadata = [];
     protected $innerItem;
     protected $poolHash;
+    protected $isTaggable = false;
 
     /**
      * {@inheritdoc}
      */
-    public function getKey()
+    public function getKey(): string
     {
         return $this->key;
     }
 
     /**
      * {@inheritdoc}
+     *
+     * @return mixed
      */
     public function get()
     {
@@ -48,7 +54,7 @@ final class CacheItem implements CacheItemInterface
     /**
      * {@inheritdoc}
      */
-    public function isHit()
+    public function isHit(): bool
     {
         return $this->isHit;
     }
@@ -58,7 +64,7 @@ final class CacheItem implements CacheItemInterface
      *
      * @return $this
      */
-    public function set($value)
+    public function set($value): self
     {
         $this->value = $value;
 
@@ -70,12 +76,12 @@ final class CacheItem implements CacheItemInterface
      *
      * @return $this
      */
-    public function expiresAt($expiration)
+    public function expiresAt($expiration): self
     {
         if (null === $expiration) {
             $this->expiry = null;
         } elseif ($expiration instanceof \DateTimeInterface) {
-            $this->expiry = (int) $expiration->format('U');
+            $this->expiry = (float) $expiration->format('U.u');
         } else {
             throw new InvalidArgumentException(sprintf('Expiration date must implement DateTimeInterface or be null, "%s" given.', \is_object($expiration) ? \get_class($expiration) : \gettype($expiration)));
         }
@@ -88,14 +94,14 @@ final class CacheItem implements CacheItemInterface
      *
      * @return $this
      */
-    public function expiresAfter($time)
+    public function expiresAfter($time): self
     {
         if (null === $time) {
             $this->expiry = null;
         } elseif ($time instanceof \DateInterval) {
-            $this->expiry = (int) \DateTime::createFromFormat('U', time())->add($time)->format('U');
+            $this->expiry = microtime(true) + \DateTime::createFromFormat('U', 0)->add($time)->format('U.u');
         } elseif (\is_int($time)) {
-            $this->expiry = $time + time();
+            $this->expiry = $time + microtime(true);
         } else {
             throw new InvalidArgumentException(sprintf('Expiration date must be an integer, a DateInterval or null, "%s" given.', \is_object($time) ? \get_class($time) : \gettype($time)));
         }
@@ -104,58 +110,64 @@ final class CacheItem implements CacheItemInterface
     }
 
     /**
-     * Adds a tag to a cache item.
-     *
-     * @param string|string[] $tags A tag or array of tags
-     *
-     * @return $this
-     *
-     * @throws InvalidArgumentException When $tag is not valid
+     * {@inheritdoc}
      */
-    public function tag($tags)
+    public function tag($tags): ItemInterface
     {
-        if (!\is_array($tags)) {
+        if (!$this->isTaggable) {
+            throw new LogicException(sprintf('Cache item "%s" comes from a non tag-aware pool: you cannot tag it.', $this->key));
+        }
+        if (!is_iterable($tags)) {
             $tags = [$tags];
         }
         foreach ($tags as $tag) {
-            if (!\is_string($tag)) {
-                throw new InvalidArgumentException(sprintf('Cache tag must be string, "%s" given.', \is_object($tag) ? \get_class($tag) : \gettype($tag)));
+            if (!\is_string($tag) && !(\is_object($tag) && method_exists($tag, '__toString'))) {
+                throw new InvalidArgumentException(sprintf('Cache tag must be string or object that implements __toString(), "%s" given.', \is_object($tag) ? \get_class($tag) : \gettype($tag)));
             }
-            if (isset($this->tags[$tag])) {
+            $tag = (string) $tag;
+            if (isset($this->newMetadata[self::METADATA_TAGS][$tag])) {
                 continue;
             }
             if ('' === $tag) {
                 throw new InvalidArgumentException('Cache tag length must be greater than zero.');
             }
-            if (false !== strpbrk($tag, '{}()/\@:')) {
-                throw new InvalidArgumentException(sprintf('Cache tag "%s" contains reserved characters {}()/\@:.', $tag));
+            if (false !== strpbrk($tag, self::RESERVED_CHARACTERS)) {
+                throw new InvalidArgumentException(sprintf('Cache tag "%s" contains reserved characters "%s".', $tag, self::RESERVED_CHARACTERS));
             }
-            $this->tags[$tag] = $tag;
+            $this->newMetadata[self::METADATA_TAGS][$tag] = $tag;
         }
 
         return $this;
     }
 
+    /**
+     * {@inheritdoc}
+     */
+    public function getMetadata(): array
+    {
+        return $this->metadata;
+    }
+
     /**
      * Returns the list of tags bound to the value coming from the pool storage if any.
      *
-     * @return array
+     * @deprecated since Symfony 4.2, use the "getMetadata()" method instead.
      */
-    public function getPreviousTags()
+    public function getPreviousTags(): array
     {
-        return $this->prevTags;
+        @trigger_error(sprintf('The "%s()" method is deprecated since Symfony 4.2, use the "getMetadata()" method instead.', __METHOD__), \E_USER_DEPRECATED);
+
+        return $this->metadata[self::METADATA_TAGS] ?? [];
     }
 
     /**
      * Validates a cache key according to PSR-6.
      *
-     * @param string $key The key to validate
-     *
-     * @return string
+     * @param mixed $key The key to validate
      *
      * @throws InvalidArgumentException When $key is not valid
      */
-    public static function validateKey($key)
+    public static function validateKey($key): string
     {
         if (!\is_string($key)) {
             throw new InvalidArgumentException(sprintf('Cache key must be string, "%s" given.', \is_object($key) ? \get_class($key) : \gettype($key)));
@@ -163,8 +175,8 @@ final class CacheItem implements CacheItemInterface
         if ('' === $key) {
             throw new InvalidArgumentException('Cache key length must be greater than zero.');
         }
-        if (false !== strpbrk($key, '{}()/\@:')) {
-            throw new InvalidArgumentException(sprintf('Cache key "%s" contains reserved characters {}()/\@:.', $key));
+        if (false !== strpbrk($key, self::RESERVED_CHARACTERS)) {
+            throw new InvalidArgumentException(sprintf('Cache key "%s" contains reserved characters "%s".', $key, self::RESERVED_CHARACTERS));
         }
 
         return $key;
@@ -175,14 +187,14 @@ final class CacheItem implements CacheItemInterface
      *
      * @internal
      */
-    public static function log(LoggerInterface $logger = null, $message, $context = [])
+    public static function log(?LoggerInterface $logger, string $message, array $context = [])
     {
         if ($logger) {
             $logger->warning($message, $context);
         } else {
             $replace = [];
             foreach ($context as $k => $v) {
-                if (is_scalar($v)) {
+                if (\is_scalar($v)) {
                     $replace['{'.$k.'}'] = $v;
                 }
             }
index c9e87d5cce16c9ab97c1f17633f499ea4bdc35ee..9bcd5b0618ba2a4ada4fad496176ca85d4ce7770 100644 (file)
@@ -21,6 +21,8 @@ use Symfony\Component\HttpKernel\DataCollector\LateDataCollectorInterface;
 /**
  * @author Aaron Scherer <aequasi@gmail.com>
  * @author Tobias Nyholm <tobias.nyholm@gmail.com>
+ *
+ * @final since Symfony 4.4
  */
 class CacheDataCollector extends DataCollector implements LateDataCollectorInterface
 {
@@ -39,8 +41,10 @@ class CacheDataCollector extends DataCollector implements LateDataCollectorInter
 
     /**
      * {@inheritdoc}
+     *
+     * @param \Throwable|null $exception
      */
-    public function collect(Request $request, Response $response, \Exception $exception = null)
+    public function collect(Request $request, Response $response/* , \Throwable $exception = null */)
     {
         $empty = ['calls' => [], 'config' => [], 'options' => [], 'statistics' => []];
         $this->data = ['instances' => $empty, 'total' => $empty];
@@ -62,7 +66,7 @@ class CacheDataCollector extends DataCollector implements LateDataCollectorInter
 
     public function lateCollect()
     {
-        $this->data = $this->cloneVar($this->data);
+        $this->data['instances']['calls'] = $this->cloneVar($this->data['instances']['calls']);
     }
 
     /**
@@ -103,10 +107,7 @@ class CacheDataCollector extends DataCollector implements LateDataCollectorInter
         return $this->data['instances']['calls'];
     }
 
-    /**
-     * @return array
-     */
-    private function calculateStatistics()
+    private function calculateStatistics(): array
     {
         $statistics = [];
         foreach ($this->data['instances']['calls'] as $name => $calls) {
@@ -123,7 +124,15 @@ class CacheDataCollector extends DataCollector implements LateDataCollectorInter
             foreach ($calls as $call) {
                 ++$statistics[$name]['calls'];
                 $statistics[$name]['time'] += $call->end - $call->start;
-                if ('getItem' === $call->name) {
+                if ('get' === $call->name) {
+                    ++$statistics[$name]['reads'];
+                    if ($call->hits) {
+                        ++$statistics[$name]['hits'];
+                    } else {
+                        ++$statistics[$name]['misses'];
+                        ++$statistics[$name]['writes'];
+                    }
+                } elseif ('getItem' === $call->name) {
                     ++$statistics[$name]['reads'];
                     if ($call->hits) {
                         ++$statistics[$name]['hits'];
@@ -157,10 +166,7 @@ class CacheDataCollector extends DataCollector implements LateDataCollectorInter
         return $statistics;
     }
 
-    /**
-     * @return array
-     */
-    private function calculateTotalStatistics()
+    private function calculateTotalStatistics(): array
     {
         $statistics = $this->getStatistics();
         $totals = [
diff --git a/advancedcontentfilter/vendor/symfony/cache/DependencyInjection/CacheCollectorPass.php b/advancedcontentfilter/vendor/symfony/cache/DependencyInjection/CacheCollectorPass.php
new file mode 100644 (file)
index 0000000..6bbab9d
--- /dev/null
@@ -0,0 +1,81 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien@symfony.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Cache\DependencyInjection;
+
+use Symfony\Component\Cache\Adapter\TagAwareAdapterInterface;
+use Symfony\Component\Cache\Adapter\TraceableAdapter;
+use Symfony\Component\Cache\Adapter\TraceableTagAwareAdapter;
+use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
+use Symfony\Component\DependencyInjection\ContainerBuilder;
+use Symfony\Component\DependencyInjection\Definition;
+use Symfony\Component\DependencyInjection\Reference;
+
+/**
+ * Inject a data collector to all the cache services to be able to get detailed statistics.
+ *
+ * @author Tobias Nyholm <tobias.nyholm@gmail.com>
+ */
+class CacheCollectorPass implements CompilerPassInterface
+{
+    private $dataCollectorCacheId;
+    private $cachePoolTag;
+    private $cachePoolRecorderInnerSuffix;
+
+    public function __construct(string $dataCollectorCacheId = 'data_collector.cache', string $cachePoolTag = 'cache.pool', string $cachePoolRecorderInnerSuffix = '.recorder_inner')
+    {
+        $this->dataCollectorCacheId = $dataCollectorCacheId;
+        $this->cachePoolTag = $cachePoolTag;
+        $this->cachePoolRecorderInnerSuffix = $cachePoolRecorderInnerSuffix;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function process(ContainerBuilder $container)
+    {
+        if (!$container->hasDefinition($this->dataCollectorCacheId)) {
+            return;
+        }
+
+        foreach ($container->findTaggedServiceIds($this->cachePoolTag) as $id => $attributes) {
+            $poolName = $attributes[0]['name'] ?? $id;
+
+            $this->addToCollector($id, $poolName, $container);
+        }
+    }
+
+    private function addToCollector(string $id, string $name, ContainerBuilder $container)
+    {
+        $definition = $container->getDefinition($id);
+        if ($definition->isAbstract()) {
+            return;
+        }
+
+        $collectorDefinition = $container->getDefinition($this->dataCollectorCacheId);
+        $recorder = new Definition(is_subclass_of($definition->getClass(), TagAwareAdapterInterface::class) ? TraceableTagAwareAdapter::class : TraceableAdapter::class);
+        $recorder->setTags($definition->getTags());
+        if (!$definition->isPublic() || !$definition->isPrivate()) {
+            $recorder->setPublic($definition->isPublic());
+        }
+        $recorder->setArguments([new Reference($innerId = $id.$this->cachePoolRecorderInnerSuffix)]);
+
+        $definition->setTags([]);
+        $definition->setPublic(false);
+
+        $container->setDefinition($innerId, $definition);
+        $container->setDefinition($id, $recorder);
+
+        // Tell the collector to add the new instance
+        $collectorDefinition->addMethodCall('addInstance', [$name, new Reference($id)]);
+        $collectorDefinition->setPublic(false);
+    }
+}
diff --git a/advancedcontentfilter/vendor/symfony/cache/DependencyInjection/CachePoolClearerPass.php b/advancedcontentfilter/vendor/symfony/cache/DependencyInjection/CachePoolClearerPass.php
new file mode 100644 (file)
index 0000000..3ca89a3
--- /dev/null
@@ -0,0 +1,48 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien@symfony.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Cache\DependencyInjection;
+
+use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
+use Symfony\Component\DependencyInjection\ContainerBuilder;
+use Symfony\Component\DependencyInjection\Reference;
+
+/**
+ * @author Nicolas Grekas <p@tchwork.com>
+ */
+class CachePoolClearerPass implements CompilerPassInterface
+{
+    private $cachePoolClearerTag;
+
+    public function __construct(string $cachePoolClearerTag = 'cache.pool.clearer')
+    {
+        $this->cachePoolClearerTag = $cachePoolClearerTag;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function process(ContainerBuilder $container)
+    {
+        $container->getParameterBag()->remove('cache.prefix.seed');
+
+        foreach ($container->findTaggedServiceIds($this->cachePoolClearerTag) as $id => $attr) {
+            $clearer = $container->getDefinition($id);
+            $pools = [];
+            foreach ($clearer->getArgument(0) as $name => $ref) {
+                if ($container->hasDefinition($ref)) {
+                    $pools[$name] = new Reference($ref);
+                }
+            }
+            $clearer->replaceArgument(0, $pools);
+        }
+    }
+}
diff --git a/advancedcontentfilter/vendor/symfony/cache/DependencyInjection/CachePoolPass.php b/advancedcontentfilter/vendor/symfony/cache/DependencyInjection/CachePoolPass.php
new file mode 100644 (file)
index 0000000..c707ad9
--- /dev/null
@@ -0,0 +1,228 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien@symfony.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Cache\DependencyInjection;
+
+use Symfony\Component\Cache\Adapter\AbstractAdapter;
+use Symfony\Component\Cache\Adapter\ArrayAdapter;
+use Symfony\Component\Cache\Adapter\ChainAdapter;
+use Symfony\Component\Cache\Adapter\NullAdapter;
+use Symfony\Component\DependencyInjection\ChildDefinition;
+use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
+use Symfony\Component\DependencyInjection\ContainerBuilder;
+use Symfony\Component\DependencyInjection\Definition;
+use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
+use Symfony\Component\DependencyInjection\Reference;
+
+/**
+ * @author Nicolas Grekas <p@tchwork.com>
+ */
+class CachePoolPass implements CompilerPassInterface
+{
+    private $cachePoolTag;
+    private $kernelResetTag;
+    private $cacheClearerId;
+    private $cachePoolClearerTag;
+    private $cacheSystemClearerId;
+    private $cacheSystemClearerTag;
+
+    public function __construct(string $cachePoolTag = 'cache.pool', string $kernelResetTag = 'kernel.reset', string $cacheClearerId = 'cache.global_clearer', string $cachePoolClearerTag = 'cache.pool.clearer', string $cacheSystemClearerId = 'cache.system_clearer', string $cacheSystemClearerTag = 'kernel.cache_clearer')
+    {
+        $this->cachePoolTag = $cachePoolTag;
+        $this->kernelResetTag = $kernelResetTag;
+        $this->cacheClearerId = $cacheClearerId;
+        $this->cachePoolClearerTag = $cachePoolClearerTag;
+        $this->cacheSystemClearerId = $cacheSystemClearerId;
+        $this->cacheSystemClearerTag = $cacheSystemClearerTag;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function process(ContainerBuilder $container)
+    {
+        if ($container->hasParameter('cache.prefix.seed')) {
+            $seed = '.'.$container->getParameterBag()->resolveValue($container->getParameter('cache.prefix.seed'));
+        } else {
+            $seed = '_'.$container->getParameter('kernel.project_dir');
+        }
+        $seed .= '.'.$container->getParameter('kernel.container_class');
+
+        $allPools = [];
+        $clearers = [];
+        $attributes = [
+            'provider',
+            'name',
+            'namespace',
+            'default_lifetime',
+            'reset',
+        ];
+        foreach ($container->findTaggedServiceIds($this->cachePoolTag) as $id => $tags) {
+            $adapter = $pool = $container->getDefinition($id);
+            if ($pool->isAbstract()) {
+                continue;
+            }
+            $class = $adapter->getClass();
+            while ($adapter instanceof ChildDefinition) {
+                $adapter = $container->findDefinition($adapter->getParent());
+                $class = $class ?: $adapter->getClass();
+                if ($t = $adapter->getTag($this->cachePoolTag)) {
+                    $tags[0] += $t[0];
+                }
+            }
+            $name = $tags[0]['name'] ?? $id;
+            if (!isset($tags[0]['namespace'])) {
+                $namespaceSeed = $seed;
+                if (null !== $class) {
+                    $namespaceSeed .= '.'.$class;
+                }
+
+                $tags[0]['namespace'] = $this->getNamespace($namespaceSeed, $name);
+            }
+            if (isset($tags[0]['clearer'])) {
+                $clearer = $tags[0]['clearer'];
+                while ($container->hasAlias($clearer)) {
+                    $clearer = (string) $container->getAlias($clearer);
+                }
+            } else {
+                $clearer = null;
+            }
+            unset($tags[0]['clearer'], $tags[0]['name']);
+
+            if (isset($tags[0]['provider'])) {
+                $tags[0]['provider'] = new Reference(static::getServiceProvider($container, $tags[0]['provider']));
+            }
+
+            if (ChainAdapter::class === $class) {
+                $adapters = [];
+                foreach ($adapter->getArgument(0) as $provider => $adapter) {
+                    if ($adapter instanceof ChildDefinition) {
+                        $chainedPool = $adapter;
+                    } else {
+                        $chainedPool = $adapter = new ChildDefinition($adapter);
+                    }
+
+                    $chainedTags = [\is_int($provider) ? [] : ['provider' => $provider]];
+                    $chainedClass = '';
+
+                    while ($adapter instanceof ChildDefinition) {
+                        $adapter = $container->findDefinition($adapter->getParent());
+                        $chainedClass = $chainedClass ?: $adapter->getClass();
+                        if ($t = $adapter->getTag($this->cachePoolTag)) {
+                            $chainedTags[0] += $t[0];
+                        }
+                    }
+
+                    if (ChainAdapter::class === $chainedClass) {
+                        throw new InvalidArgumentException(sprintf('Invalid service "%s": chain of adapters cannot reference another chain, found "%s".', $id, $chainedPool->getParent()));
+                    }
+
+                    $i = 0;
+
+                    if (isset($chainedTags[0]['provider'])) {
+                        $chainedPool->replaceArgument($i++, new Reference(static::getServiceProvider($container, $chainedTags[0]['provider'])));
+                    }
+
+                    if (isset($tags[0]['namespace']) && !\in_array($adapter->getClass(), [ArrayAdapter::class, NullAdapter::class], true)) {
+                        $chainedPool->replaceArgument($i++, $tags[0]['namespace']);
+                    }
+
+                    if (isset($tags[0]['default_lifetime'])) {
+                        $chainedPool->replaceArgument($i++, $tags[0]['default_lifetime']);
+                    }
+
+                    $adapters[] = $chainedPool;
+                }
+
+                $pool->replaceArgument(0, $adapters);
+                unset($tags[0]['provider'], $tags[0]['namespace']);
+                $i = 1;
+            } else {
+                $i = 0;
+            }
+
+            foreach ($attributes as $attr) {
+                if (!isset($tags[0][$attr])) {
+                    // no-op
+                } elseif ('reset' === $attr) {
+                    if ($tags[0][$attr]) {
+                        $pool->addTag($this->kernelResetTag, ['method' => $tags[0][$attr]]);
+                    }
+                } elseif ('namespace' !== $attr || !\in_array($class, [ArrayAdapter::class, NullAdapter::class], true)) {
+                    $pool->replaceArgument($i++, $tags[0][$attr]);
+                }
+                unset($tags[0][$attr]);
+            }
+            if (!empty($tags[0])) {
+                throw new InvalidArgumentException(sprintf('Invalid "%s" tag for service "%s": accepted attributes are "clearer", "provider", "name", "namespace", "default_lifetime" and "reset", found "%s".', $this->cachePoolTag, $id, implode('", "', array_keys($tags[0]))));
+            }
+
+            if (null !== $clearer) {
+                $clearers[$clearer][$name] = new Reference($id, $container::IGNORE_ON_UNINITIALIZED_REFERENCE);
+            }
+
+            $allPools[$name] = new Reference($id, $container::IGNORE_ON_UNINITIALIZED_REFERENCE);
+        }
+
+        $notAliasedCacheClearerId = $this->cacheClearerId;
+        while ($container->hasAlias($this->cacheClearerId)) {
+            $this->cacheClearerId = (string) $container->getAlias($this->cacheClearerId);
+        }
+        if ($container->hasDefinition($this->cacheClearerId)) {
+            $clearers[$notAliasedCacheClearerId] = $allPools;
+        }
+
+        foreach ($clearers as $id => $pools) {
+            $clearer = $container->getDefinition($id);
+            if ($clearer instanceof ChildDefinition) {
+                $clearer->replaceArgument(0, $pools);
+            } else {
+                $clearer->setArgument(0, $pools);
+            }
+            $clearer->addTag($this->cachePoolClearerTag);
+
+            if ($this->cacheSystemClearerId === $id) {
+                $clearer->addTag($this->cacheSystemClearerTag);
+            }
+        }
+
+        if ($container->hasDefinition('console.command.cache_pool_list')) {
+            $container->getDefinition('console.command.cache_pool_list')->replaceArgument(0, array_keys($allPools));
+        }
+    }
+
+    private function getNamespace(string $seed, string $id)
+    {
+        return substr(str_replace('/', '-', base64_encode(hash('sha256', $id.$seed, true))), 0, 10);
+    }
+
+    /**
+     * @internal
+     */
+    public static function getServiceProvider(ContainerBuilder $container, $name)
+    {
+        $container->resolveEnvPlaceholders($name, null, $usedEnvs);
+
+        if ($usedEnvs || preg_match('#^[a-z]++:#', $name)) {
+            $dsn = $name;
+
+            if (!$container->hasDefinition($name = '.cache_connection.'.ContainerBuilder::hash($dsn))) {
+                $definition = new Definition(AbstractAdapter::class);
+                $definition->setPublic(false);
+                $definition->setFactory([AbstractAdapter::class, 'createConnection']);
+                $definition->setArguments([$dsn, ['lazy' => true]]);
+                $container->setDefinition($name, $definition);
+            }
+        }
+
+        return $name;
+    }
+}
diff --git a/advancedcontentfilter/vendor/symfony/cache/DependencyInjection/CachePoolPrunerPass.php b/advancedcontentfilter/vendor/symfony/cache/DependencyInjection/CachePoolPrunerPass.php
new file mode 100644 (file)
index 0000000..e569962
--- /dev/null
@@ -0,0 +1,60 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien@symfony.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Cache\DependencyInjection;
+
+use Symfony\Component\Cache\PruneableInterface;
+use Symfony\Component\DependencyInjection\Argument\IteratorArgument;
+use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
+use Symfony\Component\DependencyInjection\ContainerBuilder;
+use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
+use Symfony\Component\DependencyInjection\Reference;
+
+/**
+ * @author Rob Frawley 2nd <rmf@src.run>
+ */
+class CachePoolPrunerPass implements CompilerPassInterface
+{
+    private $cacheCommandServiceId;
+    private $cachePoolTag;
+
+    public function __construct(string $cacheCommandServiceId = 'console.command.cache_pool_prune', string $cachePoolTag = 'cache.pool')
+    {
+        $this->cacheCommandServiceId = $cacheCommandServiceId;
+        $this->cachePoolTag = $cachePoolTag;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function process(ContainerBuilder $container)
+    {
+        if (!$container->hasDefinition($this->cacheCommandServiceId)) {
+            return;
+        }
+
+        $services = [];
+
+        foreach ($container->findTaggedServiceIds($this->cachePoolTag) as $id => $tags) {
+            $class = $container->getParameterBag()->resolveValue($container->getDefinition($id)->getClass());
+
+            if (!$reflection = $container->getReflectionClass($class)) {
+                throw new InvalidArgumentException(sprintf('Class "%s" used for service "%s" cannot be found.', $class, $id));
+            }
+
+            if ($reflection->implementsInterface(PruneableInterface::class)) {
+                $services[$id] = new Reference($id);
+            }
+        }
+
+        $container->getDefinition($this->cacheCommandServiceId)->replaceArgument(0, new IteratorArgument($services));
+    }
+}
index 4c5cd0cb1f993203b6c2d06407cb44c8d99c139e..f6ac5745dfd124abc96e32f9455ef294370e6020 100644 (file)
@@ -13,6 +13,11 @@ namespace Symfony\Component\Cache;
 
 use Doctrine\Common\Cache\CacheProvider;
 use Psr\Cache\CacheItemPoolInterface;
+use Symfony\Contracts\Service\ResetInterface;
+
+if (!class_exists(CacheProvider::class)) {
+    return;
+}
 
 /**
  * @author Nicolas Grekas <p@tchwork.com>
@@ -39,7 +44,7 @@ class DoctrineProvider extends CacheProvider implements PruneableInterface, Rese
      */
     public function reset()
     {
-        if ($this->pool instanceof ResettableInterface) {
+        if ($this->pool instanceof ResetInterface) {
             $this->pool->reset();
         }
         $this->setNamespace($this->getNamespace());
@@ -47,6 +52,8 @@ class DoctrineProvider extends CacheProvider implements PruneableInterface, Rese
 
     /**
      * {@inheritdoc}
+     *
+     * @return mixed
      */
     protected function doFetch($id)
     {
@@ -57,6 +64,8 @@ class DoctrineProvider extends CacheProvider implements PruneableInterface, Rese
 
     /**
      * {@inheritdoc}
+     *
+     * @return bool
      */
     protected function doContains($id)
     {
@@ -65,6 +74,8 @@ class DoctrineProvider extends CacheProvider implements PruneableInterface, Rese
 
     /**
      * {@inheritdoc}
+     *
+     * @return bool
      */
     protected function doSave($id, $data, $lifeTime = 0)
     {
@@ -79,6 +90,8 @@ class DoctrineProvider extends CacheProvider implements PruneableInterface, Rese
 
     /**
      * {@inheritdoc}
+     *
+     * @return bool
      */
     protected function doDelete($id)
     {
@@ -87,6 +100,8 @@ class DoctrineProvider extends CacheProvider implements PruneableInterface, Rese
 
     /**
      * {@inheritdoc}
+     *
+     * @return bool
      */
     protected function doFlush()
     {
@@ -95,6 +110,8 @@ class DoctrineProvider extends CacheProvider implements PruneableInterface, Rese
 
     /**
      * {@inheritdoc}
+     *
+     * @return array|null
      */
     protected function doGetStats()
     {
index e87b2db8fe733f8edec809d78720aad50376ca82..d2e975b2bc6066d29699372407541865c5e2cd74 100644 (file)
@@ -14,6 +14,12 @@ namespace Symfony\Component\Cache\Exception;
 use Psr\Cache\CacheException as Psr6CacheInterface;
 use Psr\SimpleCache\CacheException as SimpleCacheInterface;
 
-class CacheException extends \Exception implements Psr6CacheInterface, SimpleCacheInterface
-{
+if (interface_exists(SimpleCacheInterface::class)) {
+    class CacheException extends \Exception implements Psr6CacheInterface, SimpleCacheInterface
+    {
+    }
+} else {
+    class CacheException extends \Exception implements Psr6CacheInterface
+    {
+    }
 }
index 828bf3ed779995915be91e1185263ecdc2287fce..7f9584a2643281302c539c764ef7db071bb54d9c 100644 (file)
@@ -14,6 +14,12 @@ namespace Symfony\Component\Cache\Exception;
 use Psr\Cache\InvalidArgumentException as Psr6CacheInterface;
 use Psr\SimpleCache\InvalidArgumentException as SimpleCacheInterface;
 
-class InvalidArgumentException extends \InvalidArgumentException implements Psr6CacheInterface, SimpleCacheInterface
-{
+if (interface_exists(SimpleCacheInterface::class)) {
+    class InvalidArgumentException extends \InvalidArgumentException implements Psr6CacheInterface, SimpleCacheInterface
+    {
+    }
+} else {
+    class InvalidArgumentException extends \InvalidArgumentException implements Psr6CacheInterface
+    {
+    }
 }
diff --git a/advancedcontentfilter/vendor/symfony/cache/Exception/LogicException.php b/advancedcontentfilter/vendor/symfony/cache/Exception/LogicException.php
new file mode 100644 (file)
index 0000000..9ffa7ed
--- /dev/null
@@ -0,0 +1,25 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien@symfony.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Cache\Exception;
+
+use Psr\Cache\CacheException as Psr6CacheInterface;
+use Psr\SimpleCache\CacheException as SimpleCacheInterface;
+
+if (interface_exists(SimpleCacheInterface::class)) {
+    class LogicException extends \LogicException implements Psr6CacheInterface, SimpleCacheInterface
+    {
+    }
+} else {
+    class LogicException extends \LogicException implements Psr6CacheInterface
+    {
+    }
+}
index a7ec70801827ad1b451693590d6a6ae5e70fc096..7fa9539054928405f33975f38584293d8a73d45a 100644 (file)
@@ -1,4 +1,4 @@
-Copyright (c) 2016-2020 Fabien Potencier
+Copyright (c) 2016-2022 Fabien Potencier
 
 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
diff --git a/advancedcontentfilter/vendor/symfony/cache/LockRegistry.php b/advancedcontentfilter/vendor/symfony/cache/LockRegistry.php
new file mode 100644 (file)
index 0000000..26574f1
--- /dev/null
@@ -0,0 +1,161 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien@symfony.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Cache;
+
+use Psr\Log\LoggerInterface;
+use Symfony\Contracts\Cache\CacheInterface;
+use Symfony\Contracts\Cache\ItemInterface;
+
+/**
+ * LockRegistry is used internally by existing adapters to protect against cache stampede.
+ *
+ * It does so by wrapping the computation of items in a pool of locks.
+ * Foreach each apps, there can be at most 20 concurrent processes that
+ * compute items at the same time and only one per cache-key.
+ *
+ * @author Nicolas Grekas <p@tchwork.com>
+ */
+final class LockRegistry
+{
+    private static $openedFiles = [];
+    private static $lockedFiles;
+    private static $signalingException;
+    private static $signalingCallback;
+
+    /**
+     * The number of items in this list controls the max number of concurrent processes.
+     */
+    private static $files = [
+        __DIR__.\DIRECTORY_SEPARATOR.'Adapter'.\DIRECTORY_SEPARATOR.'AbstractAdapter.php',
+        __DIR__.\DIRECTORY_SEPARATOR.'Adapter'.\DIRECTORY_SEPARATOR.'AbstractTagAwareAdapter.php',
+        __DIR__.\DIRECTORY_SEPARATOR.'Adapter'.\DIRECTORY_SEPARATOR.'AdapterInterface.php',
+        __DIR__.\DIRECTORY_SEPARATOR.'Adapter'.\DIRECTORY_SEPARATOR.'ApcuAdapter.php',
+        __DIR__.\DIRECTORY_SEPARATOR.'Adapter'.\DIRECTORY_SEPARATOR.'ArrayAdapter.php',
+        __DIR__.\DIRECTORY_SEPARATOR.'Adapter'.\DIRECTORY_SEPARATOR.'ChainAdapter.php',
+        __DIR__.\DIRECTORY_SEPARATOR.'Adapter'.\DIRECTORY_SEPARATOR.'DoctrineAdapter.php',
+        __DIR__.\DIRECTORY_SEPARATOR.'Adapter'.\DIRECTORY_SEPARATOR.'FilesystemAdapter.php',
+        __DIR__.\DIRECTORY_SEPARATOR.'Adapter'.\DIRECTORY_SEPARATOR.'FilesystemTagAwareAdapter.php',
+        __DIR__.\DIRECTORY_SEPARATOR.'Adapter'.\DIRECTORY_SEPARATOR.'MemcachedAdapter.php',
+        __DIR__.\DIRECTORY_SEPARATOR.'Adapter'.\DIRECTORY_SEPARATOR.'NullAdapter.php',
+        __DIR__.\DIRECTORY_SEPARATOR.'Adapter'.\DIRECTORY_SEPARATOR.'PdoAdapter.php',
+        __DIR__.\DIRECTORY_SEPARATOR.'Adapter'.\DIRECTORY_SEPARATOR.'PhpArrayAdapter.php',
+        __DIR__.\DIRECTORY_SEPARATOR.'Adapter'.\DIRECTORY_SEPARATOR.'PhpFilesAdapter.php',
+        __DIR__.\DIRECTORY_SEPARATOR.'Adapter'.\DIRECTORY_SEPARATOR.'ProxyAdapter.php',
+        __DIR__.\DIRECTORY_SEPARATOR.'Adapter'.\DIRECTORY_SEPARATOR.'Psr16Adapter.php',
+        __DIR__.\DIRECTORY_SEPARATOR.'Adapter'.\DIRECTORY_SEPARATOR.'RedisAdapter.php',
+        __DIR__.\DIRECTORY_SEPARATOR.'Adapter'.\DIRECTORY_SEPARATOR.'RedisTagAwareAdapter.php',
+        __DIR__.\DIRECTORY_SEPARATOR.'Adapter'.\DIRECTORY_SEPARATOR.'SimpleCacheAdapter.php',
+        __DIR__.\DIRECTORY_SEPARATOR.'Adapter'.\DIRECTORY_SEPARATOR.'TagAwareAdapter.php',
+        __DIR__.\DIRECTORY_SEPARATOR.'Adapter'.\DIRECTORY_SEPARATOR.'TagAwareAdapterInterface.php',
+        __DIR__.\DIRECTORY_SEPARATOR.'Adapter'.\DIRECTORY_SEPARATOR.'TraceableAdapter.php',
+        __DIR__.\DIRECTORY_SEPARATOR.'Adapter'.\DIRECTORY_SEPARATOR.'TraceableTagAwareAdapter.php',
+    ];
+
+    /**
+     * Defines a set of existing files that will be used as keys to acquire locks.
+     *
+     * @return array The previously defined set of files
+     */
+    public static function setFiles(array $files): array
+    {
+        $previousFiles = self::$files;
+        self::$files = $files;
+
+        foreach (self::$openedFiles as $file) {
+            if ($file) {
+                flock($file, \LOCK_UN);
+                fclose($file);
+            }
+        }
+        self::$openedFiles = self::$lockedFiles = [];
+
+        return $previousFiles;
+    }
+
+    public static function compute(callable $callback, ItemInterface $item, bool &$save, CacheInterface $pool, \Closure $setMetadata = null, LoggerInterface $logger = null)
+    {
+        if ('\\' === \DIRECTORY_SEPARATOR && null === self::$lockedFiles) {
+            // disable locking on Windows by default
+            self::$files = self::$lockedFiles = [];
+        }
+
+        $key = self::$files ? abs(crc32($item->getKey())) % \count(self::$files) : -1;
+
+        if ($key < 0 || self::$lockedFiles || !$lock = self::open($key)) {
+            return $callback($item, $save);
+        }
+
+        self::$signalingException ?? self::$signalingException = unserialize("O:9:\"Exception\":1:{s:16:\"\0Exception\0trace\";a:0:{}}");
+        self::$signalingCallback ?? self::$signalingCallback = function () { throw self::$signalingException; };
+
+        while (true) {
+            try {
+                // race to get the lock in non-blocking mode
+                $locked = flock($lock, \LOCK_EX | \LOCK_NB, $wouldBlock);
+
+                if ($locked || !$wouldBlock) {
+                    $logger && $logger->info(sprintf('Lock %s, now computing item "{key}"', $locked ? 'acquired' : 'not supported'), ['key' => $item->getKey()]);
+                    self::$lockedFiles[$key] = true;
+
+                    $value = $callback($item, $save);
+
+                    if ($save) {
+                        if ($setMetadata) {
+                            $setMetadata($item);
+                        }
+
+                        $pool->save($item->set($value));
+                        $save = false;
+                    }
+
+                    return $value;
+                }
+                // if we failed the race, retry locking in blocking mode to wait for the winner
+                $logger && $logger->info('Item "{key}" is locked, waiting for it to be released', ['key' => $item->getKey()]);
+                flock($lock, \LOCK_SH);
+            } finally {
+                flock($lock, \LOCK_UN);
+                unset(self::$lockedFiles[$key]);
+            }
+
+            try {
+                $value = $pool->get($item->getKey(), self::$signalingCallback, 0);
+                $logger && $logger->info('Item "{key}" retrieved after lock was released', ['key' => $item->getKey()]);
+                $save = false;
+
+                return $value;
+            } catch (\Exception $e) {
+                if (self::$signalingException !== $e) {
+                    throw $e;
+                }
+                $logger && $logger->info('Item "{key}" not found while lock was released, now retrying', ['key' => $item->getKey()]);
+            }
+        }
+
+        return null;
+    }
+
+    private static function open(int $key)
+    {
+        if (null !== $h = self::$openedFiles[$key] ?? null) {
+            return $h;
+        }
+        set_error_handler(function () {});
+        try {
+            $h = fopen(self::$files[$key], 'r+');
+        } finally {
+            restore_error_handler();
+        }
+
+        return self::$openedFiles[$key] = $h ?: @fopen(self::$files[$key], 'r');
+    }
+}
diff --git a/advancedcontentfilter/vendor/symfony/cache/Marshaller/DefaultMarshaller.php b/advancedcontentfilter/vendor/symfony/cache/Marshaller/DefaultMarshaller.php
new file mode 100644 (file)
index 0000000..7493a2e
--- /dev/null
@@ -0,0 +1,99 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien@symfony.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Cache\Marshaller;
+
+use Symfony\Component\Cache\Exception\CacheException;
+
+/**
+ * Serializes/unserializes values using igbinary_serialize() if available, serialize() otherwise.
+ *
+ * @author Nicolas Grekas <p@tchwork.com>
+ */
+class DefaultMarshaller implements MarshallerInterface
+{
+    private $useIgbinarySerialize = true;
+
+    public function __construct(bool $useIgbinarySerialize = null)
+    {
+        if (null === $useIgbinarySerialize) {
+            $useIgbinarySerialize = \extension_loaded('igbinary') && (\PHP_VERSION_ID < 70400 || version_compare('3.1.6', phpversion('igbinary'), '<='));
+        } elseif ($useIgbinarySerialize && (!\extension_loaded('igbinary') || (\PHP_VERSION_ID >= 70400 && version_compare('3.1.6', phpversion('igbinary'), '>')))) {
+            throw new CacheException(\extension_loaded('igbinary') && \PHP_VERSION_ID >= 70400 ? 'Please upgrade the "igbinary" PHP extension to v3.1.6 or higher.' : 'The "igbinary" PHP extension is not loaded.');
+        }
+        $this->useIgbinarySerialize = $useIgbinarySerialize;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function marshall(array $values, ?array &$failed): array
+    {
+        $serialized = $failed = [];
+
+        foreach ($values as $id => $value) {
+            try {
+                if ($this->useIgbinarySerialize) {
+                    $serialized[$id] = igbinary_serialize($value);
+                } else {
+                    $serialized[$id] = serialize($value);
+                }
+            } catch (\Exception $e) {
+                $failed[] = $id;
+            }
+        }
+
+        return $serialized;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function unmarshall(string $value)
+    {
+        if ('b:0;' === $value) {
+            return false;
+        }
+        if ('N;' === $value) {
+            return null;
+        }
+        static $igbinaryNull;
+        if ($value === ($igbinaryNull ?? $igbinaryNull = \extension_loaded('igbinary') ? igbinary_serialize(null) : false)) {
+            return null;
+        }
+        $unserializeCallbackHandler = ini_set('unserialize_callback_func', __CLASS__.'::handleUnserializeCallback');
+        try {
+            if (':' === ($value[1] ?? ':')) {
+                if (false !== $value = unserialize($value)) {
+                    return $value;
+                }
+            } elseif (false === $igbinaryNull) {
+                throw new \RuntimeException('Failed to unserialize values, did you forget to install the "igbinary" extension?');
+            } elseif (null !== $value = igbinary_unserialize($value)) {
+                return $value;
+            }
+
+            throw new \DomainException(error_get_last() ? error_get_last()['message'] : 'Failed to unserialize values.');
+        } catch (\Error $e) {
+            throw new \ErrorException($e->getMessage(), $e->getCode(), \E_ERROR, $e->getFile(), $e->getLine());
+        } finally {
+            ini_set('unserialize_callback_func', $unserializeCallbackHandler);
+        }
+    }
+
+    /**
+     * @internal
+     */
+    public static function handleUnserializeCallback($class)
+    {
+        throw new \DomainException('Class not found: '.$class);
+    }
+}
diff --git a/advancedcontentfilter/vendor/symfony/cache/Marshaller/DeflateMarshaller.php b/advancedcontentfilter/vendor/symfony/cache/Marshaller/DeflateMarshaller.php
new file mode 100644 (file)
index 0000000..5544806
--- /dev/null
@@ -0,0 +1,53 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien@symfony.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Cache\Marshaller;
+
+use Symfony\Component\Cache\Exception\CacheException;
+
+/**
+ * Compresses values using gzdeflate().
+ *
+ * @author Nicolas Grekas <p@tchwork.com>
+ */
+class DeflateMarshaller implements MarshallerInterface
+{
+    private $marshaller;
+
+    public function __construct(MarshallerInterface $marshaller)
+    {
+        if (!\function_exists('gzdeflate')) {
+            throw new CacheException('The "zlib" PHP extension is not loaded.');
+        }
+
+        $this->marshaller = $marshaller;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function marshall(array $values, ?array &$failed): array
+    {
+        return array_map('gzdeflate', $this->marshaller->marshall($values, $failed));
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function unmarshall(string $value)
+    {
+        if (false !== $inflatedValue = @gzinflate($value)) {
+            $value = $inflatedValue;
+        }
+
+        return $this->marshaller->unmarshall($value);
+    }
+}
diff --git a/advancedcontentfilter/vendor/symfony/cache/Marshaller/MarshallerInterface.php b/advancedcontentfilter/vendor/symfony/cache/Marshaller/MarshallerInterface.php
new file mode 100644 (file)
index 0000000..cdd6c40
--- /dev/null
@@ -0,0 +1,40 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien@symfony.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Cache\Marshaller;
+
+/**
+ * Serializes/unserializes PHP values.
+ *
+ * Implementations of this interface MUST deal with errors carefully. They MUST
+ * also deal with forward and backward compatibility at the storage format level.
+ *
+ * @author Nicolas Grekas <p@tchwork.com>
+ */
+interface MarshallerInterface
+{
+    /**
+     * Serializes a list of values.
+     *
+     * When serialization fails for a specific value, no exception should be
+     * thrown. Instead, its key should be listed in $failed.
+     */
+    public function marshall(array $values, ?array &$failed): array;
+
+    /**
+     * Unserializes a single value and throws an exception if anything goes wrong.
+     *
+     * @return mixed
+     *
+     * @throws \Exception Whenever unserialization fails
+     */
+    public function unmarshall(string $value);
+}
diff --git a/advancedcontentfilter/vendor/symfony/cache/Marshaller/TagAwareMarshaller.php b/advancedcontentfilter/vendor/symfony/cache/Marshaller/TagAwareMarshaller.php
new file mode 100644 (file)
index 0000000..5d1e303
--- /dev/null
@@ -0,0 +1,89 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien@symfony.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Cache\Marshaller;
+
+/**
+ * A marshaller optimized for data structures generated by AbstractTagAwareAdapter.
+ *
+ * @author Nicolas Grekas <p@tchwork.com>
+ */
+class TagAwareMarshaller implements MarshallerInterface
+{
+    private $marshaller;
+
+    public function __construct(MarshallerInterface $marshaller = null)
+    {
+        $this->marshaller = $marshaller ?? new DefaultMarshaller();
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function marshall(array $values, ?array &$failed): array
+    {
+        $failed = $notSerialized = $serialized = [];
+
+        foreach ($values as $id => $value) {
+            if (\is_array($value) && \is_array($value['tags'] ?? null) && \array_key_exists('value', $value) && \count($value) === 2 + (\is_string($value['meta'] ?? null) && 8 === \strlen($value['meta']))) {
+                // if the value is an array with keys "tags", "value" and "meta", use a compact serialization format
+                // magic numbers in the form 9D-..-..-..-..-00-..-..-..-5F allow detecting this format quickly in unmarshall()
+
+                $v = $this->marshaller->marshall($value, $f);
+
+                if ($f) {
+                    $f = [];
+                    $failed[] = $id;
+                } else {
+                    if ([] === $value['tags']) {
+                        $v['tags'] = '';
+                    }
+
+                    $serialized[$id] = "\x9D".($value['meta'] ?? "\0\0\0\0\0\0\0\0").pack('N', \strlen($v['tags'])).$v['tags'].$v['value'];
+                    $serialized[$id][9] = "\x5F";
+                }
+            } else {
+                // other arbitratry values are serialized using the decorated marshaller below
+                $notSerialized[$id] = $value;
+            }
+        }
+
+        if ($notSerialized) {
+            $serialized += $this->marshaller->marshall($notSerialized, $f);
+            $failed = array_merge($failed, $f);
+        }
+
+        return $serialized;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function unmarshall(string $value)
+    {
+        // detect the compact format used in marshall() using magic numbers in the form 9D-..-..-..-..-00-..-..-..-5F
+        if (13 >= \strlen($value) || "\x9D" !== $value[0] || "\0" !== $value[5] || "\x5F" !== $value[9]) {
+            return $this->marshaller->unmarshall($value);
+        }
+
+        // data consists of value, tags and metadata which we need to unpack
+        $meta = substr($value, 1, 12);
+        $meta[8] = "\0";
+        $tagLen = unpack('Nlen', $meta, 8)['len'];
+        $meta = substr($meta, 0, 8);
+
+        return [
+            'value' => $this->marshaller->unmarshall(substr($value, 13 + $tagLen)),
+            'tags' => $tagLen ? $this->marshaller->unmarshall(substr($value, 13, $tagLen)) : [],
+            'meta' => "\0\0\0\0\0\0\0\0" === $meta ? null : $meta,
+        ];
+    }
+}
diff --git a/advancedcontentfilter/vendor/symfony/cache/Psr16Cache.php b/advancedcontentfilter/vendor/symfony/cache/Psr16Cache.php
new file mode 100644 (file)
index 0000000..ac265a5
--- /dev/null
@@ -0,0 +1,284 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien@symfony.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Cache;
+
+use Psr\Cache\CacheException as Psr6CacheException;
+use Psr\Cache\CacheItemPoolInterface;
+use Psr\SimpleCache\CacheException as SimpleCacheException;
+use Psr\SimpleCache\CacheInterface;
+use Symfony\Component\Cache\Adapter\AdapterInterface;
+use Symfony\Component\Cache\Exception\InvalidArgumentException;
+use Symfony\Component\Cache\Traits\ProxyTrait;
+
+if (null !== (new \ReflectionMethod(CacheInterface::class, 'get'))->getReturnType()) {
+    throw new \LogicException('psr/simple-cache 3.0+ is not compatible with this version of symfony/cache. Please upgrade symfony/cache to 6.0+ or downgrade psr/simple-cache to 1.x or 2.x.');
+}
+
+/**
+ * Turns a PSR-6 cache into a PSR-16 one.
+ *
+ * @author Nicolas Grekas <p@tchwork.com>
+ */
+class Psr16Cache implements CacheInterface, PruneableInterface, ResettableInterface
+{
+    use ProxyTrait;
+
+    private const METADATA_EXPIRY_OFFSET = 1527506807;
+
+    private $createCacheItem;
+    private $cacheItemPrototype;
+
+    public function __construct(CacheItemPoolInterface $pool)
+    {
+        $this->pool = $pool;
+
+        if (!$pool instanceof AdapterInterface) {
+            return;
+        }
+        $cacheItemPrototype = &$this->cacheItemPrototype;
+        $createCacheItem = \Closure::bind(
+            static function ($key, $value, $allowInt = false) use (&$cacheItemPrototype) {
+                $item = clone $cacheItemPrototype;
+                $item->poolHash = $item->innerItem = null;
+                $item->key = $allowInt && \is_int($key) ? (string) $key : CacheItem::validateKey($key);
+                $item->value = $value;
+                $item->isHit = false;
+
+                return $item;
+            },
+            null,
+            CacheItem::class
+        );
+        $this->createCacheItem = function ($key, $value, $allowInt = false) use ($createCacheItem) {
+            if (null === $this->cacheItemPrototype) {
+                $this->get($allowInt && \is_int($key) ? (string) $key : $key);
+            }
+            $this->createCacheItem = $createCacheItem;
+
+            return $createCacheItem($key, null, $allowInt)->set($value);
+        };
+    }
+
+    /**
+     * {@inheritdoc}
+     *
+     * @return mixed
+     */
+    public function get($key, $default = null)
+    {
+        try {
+            $item = $this->pool->getItem($key);
+        } catch (SimpleCacheException $e) {
+            throw $e;
+        } catch (Psr6CacheException $e) {
+            throw new InvalidArgumentException($e->getMessage(), $e->getCode(), $e);
+        }
+        if (null === $this->cacheItemPrototype) {
+            $this->cacheItemPrototype = clone $item;
+            $this->cacheItemPrototype->set(null);
+        }
+
+        return $item->isHit() ? $item->get() : $default;
+    }
+
+    /**
+     * {@inheritdoc}
+     *
+     * @return bool
+     */
+    public function set($key, $value, $ttl = null)
+    {
+        try {
+            if (null !== $f = $this->createCacheItem) {
+                $item = $f($key, $value);
+            } else {
+                $item = $this->pool->getItem($key)->set($value);
+            }
+        } catch (SimpleCacheException $e) {
+            throw $e;
+        } catch (Psr6CacheException $e) {
+            throw new InvalidArgumentException($e->getMessage(), $e->getCode(), $e);
+        }
+        if (null !== $ttl) {
+            $item->expiresAfter($ttl);
+        }
+
+        return $this->pool->save($item);
+    }
+
+    /**
+     * {@inheritdoc}
+     *
+     * @return bool
+     */
+    public function delete($key)
+    {
+        try {
+            return $this->pool->deleteItem($key);
+        } catch (SimpleCacheException $e) {
+            throw $e;
+        } catch (Psr6CacheException $e) {
+            throw new InvalidArgumentException($e->getMessage(), $e->getCode(), $e);
+        }
+    }
+
+    /**
+     * {@inheritdoc}
+     *
+     * @return bool
+     */
+    public function clear()
+    {
+        return $this->pool->clear();
+    }
+
+    /**
+     * {@inheritdoc}
+     *
+     * @return iterable
+     */
+    public function getMultiple($keys, $default = null)
+    {
+        if ($keys instanceof \Traversable) {
+            $keys = iterator_to_array($keys, false);
+        } elseif (!\is_array($keys)) {
+            throw new InvalidArgumentException(sprintf('Cache keys must be array or Traversable, "%s" given.', \is_object($keys) ? \get_class($keys) : \gettype($keys)));
+        }
+
+        try {
+            $items = $this->pool->getItems($keys);
+        } catch (SimpleCacheException $e) {
+            throw $e;
+        } catch (Psr6CacheException $e) {
+            throw new InvalidArgumentException($e->getMessage(), $e->getCode(), $e);
+        }
+        $values = [];
+
+        if (!$this->pool instanceof AdapterInterface) {
+            foreach ($items as $key => $item) {
+                $values[$key] = $item->isHit() ? $item->get() : $default;
+            }
+
+            return $values;
+        }
+
+        foreach ($items as $key => $item) {
+            if (!$item->isHit()) {
+                $values[$key] = $default;
+                continue;
+            }
+            $values[$key] = $item->get();
+
+            if (!$metadata = $item->getMetadata()) {
+                continue;
+            }
+            unset($metadata[CacheItem::METADATA_TAGS]);
+
+            if ($metadata) {
+                $values[$key] = ["\x9D".pack('VN', (int) (0.1 + $metadata[CacheItem::METADATA_EXPIRY] - self::METADATA_EXPIRY_OFFSET), $metadata[CacheItem::METADATA_CTIME])."\x5F" => $values[$key]];
+            }
+        }
+
+        return $values;
+    }
+
+    /**
+     * {@inheritdoc}
+     *
+     * @return bool
+     */
+    public function setMultiple($values, $ttl = null)
+    {
+        $valuesIsArray = \is_array($values);
+        if (!$valuesIsArray && !$values instanceof \Traversable) {
+            throw new InvalidArgumentException(sprintf('Cache values must be array or Traversable, "%s" given.', \is_object($values) ? \get_class($values) : \gettype($values)));
+        }
+        $items = [];
+
+        try {
+            if (null !== $f = $this->createCacheItem) {
+                $valuesIsArray = false;
+                foreach ($values as $key => $value) {
+                    $items[$key] = $f($key, $value, true);
+                }
+            } elseif ($valuesIsArray) {
+                $items = [];
+                foreach ($values as $key => $value) {
+                    $items[] = (string) $key;
+                }
+                $items = $this->pool->getItems($items);
+            } else {
+                foreach ($values as $key => $value) {
+                    if (\is_int($key)) {
+                        $key = (string) $key;
+                    }
+                    $items[$key] = $this->pool->getItem($key)->set($value);
+                }
+            }
+        } catch (SimpleCacheException $e) {
+            throw $e;
+        } catch (Psr6CacheException $e) {
+            throw new InvalidArgumentException($e->getMessage(), $e->getCode(), $e);
+        }
+        $ok = true;
+
+        foreach ($items as $key => $item) {
+            if ($valuesIsArray) {
+                $item->set($values[$key]);
+            }
+            if (null !== $ttl) {
+                $item->expiresAfter($ttl);
+            }
+            $ok = $this->pool->saveDeferred($item) && $ok;
+        }
+
+        return $this->pool->commit() && $ok;
+    }
+
+    /**
+     * {@inheritdoc}
+     *
+     * @return bool
+     */
+    public function deleteMultiple($keys)
+    {
+        if ($keys instanceof \Traversable) {
+            $keys = iterator_to_array($keys, false);
+        } elseif (!\is_array($keys)) {
+            throw new InvalidArgumentException(sprintf('Cache keys must be array or Traversable, "%s" given.', \is_object($keys) ? \get_class($keys) : \gettype($keys)));
+        }
+
+        try {
+            return $this->pool->deleteItems($keys);
+        } catch (SimpleCacheException $e) {
+            throw $e;
+        } catch (Psr6CacheException $e) {
+            throw new InvalidArgumentException($e->getMessage(), $e->getCode(), $e);
+        }
+    }
+
+    /**
+     * {@inheritdoc}
+     *
+     * @return bool
+     */
+    public function has($key)
+    {
+        try {
+            return $this->pool->hasItem($key);
+        } catch (SimpleCacheException $e) {
+            throw $e;
+        } catch (Psr6CacheException $e) {
+            throw new InvalidArgumentException($e->getMessage(), $e->getCode(), $e);
+        }
+    }
+}
index c4ab7520f451e20fc5e6d79784cca912264523a8..c466d57883c2f0deb5eb95cf21150b07afca2c61 100644 (file)
@@ -1,18 +1,19 @@
 Symfony PSR-6 implementation for caching
 ========================================
 
-This component provides an extended [PSR-6](http://www.php-fig.org/psr/psr-6/)
-implementation for adding cache to your applications. It is designed to have a
-low overhead so that caching is fastest. It ships with a few caching adapters
-for the most widespread and suited to caching backends. It also provides a
-`doctrine/cache` proxy adapter to cover more advanced caching needs and a proxy
-adapter for greater interoperability between PSR-6 implementations.
+The Cache component provides extended
+[PSR-6](https://www.php-fig.org/psr/psr-6/) implementations for adding cache to
+your applications. It is designed to have a low overhead so that caching is
+fastest. It ships with adapters for the most widespread caching backends.
+It also provides a [PSR-16](https://www.php-fig.org/psr/psr-16/) adapter,
+and implementations for [symfony/cache-contracts](https://github.com/symfony/cache-contracts)'
+`CacheInterface` and `TagAwareCacheInterface`.
 
 Resources
 ---------
 
 * [Documentation](https://symfony.com/doc/current/components/cache.html)
 * [Contributing](https://symfony.com/doc/current/contributing/index.html)
 * [Report issues](https://github.com/symfony/symfony/issues) and
-    [send Pull Requests](https://github.com/symfony/symfony/pulls)
-    in the [main Symfony repository](https://github.com/symfony/symfony)
+ * [Documentation](https://symfony.com/doc/current/components/cache.html)
+ * [Contributing](https://symfony.com/doc/current/contributing/index.html)
+ * [Report issues](https://github.com/symfony/symfony/issues) and
+   [send Pull Requests](https://github.com/symfony/symfony/pulls)
+   in the [main Symfony repository](https://github.com/symfony/symfony)
index 6be72861e709ce460feeadaa8320fa372e119c2e..7b0a853f234d12df6f9b80b7174e9ac8a6d9da36 100644 (file)
 
 namespace Symfony\Component\Cache;
 
+use Symfony\Contracts\Service\ResetInterface;
+
 /**
  * Resets a pool's local state.
  */
-interface ResettableInterface
+interface ResettableInterface extends ResetInterface
 {
-    public function reset();
 }
index baedb737479a3790da00a3cde1ecb863b450ae47..c3d8b38cc8821c71670989b2a91087b4e368808c 100644 (file)
 namespace Symfony\Component\Cache\Simple;
 
 use Psr\Log\LoggerAwareInterface;
-use Psr\SimpleCache\CacheInterface;
+use Psr\SimpleCache\CacheInterface as Psr16CacheInterface;
+use Symfony\Component\Cache\Adapter\AbstractAdapter;
 use Symfony\Component\Cache\CacheItem;
 use Symfony\Component\Cache\Exception\InvalidArgumentException;
 use Symfony\Component\Cache\ResettableInterface;
 use Symfony\Component\Cache\Traits\AbstractTrait;
+use Symfony\Contracts\Cache\CacheInterface;
+
+@trigger_error(sprintf('The "%s" class is deprecated since Symfony 4.3, use "%s" and type-hint for "%s" instead.', AbstractCache::class, AbstractAdapter::class, CacheInterface::class), \E_USER_DEPRECATED);
 
 /**
- * @author Nicolas Grekas <p@tchwork.com>
+ * @deprecated since Symfony 4.3, use AbstractAdapter and type-hint for CacheInterface instead.
  */
-abstract class AbstractCache implements CacheInterface, LoggerAwareInterface, ResettableInterface
+abstract class AbstractCache implements Psr16CacheInterface, LoggerAwareInterface, ResettableInterface
 {
-    /**
-     * @internal
-     */
-    const NS_SEPARATOR = ':';
-
     use AbstractTrait {
         deleteItems as private;
         AbstractTrait::deleteItem as delete;
         AbstractTrait::hasItem as has;
     }
 
-    private $defaultLifetime;
-
     /**
-     * @param string $namespace
-     * @param int    $defaultLifetime
+     * @internal
      */
-    protected function __construct($namespace = '', $defaultLifetime = 0)
+    protected const NS_SEPARATOR = ':';
+
+    private $defaultLifetime;
+
+    protected function __construct(string $namespace = '', int $defaultLifetime = 0)
     {
-        $this->defaultLifetime = max(0, (int) $defaultLifetime);
+        $this->defaultLifetime = max(0, $defaultLifetime);
         $this->namespace = '' === $namespace ? '' : CacheItem::validateKey($namespace).':';
         if (null !== $this->maxIdLength && \strlen($namespace) > $this->maxIdLength - 24) {
             throw new InvalidArgumentException(sprintf('Namespace must be %d chars max, %d given ("%s").', $this->maxIdLength - 24, \strlen($namespace), $namespace));
@@ -61,7 +61,7 @@ abstract class AbstractCache implements CacheInterface, LoggerAwareInterface, Re
                 return $value;
             }
         } catch (\Exception $e) {
-            CacheItem::log($this->logger, 'Failed to fetch key "{key}"', ['key' => $key, 'exception' => $e]);
+            CacheItem::log($this->logger, 'Failed to fetch key "{key}": '.$e->getMessage(), ['key' => $key, 'exception' => $e]);
         }
 
         return $default;
@@ -69,6 +69,8 @@ abstract class AbstractCache implements CacheInterface, LoggerAwareInterface, Re
 
     /**
      * {@inheritdoc}
+     *
+     * @return bool
      */
     public function set($key, $value, $ttl = null)
     {
@@ -79,6 +81,8 @@ abstract class AbstractCache implements CacheInterface, LoggerAwareInterface, Re
 
     /**
      * {@inheritdoc}
+     *
+     * @return iterable
      */
     public function getMultiple($keys, $default = null)
     {
@@ -95,7 +99,7 @@ abstract class AbstractCache implements CacheInterface, LoggerAwareInterface, Re
         try {
             $values = $this->doFetch($ids);
         } catch (\Exception $e) {
-            CacheItem::log($this->logger, 'Failed to fetch requested values', ['keys' => $keys, 'exception' => $e]);
+            CacheItem::log($this->logger, 'Failed to fetch values: '.$e->getMessage(), ['keys' => $keys, 'exception' => $e]);
             $values = [];
         }
         $ids = array_combine($ids, $keys);
@@ -105,6 +109,8 @@ abstract class AbstractCache implements CacheInterface, LoggerAwareInterface, Re
 
     /**
      * {@inheritdoc}
+     *
+     * @return bool
      */
     public function setMultiple($values, $ttl = null)
     {
@@ -134,13 +140,16 @@ abstract class AbstractCache implements CacheInterface, LoggerAwareInterface, Re
         foreach (\is_array($e) ? $e : array_keys($valuesById) as $id) {
             $keys[] = substr($id, \strlen($this->namespace));
         }
-        CacheItem::log($this->logger, 'Failed to save values', ['keys' => $keys, 'exception' => $e instanceof \Exception ? $e : null]);
+        $message = 'Failed to save values'.($e instanceof \Exception ? ': '.$e->getMessage() : '.');
+        CacheItem::log($this->logger, $message, ['keys' => $keys, 'exception' => $e instanceof \Exception ? $e : null]);
 
         return false;
     }
 
     /**
      * {@inheritdoc}
+     *
+     * @return bool
      */
     public function deleteMultiple($keys)
     {
@@ -168,19 +177,19 @@ abstract class AbstractCache implements CacheInterface, LoggerAwareInterface, Re
         throw new InvalidArgumentException(sprintf('Expiration date must be an integer, a DateInterval or null, "%s" given.', \is_object($ttl) ? \get_class($ttl) : \gettype($ttl)));
     }
 
-    private function generateValues($values, &$keys, $default)
+    private function generateValues(iterable $values, array &$keys, $default): iterable
     {
         try {
             foreach ($values as $id => $value) {
                 if (!isset($keys[$id])) {
-                    $id = key($keys);
+                    throw new InvalidArgumentException(sprintf('Could not match value id "%s" to keys "%s".', $id, implode('", "', $keys)));
                 }
                 $key = $keys[$id];
                 unset($keys[$id]);
                 yield $key => $value;
             }
         } catch (\Exception $e) {
-            CacheItem::log($this->logger, 'Failed to fetch requested values', ['keys' => array_values($keys), 'exception' => $e]);
+            CacheItem::log($this->logger, 'Failed to fetch values: '.$e->getMessage(), ['keys' => array_values($keys), 'exception' => $e]);
         }
 
         foreach ($keys as $key) {
index e583b44341dce98ed95676bc8e36740b323f6e2b..bef89e27326833a26d2b4e2558223cf0efa44a7f 100644 (file)
 
 namespace Symfony\Component\Cache\Simple;
 
+use Symfony\Component\Cache\Adapter\ApcuAdapter;
 use Symfony\Component\Cache\Traits\ApcuTrait;
+use Symfony\Contracts\Cache\CacheInterface;
 
+@trigger_error(sprintf('The "%s" class is deprecated since Symfony 4.3, use "%s" and type-hint for "%s" instead.', ApcuCache::class, ApcuAdapter::class, CacheInterface::class), \E_USER_DEPRECATED);
+
+/**
+ * @deprecated since Symfony 4.3, use ApcuAdapter and type-hint for CacheInterface instead.
+ */
 class ApcuCache extends AbstractCache
 {
     use ApcuTrait;
 
-    /**
-     * @param string      $namespace
-     * @param int         $defaultLifetime
-     * @param string|null $version
-     */
-    public function __construct($namespace = '', $defaultLifetime = 0, $version = null)
+    public function __construct(string $namespace = '', int $defaultLifetime = 0, string $version = null)
     {
         $this->init($namespace, $defaultLifetime, $version);
     }
index 6013f0ad2030bfcb189edae999923c9c2c0024cd..469edf1c62b5494b5c6d4627a95a72b1785f07c1 100644 (file)
 namespace Symfony\Component\Cache\Simple;
 
 use Psr\Log\LoggerAwareInterface;
-use Psr\SimpleCache\CacheInterface;
+use Psr\SimpleCache\CacheInterface as Psr16CacheInterface;
+use Symfony\Component\Cache\Adapter\ArrayAdapter;
 use Symfony\Component\Cache\CacheItem;
 use Symfony\Component\Cache\Exception\InvalidArgumentException;
 use Symfony\Component\Cache\ResettableInterface;
 use Symfony\Component\Cache\Traits\ArrayTrait;
+use Symfony\Contracts\Cache\CacheInterface;
+
+@trigger_error(sprintf('The "%s" class is deprecated since Symfony 4.3, use "%s" and type-hint for "%s" instead.', ArrayCache::class, ArrayAdapter::class, CacheInterface::class), \E_USER_DEPRECATED);
 
 /**
- * @author Nicolas Grekas <p@tchwork.com>
+ * @deprecated since Symfony 4.3, use ArrayAdapter and type-hint for CacheInterface instead.
  */
-class ArrayCache implements CacheInterface, LoggerAwareInterface, ResettableInterface
+class ArrayCache implements Psr16CacheInterface, LoggerAwareInterface, ResettableInterface
 {
     use ArrayTrait {
         ArrayTrait::deleteItem as delete;
@@ -31,12 +35,11 @@ class ArrayCache implements CacheInterface, LoggerAwareInterface, ResettableInte
     private $defaultLifetime;
 
     /**
-     * @param int  $defaultLifetime
      * @param bool $storeSerialized Disabling serialization can lead to cache corruptions when storing mutable values but increases performance otherwise
      */
-    public function __construct($defaultLifetime = 0, $storeSerialized = true)
+    public function __construct(int $defaultLifetime = 0, bool $storeSerialized = true)
     {
-        $this->defaultLifetime = (int) $defaultLifetime;
+        $this->defaultLifetime = $defaultLifetime;
         $this->storeSerialized = $storeSerialized;
     }
 
@@ -45,13 +48,26 @@ class ArrayCache implements CacheInterface, LoggerAwareInterface, ResettableInte
      */
     public function get($key, $default = null)
     {
-        foreach ($this->getMultiple([$key], $default) as $v) {
-            return $v;
+        if (!\is_string($key) || !isset($this->expiries[$key])) {
+            CacheItem::validateKey($key);
+        }
+        if (!$isHit = isset($this->expiries[$key]) && ($this->expiries[$key] > microtime(true) || !$this->delete($key))) {
+            $this->values[$key] = null;
+
+            return $default;
         }
+        if (!$this->storeSerialized) {
+            return $this->values[$key];
+        }
+        $value = $this->unfreeze($key, $isHit);
+
+        return $isHit ? $value : $default;
     }
 
     /**
      * {@inheritdoc}
+     *
+     * @return iterable
      */
     public function getMultiple($keys, $default = null)
     {
@@ -61,14 +77,18 @@ class ArrayCache implements CacheInterface, LoggerAwareInterface, ResettableInte
             throw new InvalidArgumentException(sprintf('Cache keys must be array or Traversable, "%s" given.', \is_object($keys) ? \get_class($keys) : \gettype($keys)));
         }
         foreach ($keys as $key) {
-            CacheItem::validateKey($key);
+            if (!\is_string($key) || !isset($this->expiries[$key])) {
+                CacheItem::validateKey($key);
+            }
         }
 
-        return $this->generateItems($keys, time(), function ($k, $v, $hit) use ($default) { return $hit ? $v : $default; });
+        return $this->generateItems($keys, microtime(true), function ($k, $v, $hit) use ($default) { return $hit ? $v : $default; });
     }
 
     /**
      * {@inheritdoc}
+     *
+     * @return bool
      */
     public function deleteMultiple($keys)
     {
@@ -84,16 +104,22 @@ class ArrayCache implements CacheInterface, LoggerAwareInterface, ResettableInte
 
     /**
      * {@inheritdoc}
+     *
+     * @return bool
      */
     public function set($key, $value, $ttl = null)
     {
-        CacheItem::validateKey($key);
+        if (!\is_string($key)) {
+            CacheItem::validateKey($key);
+        }
 
         return $this->setMultiple([$key => $value], $ttl);
     }
 
     /**
      * {@inheritdoc}
+     *
+     * @return bool
      */
     public function setMultiple($values, $ttl = null)
     {
@@ -103,27 +129,20 @@ class ArrayCache implements CacheInterface, LoggerAwareInterface, ResettableInte
         $valuesArray = [];
 
         foreach ($values as $key => $value) {
-            \is_int($key) || CacheItem::validateKey($key);
+            if (!\is_int($key) && !(\is_string($key) && isset($this->expiries[$key]))) {
+                CacheItem::validateKey($key);
+            }
             $valuesArray[$key] = $value;
         }
         if (false === $ttl = $this->normalizeTtl($ttl)) {
             return $this->deleteMultiple(array_keys($valuesArray));
         }
-        if ($this->storeSerialized) {
-            foreach ($valuesArray as $key => $value) {
-                try {
-                    $valuesArray[$key] = serialize($value);
-                } catch (\Exception $e) {
-                    $type = \is_object($value) ? \get_class($value) : \gettype($value);
-                    CacheItem::log($this->logger, 'Failed to save key "{key}" ({type})', ['key' => $key, 'type' => $type, 'exception' => $e]);
-
-                    return false;
-                }
-            }
-        }
-        $expiry = 0 < $ttl ? time() + $ttl : \PHP_INT_MAX;
+        $expiry = 0 < $ttl ? microtime(true) + $ttl : \PHP_INT_MAX;
 
         foreach ($valuesArray as $key => $value) {
+            if ($this->storeSerialized && null === $value = $this->freeze($value, $key)) {
+                return false;
+            }
             $this->values[$key] = $value;
             $this->expiries[$key] = $expiry;
         }
index 2e6c7277d78e4c13480123845eec081e7a7586ed..bae9507260d0ef6e6d3e889f8c5d459e187614da 100644 (file)
 
 namespace Symfony\Component\Cache\Simple;
 
-use Psr\SimpleCache\CacheInterface;
+use Psr\SimpleCache\CacheInterface as Psr16CacheInterface;
+use Symfony\Component\Cache\Adapter\ChainAdapter;
 use Symfony\Component\Cache\Exception\InvalidArgumentException;
 use Symfony\Component\Cache\PruneableInterface;
 use Symfony\Component\Cache\ResettableInterface;
+use Symfony\Contracts\Cache\CacheInterface;
+use Symfony\Contracts\Service\ResetInterface;
+
+@trigger_error(sprintf('The "%s" class is deprecated since Symfony 4.3, use "%s" and type-hint for "%s" instead.', ChainCache::class, ChainAdapter::class, CacheInterface::class), \E_USER_DEPRECATED);
 
 /**
  * Chains several caches together.
@@ -22,9 +27,9 @@ use Symfony\Component\Cache\ResettableInterface;
  * Cached items are fetched from the first cache having them in its data store.
  * They are saved and deleted in all caches at once.
  *
- * @author Nicolas Grekas <p@tchwork.com>
+ * @deprecated since Symfony 4.3, use ChainAdapter and type-hint for CacheInterface instead.
  */
-class ChainCache implements CacheInterface, PruneableInterface, ResettableInterface
+class ChainCache implements Psr16CacheInterface, PruneableInterface, ResettableInterface
 {
     private $miss;
     private $caches = [];
@@ -32,25 +37,25 @@ class ChainCache implements CacheInterface, PruneableInterface, ResettableInterf
     private $cacheCount;
 
     /**
-     * @param CacheInterface[] $caches          The ordered list of caches used to fetch cached items
-     * @param int              $defaultLifetime The lifetime of items propagated from lower caches to upper ones
+     * @param Psr16CacheInterface[] $caches          The ordered list of caches used to fetch cached items
+     * @param int                   $defaultLifetime The lifetime of items propagated from lower caches to upper ones
      */
-    public function __construct(array $caches, $defaultLifetime = 0)
+    public function __construct(array $caches, int $defaultLifetime = 0)
     {
         if (!$caches) {
             throw new InvalidArgumentException('At least one cache must be specified.');
         }
 
         foreach ($caches as $cache) {
-            if (!$cache instanceof CacheInterface) {
-                throw new InvalidArgumentException(sprintf('The class "%s" does not implement the "%s" interface.', \get_class($cache), CacheInterface::class));
+            if (!$cache instanceof Psr16CacheInterface) {
+                throw new InvalidArgumentException(sprintf('The class "%s" does not implement the "%s" interface.', \get_class($cache), Psr16CacheInterface::class));
             }
         }
 
         $this->miss = new \stdClass();
         $this->caches = array_values($caches);
         $this->cacheCount = \count($this->caches);
-        $this->defaultLifetime = 0 < $defaultLifetime ? (int) $defaultLifetime : null;
+        $this->defaultLifetime = 0 < $defaultLifetime ? $defaultLifetime : null;
     }
 
     /**
@@ -77,6 +82,8 @@ class ChainCache implements CacheInterface, PruneableInterface, ResettableInterf
 
     /**
      * {@inheritdoc}
+     *
+     * @return iterable
      */
     public function getMultiple($keys, $default = null)
     {
@@ -85,11 +92,11 @@ class ChainCache implements CacheInterface, PruneableInterface, ResettableInterf
         return $this->generateItems($this->caches[0]->getMultiple($keys, $miss), 0, $miss, $default);
     }
 
-    private function generateItems($values, $cacheIndex, $miss, $default)
+    private function generateItems(iterable $values, int $cacheIndex, $miss, $default): iterable
     {
         $missing = [];
         $nextCacheIndex = $cacheIndex + 1;
-        $nextCache = isset($this->caches[$nextCacheIndex]) ? $this->caches[$nextCacheIndex] : null;
+        $nextCache = $this->caches[$nextCacheIndex] ?? null;
 
         foreach ($values as $k => $value) {
             if ($miss !== $value) {
@@ -118,6 +125,8 @@ class ChainCache implements CacheInterface, PruneableInterface, ResettableInterf
 
     /**
      * {@inheritdoc}
+     *
+     * @return bool
      */
     public function has($key)
     {
@@ -132,6 +141,8 @@ class ChainCache implements CacheInterface, PruneableInterface, ResettableInterf
 
     /**
      * {@inheritdoc}
+     *
+     * @return bool
      */
     public function clear()
     {
@@ -147,6 +158,8 @@ class ChainCache implements CacheInterface, PruneableInterface, ResettableInterf
 
     /**
      * {@inheritdoc}
+     *
+     * @return bool
      */
     public function delete($key)
     {
@@ -162,6 +175,8 @@ class ChainCache implements CacheInterface, PruneableInterface, ResettableInterf
 
     /**
      * {@inheritdoc}
+     *
+     * @return bool
      */
     public function deleteMultiple($keys)
     {
@@ -180,6 +195,8 @@ class ChainCache implements CacheInterface, PruneableInterface, ResettableInterf
 
     /**
      * {@inheritdoc}
+     *
+     * @return bool
      */
     public function set($key, $value, $ttl = null)
     {
@@ -195,6 +212,8 @@ class ChainCache implements CacheInterface, PruneableInterface, ResettableInterf
 
     /**
      * {@inheritdoc}
+     *
+     * @return bool
      */
     public function setMultiple($values, $ttl = null)
     {
@@ -244,7 +263,7 @@ class ChainCache implements CacheInterface, PruneableInterface, ResettableInterf
     public function reset()
     {
         foreach ($this->caches as $cache) {
-            if ($cache instanceof ResettableInterface) {
+            if ($cache instanceof ResetInterface) {
                 $cache->reset();
             }
         }
index ea1a4eda50ba6d748cd2c65bcebd3811ad7300d6..d7feb4d3b002c76b4360f2cc8a2f951e1c9a8508 100644 (file)
 namespace Symfony\Component\Cache\Simple;
 
 use Doctrine\Common\Cache\CacheProvider;
+use Symfony\Component\Cache\Adapter\DoctrineAdapter;
 use Symfony\Component\Cache\Traits\DoctrineTrait;
+use Symfony\Contracts\Cache\CacheInterface;
 
+@trigger_error(sprintf('The "%s" class is deprecated since Symfony 4.3, use "%s" and type-hint for "%s" instead.', DoctrineCache::class, DoctrineAdapter::class, CacheInterface::class), \E_USER_DEPRECATED);
+
+/**
+ * @deprecated since Symfony 4.3, use DoctrineAdapter and type-hint for CacheInterface instead.
+ */
 class DoctrineCache extends AbstractCache
 {
     use DoctrineTrait;
 
-    /**
-     * @param string $namespace
-     * @param int    $defaultLifetime
-     */
-    public function __construct(CacheProvider $provider, $namespace = '', $defaultLifetime = 0)
+    public function __construct(CacheProvider $provider, string $namespace = '', int $defaultLifetime = 0)
     {
         parent::__construct('', $defaultLifetime);
         $this->provider = $provider;
index ccd579534288ed82e3927ae32c1f12d3f8759f3e..fcc8a17028636a59c4fe28769061e082fcf0c6c8 100644 (file)
 
 namespace Symfony\Component\Cache\Simple;
 
+use Symfony\Component\Cache\Adapter\FilesystemAdapter;
+use Symfony\Component\Cache\Marshaller\DefaultMarshaller;
+use Symfony\Component\Cache\Marshaller\MarshallerInterface;
 use Symfony\Component\Cache\PruneableInterface;
 use Symfony\Component\Cache\Traits\FilesystemTrait;
+use Symfony\Contracts\Cache\CacheInterface;
 
+@trigger_error(sprintf('The "%s" class is deprecated since Symfony 4.3, use "%s" and type-hint for "%s" instead.', FilesystemCache::class, FilesystemAdapter::class, CacheInterface::class), \E_USER_DEPRECATED);
+
+/**
+ * @deprecated since Symfony 4.3, use FilesystemAdapter and type-hint for CacheInterface instead.
+ */
 class FilesystemCache extends AbstractCache implements PruneableInterface
 {
     use FilesystemTrait;
 
-    /**
-     * @param string      $namespace
-     * @param int         $defaultLifetime
-     * @param string|null $directory
-     */
-    public function __construct($namespace = '', $defaultLifetime = 0, $directory = null)
+    public function __construct(string $namespace = '', int $defaultLifetime = 0, string $directory = null, MarshallerInterface $marshaller = null)
     {
+        $this->marshaller = $marshaller ?? new DefaultMarshaller();
         parent::__construct('', $defaultLifetime);
         $this->init($namespace, $directory);
     }
index 94a9f297d7a12e32f7b688f13b0d65f8dd8eca0e..1f636486cb3bbc5eb38294ac9434288b5176fb14 100644 (file)
 
 namespace Symfony\Component\Cache\Simple;
 
+use Symfony\Component\Cache\Adapter\MemcachedAdapter;
+use Symfony\Component\Cache\Marshaller\MarshallerInterface;
 use Symfony\Component\Cache\Traits\MemcachedTrait;
+use Symfony\Contracts\Cache\CacheInterface;
 
+@trigger_error(sprintf('The "%s" class is deprecated since Symfony 4.3, use "%s" and type-hint for "%s" instead.', MemcachedCache::class, MemcachedAdapter::class, CacheInterface::class), \E_USER_DEPRECATED);
+
+/**
+ * @deprecated since Symfony 4.3, use MemcachedAdapter and type-hint for CacheInterface instead.
+ */
 class MemcachedCache extends AbstractCache
 {
     use MemcachedTrait;
 
     protected $maxIdLength = 250;
 
-    /**
-     * @param string $namespace
-     * @param int    $defaultLifetime
-     */
-    public function __construct(\Memcached $client, $namespace = '', $defaultLifetime = 0)
+    public function __construct(\Memcached $client, string $namespace = '', int $defaultLifetime = 0, MarshallerInterface $marshaller = null)
     {
-        $this->init($client, $namespace, $defaultLifetime);
+        $this->init($client, $namespace, $defaultLifetime, $marshaller);
     }
 }
index fa986aebd11b0159724ccd78e4da7e47c2f22ec6..fcbd39d56d8bc5551d75f51c61b361c7d60ae732 100644 (file)
 
 namespace Symfony\Component\Cache\Simple;
 
-use Psr\SimpleCache\CacheInterface;
+use Psr\SimpleCache\CacheInterface as Psr16CacheInterface;
+use Symfony\Component\Cache\Adapter\NullAdapter;
+use Symfony\Contracts\Cache\CacheInterface;
+
+@trigger_error(sprintf('The "%s" class is deprecated since Symfony 4.3, use "%s" and type-hint for "%s" instead.', NullCache::class, NullAdapter::class, CacheInterface::class), \E_USER_DEPRECATED);
 
 /**
- * @author Nicolas Grekas <p@tchwork.com>
+ * @deprecated since Symfony 4.3, use NullAdapter and type-hint for CacheInterface instead.
  */
-class NullCache implements CacheInterface
+class NullCache implements Psr16CacheInterface
 {
     /**
      * {@inheritdoc}
@@ -28,6 +32,8 @@ class NullCache implements CacheInterface
 
     /**
      * {@inheritdoc}
+     *
+     * @return iterable
      */
     public function getMultiple($keys, $default = null)
     {
@@ -38,6 +44,8 @@ class NullCache implements CacheInterface
 
     /**
      * {@inheritdoc}
+     *
+     * @return bool
      */
     public function has($key)
     {
@@ -46,6 +54,8 @@ class NullCache implements CacheInterface
 
     /**
      * {@inheritdoc}
+     *
+     * @return bool
      */
     public function clear()
     {
@@ -54,6 +64,8 @@ class NullCache implements CacheInterface
 
     /**
      * {@inheritdoc}
+     *
+     * @return bool
      */
     public function delete($key)
     {
@@ -62,6 +74,8 @@ class NullCache implements CacheInterface
 
     /**
      * {@inheritdoc}
+     *
+     * @return bool
      */
     public function deleteMultiple($keys)
     {
@@ -70,6 +84,8 @@ class NullCache implements CacheInterface
 
     /**
      * {@inheritdoc}
+     *
+     * @return bool
      */
     public function set($key, $value, $ttl = null)
     {
@@ -78,6 +94,8 @@ class NullCache implements CacheInterface
 
     /**
      * {@inheritdoc}
+     *
+     * @return bool
      */
     public function setMultiple($values, $ttl = null)
     {
index c92e049a1ba12fcd7c15a1c2052a5ded6e8a927d..7011ea07c45aea87e136f499db8707ddfe9c8240 100644 (file)
 
 namespace Symfony\Component\Cache\Simple;
 
+use Symfony\Component\Cache\Adapter\PdoAdapter;
+use Symfony\Component\Cache\Marshaller\MarshallerInterface;
 use Symfony\Component\Cache\PruneableInterface;
 use Symfony\Component\Cache\Traits\PdoTrait;
+use Symfony\Contracts\Cache\CacheInterface;
 
+@trigger_error(sprintf('The "%s" class is deprecated since Symfony 4.3, use "%s" and type-hint for "%s" instead.', PdoCache::class, PdoAdapter::class, CacheInterface::class), \E_USER_DEPRECATED);
+
+/**
+ * @deprecated since Symfony 4.3, use PdoAdapter and type-hint for CacheInterface instead.
+ */
 class PdoCache extends AbstractCache implements PruneableInterface
 {
     use PdoTrait;
@@ -25,6 +33,9 @@ class PdoCache extends AbstractCache implements PruneableInterface
      * a Doctrine DBAL Connection or a DSN string that will be used to
      * lazy-connect to the database when the cache is actually used.
      *
+     * When a Doctrine DBAL Connection is passed, the cache table is created
+     * automatically when possible. Otherwise, use the createTable() method.
+     *
      * List of available options:
      *  * db_table: The name of the table [default: cache_items]
      *  * db_id_col: The column where to store the cache id [default: item_id]
@@ -35,17 +46,14 @@ class PdoCache extends AbstractCache implements PruneableInterface
      *  * db_password: The password when lazy-connect [default: '']
      *  * db_connection_options: An array of driver-specific connection options [default: []]
      *
-     * @param \PDO|Connection|string $connOrDsn       A \PDO or Connection instance or DSN string or null
-     * @param string                 $namespace
-     * @param int                    $defaultLifetime
-     * @param array                  $options         An associative array of options
+     * @param \PDO|Connection|string $connOrDsn a \PDO or Connection instance or DSN string or null
      *
      * @throws InvalidArgumentException When first argument is not PDO nor Connection nor string
      * @throws InvalidArgumentException When PDO error mode is not PDO::ERRMODE_EXCEPTION
      * @throws InvalidArgumentException When namespace contains invalid characters
      */
-    public function __construct($connOrDsn, $namespace = '', $defaultLifetime = 0, array $options = [])
+    public function __construct($connOrDsn, string $namespace = '', int $defaultLifetime = 0, array $options = [], MarshallerInterface $marshaller = null)
     {
-        $this->init($connOrDsn, $namespace, $defaultLifetime, $options);
+        $this->init($connOrDsn, $namespace, $defaultLifetime, $options, $marshaller);
     }
 }
index 7bb25ff80e85caabf7e8cac6ff3d74278a584477..10c7340a0aa2bfa5c27ae013213828507f1e2a7e 100644 (file)
 
 namespace Symfony\Component\Cache\Simple;
 
-use Psr\SimpleCache\CacheInterface;
+use Psr\SimpleCache\CacheInterface as Psr16CacheInterface;
+use Symfony\Component\Cache\Adapter\PhpArrayAdapter;
 use Symfony\Component\Cache\Exception\InvalidArgumentException;
 use Symfony\Component\Cache\PruneableInterface;
 use Symfony\Component\Cache\ResettableInterface;
 use Symfony\Component\Cache\Traits\PhpArrayTrait;
+use Symfony\Contracts\Cache\CacheInterface;
+
+@trigger_error(sprintf('The "%s" class is deprecated since Symfony 4.3, use "%s" and type-hint for "%s" instead.', PhpArrayCache::class, PhpArrayAdapter::class, CacheInterface::class), \E_USER_DEPRECATED);
 
 /**
- * Caches items at warm up time using a PHP array that is stored in shared memory by OPCache since PHP 7.0.
- * Warmed up items are read-only and run-time discovered items are cached using a fallback adapter.
- *
- * @author Titouan Galopin <galopintitouan@gmail.com>
- * @author Nicolas Grekas <p@tchwork.com>
+ * @deprecated since Symfony 4.3, use PhpArrayAdapter and type-hint for CacheInterface instead.
  */
-class PhpArrayCache implements CacheInterface, PruneableInterface, ResettableInterface
+class PhpArrayCache implements Psr16CacheInterface, PruneableInterface, ResettableInterface
 {
     use PhpArrayTrait;
 
     /**
-     * @param string         $file         The PHP file were values are cached
-     * @param CacheInterface $fallbackPool A pool to fallback on when an item is not hit
+     * @param string              $file         The PHP file were values are cached
+     * @param Psr16CacheInterface $fallbackPool A pool to fallback on when an item is not hit
      */
-    public function __construct($file, CacheInterface $fallbackPool)
+    public function __construct(string $file, Psr16CacheInterface $fallbackPool)
     {
         $this->file = $file;
         $this->pool = $fallbackPool;
-        $this->zendDetectUnicode = filter_var(ini_get('zend.detect_unicode'), \FILTER_VALIDATE_BOOLEAN);
     }
 
     /**
-     * This adapter should only be used on PHP 7.0+ to take advantage of how PHP
-     * stores arrays in its latest versions. This factory method decorates the given
-     * fallback pool with this adapter only if the current PHP version is supported.
+     * This adapter takes advantage of how PHP stores arrays in its latest versions.
      *
      * @param string         $file         The PHP file were values are cached
      * @param CacheInterface $fallbackPool A pool to fallback on when an item is not hit
      *
-     * @return CacheInterface
+     * @return Psr16CacheInterface
      */
-    public static function create($file, CacheInterface $fallbackPool)
+    public static function create($file, Psr16CacheInterface $fallbackPool)
     {
-        if (\PHP_VERSION_ID >= 70000) {
-            return new static($file, $fallbackPool);
-        }
-
-        return $fallbackPool;
+        return new static($file, $fallbackPool);
     }
 
     /**
@@ -69,22 +62,18 @@ class PhpArrayCache implements CacheInterface, PruneableInterface, ResettableInt
         if (null === $this->values) {
             $this->initialize();
         }
-        if (!isset($this->values[$key])) {
+        if (!isset($this->keys[$key])) {
             return $this->pool->get($key, $default);
         }
-
-        $value = $this->values[$key];
+        $value = $this->values[$this->keys[$key]];
 
         if ('N;' === $value) {
-            $value = null;
-        } elseif (\is_string($value) && isset($value[2]) && ':' === $value[1]) {
+            return null;
+        }
+        if ($value instanceof \Closure) {
             try {
-                $e = null;
-                $value = unserialize($value);
-            } catch (\Error $e) {
-            } catch (\Exception $e) {
-            }
-            if (null !== $e) {
+                return $value();
+            } catch (\Throwable $e) {
                 return $default;
             }
         }
@@ -94,6 +83,8 @@ class PhpArrayCache implements CacheInterface, PruneableInterface, ResettableInt
 
     /**
      * {@inheritdoc}
+     *
+     * @return iterable
      */
     public function getMultiple($keys, $default = null)
     {
@@ -116,6 +107,8 @@ class PhpArrayCache implements CacheInterface, PruneableInterface, ResettableInt
 
     /**
      * {@inheritdoc}
+     *
+     * @return bool
      */
     public function has($key)
     {
@@ -126,11 +119,13 @@ class PhpArrayCache implements CacheInterface, PruneableInterface, ResettableInt
             $this->initialize();
         }
 
-        return isset($this->values[$key]) || $this->pool->has($key);
+        return isset($this->keys[$key]) || $this->pool->has($key);
     }
 
     /**
      * {@inheritdoc}
+     *
+     * @return bool
      */
     public function delete($key)
     {
@@ -141,11 +136,13 @@ class PhpArrayCache implements CacheInterface, PruneableInterface, ResettableInt
             $this->initialize();
         }
 
-        return !isset($this->values[$key]) && $this->pool->delete($key);
+        return !isset($this->keys[$key]) && $this->pool->delete($key);
     }
 
     /**
      * {@inheritdoc}
+     *
+     * @return bool
      */
     public function deleteMultiple($keys)
     {
@@ -161,7 +158,7 @@ class PhpArrayCache implements CacheInterface, PruneableInterface, ResettableInt
                 throw new InvalidArgumentException(sprintf('Cache key must be string, "%s" given.', \is_object($key) ? \get_class($key) : \gettype($key)));
             }
 
-            if (isset($this->values[$key])) {
+            if (isset($this->keys[$key])) {
                 $deleted = false;
             } else {
                 $fallbackKeys[] = $key;
@@ -180,6 +177,8 @@ class PhpArrayCache implements CacheInterface, PruneableInterface, ResettableInt
 
     /**
      * {@inheritdoc}
+     *
+     * @return bool
      */
     public function set($key, $value, $ttl = null)
     {
@@ -190,11 +189,13 @@ class PhpArrayCache implements CacheInterface, PruneableInterface, ResettableInt
             $this->initialize();
         }
 
-        return !isset($this->values[$key]) && $this->pool->set($key, $value, $ttl);
+        return !isset($this->keys[$key]) && $this->pool->set($key, $value, $ttl);
     }
 
     /**
      * {@inheritdoc}
+     *
+     * @return bool
      */
     public function setMultiple($values, $ttl = null)
     {
@@ -210,7 +211,7 @@ class PhpArrayCache implements CacheInterface, PruneableInterface, ResettableInt
                 throw new InvalidArgumentException(sprintf('Cache key must be string, "%s" given.', \is_object($key) ? \get_class($key) : \gettype($key)));
             }
 
-            if (isset($this->values[$key])) {
+            if (isset($this->keys[$key])) {
                 $saved = false;
             } else {
                 $fallbackValues[$key] = $value;
@@ -224,22 +225,20 @@ class PhpArrayCache implements CacheInterface, PruneableInterface, ResettableInt
         return $saved;
     }
 
-    private function generateItems(array $keys, $default)
+    private function generateItems(array $keys, $default): iterable
     {
         $fallbackKeys = [];
 
         foreach ($keys as $key) {
-            if (isset($this->values[$key])) {
-                $value = $this->values[$key];
+            if (isset($this->keys[$key])) {
+                $value = $this->values[$this->keys[$key]];
 
                 if ('N;' === $value) {
                     yield $key => null;
-                } elseif (\is_string($value) && isset($value[2]) && ':' === $value[1]) {
+                } elseif ($value instanceof \Closure) {
                     try {
-                        yield $key => unserialize($value);
-                    } catch (\Error $e) {
-                        yield $key => $default;
-                    } catch (\Exception $e) {
+                        yield $key => $value();
+                    } catch (\Throwable $e) {
                         yield $key => $default;
                     }
                 } else {
@@ -251,9 +250,7 @@ class PhpArrayCache implements CacheInterface, PruneableInterface, ResettableInt
         }
 
         if ($fallbackKeys) {
-            foreach ($this->pool->getMultiple($fallbackKeys, $default) as $key => $item) {
-                yield $key => $item;
-            }
+            yield from $this->pool->getMultiple($fallbackKeys, $default);
         }
     }
 }
index 50c19034a86df7275b5722a2c36be687ae55b57f..9c79ae9a154e5944499771a7a2ad4c92bcdfa8e1 100644 (file)
 
 namespace Symfony\Component\Cache\Simple;
 
+use Symfony\Component\Cache\Adapter\PhpFilesAdapter;
 use Symfony\Component\Cache\Exception\CacheException;
 use Symfony\Component\Cache\PruneableInterface;
 use Symfony\Component\Cache\Traits\PhpFilesTrait;
+use Symfony\Contracts\Cache\CacheInterface;
 
+@trigger_error(sprintf('The "%s" class is deprecated since Symfony 4.3, use "%s" and type-hint for "%s" instead.', PhpFilesCache::class, PhpFilesAdapter::class, CacheInterface::class), \E_USER_DEPRECATED);
+
+/**
+ * @deprecated since Symfony 4.3, use PhpFilesAdapter and type-hint for CacheInterface instead.
+ */
 class PhpFilesCache extends AbstractCache implements PruneableInterface
 {
     use PhpFilesTrait;
 
     /**
-     * @param string      $namespace
-     * @param int         $defaultLifetime
-     * @param string|null $directory
+     * @param $appendOnly Set to `true` to gain extra performance when the items stored in this pool never expire.
+     *                    Doing so is encouraged because it fits perfectly OPcache's memory model.
      *
      * @throws CacheException if OPcache is not enabled
      */
-    public function __construct($namespace = '', $defaultLifetime = 0, $directory = null)
+    public function __construct(string $namespace = '', int $defaultLifetime = 0, string $directory = null, bool $appendOnly = false)
     {
-        if (!static::isSupported()) {
-            throw new CacheException('OPcache is not enabled.');
-        }
+        $this->appendOnly = $appendOnly;
+        self::$startTime = self::$startTime ?? $_SERVER['REQUEST_TIME'] ?? time();
         parent::__construct('', $defaultLifetime);
         $this->init($namespace, $directory);
-
-        $e = new \Exception();
-        $this->includeHandler = function () use ($e) { throw $e; };
-        $this->zendDetectUnicode = filter_var(ini_get('zend.detect_unicode'), \FILTER_VALIDATE_BOOLEAN);
+        $this->includeHandler = static function ($type, $msg, $file, $line) {
+            throw new \ErrorException($msg, 0, $type, $file, $line);
+        };
     }
 }
index 6b3de205998553cc61d4912c557df54376bf85f9..366284b2bf183839bec444576d06a39889fca6da 100644 (file)
 
 namespace Symfony\Component\Cache\Simple;
 
-use Psr\Cache\CacheException as Psr6CacheException;
-use Psr\Cache\CacheItemPoolInterface;
-use Psr\SimpleCache\CacheException as SimpleCacheException;
-use Psr\SimpleCache\CacheInterface;
-use Symfony\Component\Cache\Adapter\AdapterInterface;
-use Symfony\Component\Cache\CacheItem;
-use Symfony\Component\Cache\Exception\InvalidArgumentException;
-use Symfony\Component\Cache\PruneableInterface;
-use Symfony\Component\Cache\ResettableInterface;
-use Symfony\Component\Cache\Traits\ProxyTrait;
+use Symfony\Component\Cache\Psr16Cache;
+
+@trigger_error(sprintf('The "%s" class is deprecated since Symfony 4.3, use "%s" instead.', Psr6Cache::class, Psr16Cache::class), \E_USER_DEPRECATED);
 
 /**
- * @author Nicolas Grekas <p@tchwork.com>
+ * @deprecated since Symfony 4.3, use Psr16Cache instead.
  */
-class Psr6Cache implements CacheInterface, PruneableInterface, ResettableInterface
+class Psr6Cache extends Psr16Cache
 {
-    use ProxyTrait;
-
-    private $createCacheItem;
-    private $cacheItemPrototype;
-
-    public function __construct(CacheItemPoolInterface $pool)
-    {
-        $this->pool = $pool;
-
-        if (!$pool instanceof AdapterInterface) {
-            return;
-        }
-        $cacheItemPrototype = &$this->cacheItemPrototype;
-        $createCacheItem = \Closure::bind(
-            static function ($key, $value, $allowInt = false) use (&$cacheItemPrototype) {
-                $item = clone $cacheItemPrototype;
-                $item->key = $allowInt && \is_int($key) ? (string) $key : CacheItem::validateKey($key);
-                $item->value = $value;
-                $item->isHit = false;
-
-                return $item;
-            },
-            null,
-            CacheItem::class
-        );
-        $this->createCacheItem = function ($key, $value, $allowInt = false) use ($createCacheItem) {
-            if (null === $this->cacheItemPrototype) {
-                $this->get($allowInt && \is_int($key) ? (string) $key : $key);
-            }
-            $this->createCacheItem = $createCacheItem;
-
-            return $createCacheItem($key, $value, $allowInt);
-        };
-    }
-
-    /**
-     * {@inheritdoc}
-     */
-    public function get($key, $default = null)
-    {
-        try {
-            $item = $this->pool->getItem($key);
-        } catch (SimpleCacheException $e) {
-            throw $e;
-        } catch (Psr6CacheException $e) {
-            throw new InvalidArgumentException($e->getMessage(), $e->getCode(), $e);
-        }
-        if (null === $this->cacheItemPrototype) {
-            $this->cacheItemPrototype = clone $item;
-            $this->cacheItemPrototype->set(null);
-        }
-
-        return $item->isHit() ? $item->get() : $default;
-    }
-
-    /**
-     * {@inheritdoc}
-     */
-    public function set($key, $value, $ttl = null)
-    {
-        try {
-            if (null !== $f = $this->createCacheItem) {
-                $item = $f($key, $value);
-            } else {
-                $item = $this->pool->getItem($key)->set($value);
-            }
-        } catch (SimpleCacheException $e) {
-            throw $e;
-        } catch (Psr6CacheException $e) {
-            throw new InvalidArgumentException($e->getMessage(), $e->getCode(), $e);
-        }
-        if (null !== $ttl) {
-            $item->expiresAfter($ttl);
-        }
-
-        return $this->pool->save($item);
-    }
-
-    /**
-     * {@inheritdoc}
-     */
-    public function delete($key)
-    {
-        try {
-            return $this->pool->deleteItem($key);
-        } catch (SimpleCacheException $e) {
-            throw $e;
-        } catch (Psr6CacheException $e) {
-            throw new InvalidArgumentException($e->getMessage(), $e->getCode(), $e);
-        }
-    }
-
-    /**
-     * {@inheritdoc}
-     */
-    public function clear()
-    {
-        return $this->pool->clear();
-    }
-
-    /**
-     * {@inheritdoc}
-     */
-    public function getMultiple($keys, $default = null)
-    {
-        if ($keys instanceof \Traversable) {
-            $keys = iterator_to_array($keys, false);
-        } elseif (!\is_array($keys)) {
-            throw new InvalidArgumentException(sprintf('Cache keys must be array or Traversable, "%s" given.', \is_object($keys) ? \get_class($keys) : \gettype($keys)));
-        }
-
-        try {
-            $items = $this->pool->getItems($keys);
-        } catch (SimpleCacheException $e) {
-            throw $e;
-        } catch (Psr6CacheException $e) {
-            throw new InvalidArgumentException($e->getMessage(), $e->getCode(), $e);
-        }
-        $values = [];
-
-        foreach ($items as $key => $item) {
-            $values[$key] = $item->isHit() ? $item->get() : $default;
-        }
-
-        return $values;
-    }
-
-    /**
-     * {@inheritdoc}
-     */
-    public function setMultiple($values, $ttl = null)
-    {
-        $valuesIsArray = \is_array($values);
-        if (!$valuesIsArray && !$values instanceof \Traversable) {
-            throw new InvalidArgumentException(sprintf('Cache values must be array or Traversable, "%s" given.', \is_object($values) ? \get_class($values) : \gettype($values)));
-        }
-        $items = [];
-
-        try {
-            if (null !== $f = $this->createCacheItem) {
-                $valuesIsArray = false;
-                foreach ($values as $key => $value) {
-                    $items[$key] = $f($key, $value, true);
-                }
-            } elseif ($valuesIsArray) {
-                $items = [];
-                foreach ($values as $key => $value) {
-                    $items[] = (string) $key;
-                }
-                $items = $this->pool->getItems($items);
-            } else {
-                foreach ($values as $key => $value) {
-                    if (\is_int($key)) {
-                        $key = (string) $key;
-                    }
-                    $items[$key] = $this->pool->getItem($key)->set($value);
-                }
-            }
-        } catch (SimpleCacheException $e) {
-            throw $e;
-        } catch (Psr6CacheException $e) {
-            throw new InvalidArgumentException($e->getMessage(), $e->getCode(), $e);
-        }
-        $ok = true;
-
-        foreach ($items as $key => $item) {
-            if ($valuesIsArray) {
-                $item->set($values[$key]);
-            }
-            if (null !== $ttl) {
-                $item->expiresAfter($ttl);
-            }
-            $ok = $this->pool->saveDeferred($item) && $ok;
-        }
-
-        return $this->pool->commit() && $ok;
-    }
-
-    /**
-     * {@inheritdoc}
-     */
-    public function deleteMultiple($keys)
-    {
-        if ($keys instanceof \Traversable) {
-            $keys = iterator_to_array($keys, false);
-        } elseif (!\is_array($keys)) {
-            throw new InvalidArgumentException(sprintf('Cache keys must be array or Traversable, "%s" given.', \is_object($keys) ? \get_class($keys) : \gettype($keys)));
-        }
-
-        try {
-            return $this->pool->deleteItems($keys);
-        } catch (SimpleCacheException $e) {
-            throw $e;
-        } catch (Psr6CacheException $e) {
-            throw new InvalidArgumentException($e->getMessage(), $e->getCode(), $e);
-        }
-    }
-
-    /**
-     * {@inheritdoc}
-     */
-    public function has($key)
-    {
-        try {
-            return $this->pool->hasItem($key);
-        } catch (SimpleCacheException $e) {
-            throw $e;
-        } catch (Psr6CacheException $e) {
-            throw new InvalidArgumentException($e->getMessage(), $e->getCode(), $e);
-        }
-    }
 }
index e82c0627e241d5b34475108b1db54c99da46ff12..e0a76fd62a54de75495c1056f0a2aa716fc91aaa 100644 (file)
 
 namespace Symfony\Component\Cache\Simple;
 
+use Symfony\Component\Cache\Adapter\RedisAdapter;
+use Symfony\Component\Cache\Marshaller\MarshallerInterface;
+use Symfony\Component\Cache\Traits\RedisClusterProxy;
+use Symfony\Component\Cache\Traits\RedisProxy;
 use Symfony\Component\Cache\Traits\RedisTrait;
+use Symfony\Contracts\Cache\CacheInterface;
 
+@trigger_error(sprintf('The "%s" class is deprecated since Symfony 4.3, use "%s" and type-hint for "%s" instead.', RedisCache::class, RedisAdapter::class, CacheInterface::class), \E_USER_DEPRECATED);
+
+/**
+ * @deprecated since Symfony 4.3, use RedisAdapter and type-hint for CacheInterface instead.
+ */
 class RedisCache extends AbstractCache
 {
     use RedisTrait;
 
     /**
-     * @param \Redis|\RedisArray|\RedisCluster|\Predis\Client $redisClient
-     * @param string                                          $namespace
-     * @param int                                             $defaultLifetime
+     * @param \Redis|\RedisArray|\RedisCluster|\Predis\ClientInterface|RedisProxy|RedisClusterProxy $redis
      */
-    public function __construct($redisClient, $namespace = '', $defaultLifetime = 0)
+    public function __construct($redis, string $namespace = '', int $defaultLifetime = 0, MarshallerInterface $marshaller = null)
     {
-        $this->init($redisClient, $namespace, $defaultLifetime);
+        $this->init($redis, $namespace, $defaultLifetime, $marshaller);
     }
 }
index 61b22963eb3293e6f86f423d85c33fdd60c8cd6b..0dae813ecd927e452040b1611aac99f4f0279fc7 100644 (file)
 
 namespace Symfony\Component\Cache\Simple;
 
-use Psr\SimpleCache\CacheInterface;
+use Psr\SimpleCache\CacheInterface as Psr16CacheInterface;
+use Symfony\Component\Cache\Adapter\TraceableAdapter;
 use Symfony\Component\Cache\PruneableInterface;
 use Symfony\Component\Cache\ResettableInterface;
+use Symfony\Contracts\Cache\CacheInterface;
+use Symfony\Contracts\Service\ResetInterface;
+
+@trigger_error(sprintf('The "%s" class is deprecated since Symfony 4.3, use "%s" and type-hint for "%s" instead.', TraceableCache::class, TraceableAdapter::class, CacheInterface::class), \E_USER_DEPRECATED);
 
 /**
- * An adapter that collects data about all cache calls.
- *
- * @author Nicolas Grekas <p@tchwork.com>
+ * @deprecated since Symfony 4.3, use TraceableAdapter and type-hint for CacheInterface instead.
  */
-class TraceableCache implements CacheInterface, PruneableInterface, ResettableInterface
+class TraceableCache implements Psr16CacheInterface, PruneableInterface, ResettableInterface
 {
     private $pool;
     private $miss;
     private $calls = [];
 
-    public function __construct(CacheInterface $pool)
+    public function __construct(Psr16CacheInterface $pool)
     {
         $this->pool = $pool;
         $this->miss = new \stdClass();
@@ -56,6 +59,8 @@ class TraceableCache implements CacheInterface, PruneableInterface, ResettableIn
 
     /**
      * {@inheritdoc}
+     *
+     * @return bool
      */
     public function has($key)
     {
@@ -69,6 +74,8 @@ class TraceableCache implements CacheInterface, PruneableInterface, ResettableIn
 
     /**
      * {@inheritdoc}
+     *
+     * @return bool
      */
     public function delete($key)
     {
@@ -82,6 +89,8 @@ class TraceableCache implements CacheInterface, PruneableInterface, ResettableIn
 
     /**
      * {@inheritdoc}
+     *
+     * @return bool
      */
     public function set($key, $value, $ttl = null)
     {
@@ -95,6 +104,8 @@ class TraceableCache implements CacheInterface, PruneableInterface, ResettableIn
 
     /**
      * {@inheritdoc}
+     *
+     * @return bool
      */
     public function setMultiple($values, $ttl = null)
     {
@@ -122,6 +133,8 @@ class TraceableCache implements CacheInterface, PruneableInterface, ResettableIn
 
     /**
      * {@inheritdoc}
+     *
+     * @return iterable
      */
     public function getMultiple($keys, $default = null)
     {
@@ -150,6 +163,8 @@ class TraceableCache implements CacheInterface, PruneableInterface, ResettableIn
 
     /**
      * {@inheritdoc}
+     *
+     * @return bool
      */
     public function clear()
     {
@@ -163,6 +178,8 @@ class TraceableCache implements CacheInterface, PruneableInterface, ResettableIn
 
     /**
      * {@inheritdoc}
+     *
+     * @return bool
      */
     public function deleteMultiple($keys)
     {
@@ -200,7 +217,7 @@ class TraceableCache implements CacheInterface, PruneableInterface, ResettableIn
      */
     public function reset()
     {
-        if (!$this->pool instanceof ResettableInterface) {
+        if (!$this->pool instanceof ResetInterface) {
             return;
         }
         $event = $this->start(__FUNCTION__);
@@ -220,7 +237,7 @@ class TraceableCache implements CacheInterface, PruneableInterface, ResettableIn
         }
     }
 
-    private function start($name)
+    private function start(string $name): TraceableCacheEvent
     {
         $this->calls[] = $event = new TraceableCacheEvent();
         $event->name = $name;
diff --git a/advancedcontentfilter/vendor/symfony/cache/Traits/AbstractAdapterTrait.php b/advancedcontentfilter/vendor/symfony/cache/Traits/AbstractAdapterTrait.php
new file mode 100644 (file)
index 0000000..388c1df
--- /dev/null
@@ -0,0 +1,164 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien@symfony.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Cache\Traits;
+
+use Psr\Cache\CacheItemInterface;
+use Symfony\Component\Cache\CacheItem;
+use Symfony\Component\Cache\Exception\InvalidArgumentException;
+
+/**
+ * @author Nicolas Grekas <p@tchwork.com>
+ *
+ * @internal
+ */
+trait AbstractAdapterTrait
+{
+    use AbstractTrait;
+
+    /**
+     * @var \Closure needs to be set by class, signature is function(string <key>, mixed <value>, bool <isHit>)
+     */
+    private $createCacheItem;
+
+    /**
+     * @var \Closure needs to be set by class, signature is function(array <deferred>, string <namespace>, array <&expiredIds>)
+     */
+    private $mergeByLifetime;
+
+    /**
+     * {@inheritdoc}
+     */
+    public function getItem($key)
+    {
+        $id = $this->getId($key);
+
+        if (isset($this->deferred[$key])) {
+            $this->commit();
+        }
+
+        $f = $this->createCacheItem;
+        $isHit = false;
+        $value = null;
+
+        try {
+            foreach ($this->doFetch([$id]) as $value) {
+                $isHit = true;
+            }
+
+            return $f($key, $value, $isHit);
+        } catch (\Exception $e) {
+            CacheItem::log($this->logger, 'Failed to fetch key "{key}": '.$e->getMessage(), ['key' => $key, 'exception' => $e]);
+        }
+
+        return $f($key, null, false);
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function getItems(array $keys = [])
+    {
+        $ids = [];
+        $commit = false;
+
+        foreach ($keys as $key) {
+            $ids[] = $this->getId($key);
+            $commit = $commit || isset($this->deferred[$key]);
+        }
+
+        if ($commit) {
+            $this->commit();
+        }
+
+        try {
+            $items = $this->doFetch($ids);
+        } catch (\Exception $e) {
+            CacheItem::log($this->logger, 'Failed to fetch items: '.$e->getMessage(), ['keys' => $keys, 'exception' => $e]);
+            $items = [];
+        }
+        $ids = array_combine($ids, $keys);
+
+        return $this->generateItems($items, $ids);
+    }
+
+    /**
+     * {@inheritdoc}
+     *
+     * @return bool
+     */
+    public function save(CacheItemInterface $item)
+    {
+        if (!$item instanceof CacheItem) {
+            return false;
+        }
+        $this->deferred[$item->getKey()] = $item;
+
+        return $this->commit();
+    }
+
+    /**
+     * {@inheritdoc}
+     *
+     * @return bool
+     */
+    public function saveDeferred(CacheItemInterface $item)
+    {
+        if (!$item instanceof CacheItem) {
+            return false;
+        }
+        $this->deferred[$item->getKey()] = $item;
+
+        return true;
+    }
+
+    /**
+     * @return array
+     */
+    public function __sleep()
+    {
+        throw new \BadMethodCallException('Cannot serialize '.__CLASS__);
+    }
+
+    public function __wakeup()
+    {
+        throw new \BadMethodCallException('Cannot unserialize '.__CLASS__);
+    }
+
+    public function __destruct()
+    {
+        if ($this->deferred) {
+            $this->commit();
+        }
+    }
+
+    private function generateItems(iterable $items, array &$keys): iterable
+    {
+        $f = $this->createCacheItem;
+
+        try {
+            foreach ($items as $id => $value) {
+                if (!isset($keys[$id])) {
+                    throw new InvalidArgumentException(sprintf('Could not match value id "%s" to keys "%s".', $id, implode('", "', $keys)));
+                }
+                $key = $keys[$id];
+                unset($keys[$id]);
+                yield $key => $f($key, $value, true);
+            }
+        } catch (\Exception $e) {
+            CacheItem::log($this->logger, 'Failed to fetch items: '.$e->getMessage(), ['keys' => array_values($keys), 'exception' => $e]);
+        }
+
+        foreach ($keys as $key) {
+            yield $key => $f($key, null, false);
+        }
+    }
+}
index dc291e103f3838f3e7158169e885a4b208ff4c4e..b047880661ff9c8d8bda2d96849e43e294b833da 100644 (file)
@@ -27,6 +27,7 @@ trait AbstractTrait
     private $namespaceVersion = '';
     private $versioningIsEnabled = false;
     private $deferred = [];
+    private $ids = [];
 
     /**
      * @var int|null The maximum length to enforce for identifiers or null when no limit applies
@@ -77,10 +78,12 @@ trait AbstractTrait
      *
      * @return array|bool The identifiers that failed to be cached or a boolean stating if caching succeeded or not
      */
-    abstract protected function doSave(array $values, $lifetime);
+    abstract protected function doSave(array $values, int $lifetime);
 
     /**
      * {@inheritdoc}
+     *
+     * @return bool
      */
     public function hasItem($key)
     {
@@ -93,7 +96,7 @@ trait AbstractTrait
         try {
             return $this->doHave($id);
         } catch (\Exception $e) {
-            CacheItem::log($this->logger, 'Failed to check if key "{key}" is cached', ['key' => $key, 'exception' => $e]);
+            CacheItem::log($this->logger, 'Failed to check if key "{key}" is cached: '.$e->getMessage(), ['key' => $key, 'exception' => $e]);
 
             return false;
         }
@@ -101,26 +104,43 @@ trait AbstractTrait
 
     /**
      * {@inheritdoc}
+     *
+     * @param string $prefix
+     *
+     * @return bool
      */
-    public function clear()
+    public function clear(/* string $prefix = '' */)
     {
         $this->deferred = [];
         if ($cleared = $this->versioningIsEnabled) {
-            $namespaceVersion = substr_replace(base64_encode(pack('V', mt_rand())), static::NS_SEPARATOR, 5);
+            if ('' === $namespaceVersionToClear = $this->namespaceVersion) {
+                foreach ($this->doFetch([static::NS_SEPARATOR.$this->namespace]) as $v) {
+                    $namespaceVersionToClear = $v;
+                }
+            }
+            $namespaceToClear = $this->namespace.$namespaceVersionToClear;
+            $namespaceVersion = self::formatNamespaceVersion(mt_rand());
             try {
-                $cleared = $this->doSave([static::NS_SEPARATOR.$this->namespace => $namespaceVersion], 0);
+                $e = $this->doSave([static::NS_SEPARATOR.$this->namespace => $namespaceVersion], 0);
             } catch (\Exception $e) {
-                $cleared = false;
             }
-            if ($cleared = true === $cleared || [] === $cleared) {
+            if (true !== $e && [] !== $e) {
+                $cleared = false;
+                $message = 'Failed to save the new namespace'.($e instanceof \Exception ? ': '.$e->getMessage() : '.');
+                CacheItem::log($this->logger, $message, ['exception' => $e instanceof \Exception ? $e : null]);
+            } else {
                 $this->namespaceVersion = $namespaceVersion;
+                $this->ids = [];
             }
+        } else {
+            $prefix = 0 < \func_num_args() ? (string) func_get_arg(0) : '';
+            $namespaceToClear = $this->namespace.$prefix;
         }
 
         try {
-            return $this->doClear($this->namespace) || $cleared;
+            return $this->doClear($namespaceToClear) || $cleared;
         } catch (\Exception $e) {
-            CacheItem::log($this->logger, 'Failed to clear the cache', ['exception' => $e]);
+            CacheItem::log($this->logger, 'Failed to clear the cache: '.$e->getMessage(), ['exception' => $e]);
 
             return false;
         }
@@ -128,6 +148,8 @@ trait AbstractTrait
 
     /**
      * {@inheritdoc}
+     *
+     * @return bool
      */
     public function deleteItem($key)
     {
@@ -136,6 +158,8 @@ trait AbstractTrait
 
     /**
      * {@inheritdoc}
+     *
+     * @return bool
      */
     public function deleteItems(array $keys)
     {
@@ -164,7 +188,8 @@ trait AbstractTrait
                 }
             } catch (\Exception $e) {
             }
-            CacheItem::log($this->logger, 'Failed to delete key "{key}"', ['key' => $key, 'exception' => $e]);
+            $message = 'Failed to delete key "{key}"'.($e instanceof \Exception ? ': '.$e->getMessage() : '.');
+            CacheItem::log($this->logger, $message, ['key' => $key, 'exception' => $e]);
             $ok = false;
         }
 
@@ -188,6 +213,7 @@ trait AbstractTrait
         $wasEnabled = $this->versioningIsEnabled;
         $this->versioningIsEnabled = (bool) $enable;
         $this->namespaceVersion = '';
+        $this->ids = [];
 
         return $wasEnabled;
     }
@@ -201,6 +227,7 @@ trait AbstractTrait
             $this->commit();
         }
         $this->namespaceVersion = '';
+        $this->ids = [];
     }
 
     /**
@@ -211,9 +238,13 @@ trait AbstractTrait
      * @return mixed
      *
      * @throws \Exception
+     *
+     * @deprecated since Symfony 4.2, use DefaultMarshaller instead.
      */
     protected static function unserialize($value)
     {
+        @trigger_error(sprintf('The "%s::unserialize()" method is deprecated since Symfony 4.2, use DefaultMarshaller instead.', __CLASS__), \E_USER_DEPRECATED);
+
         if ('b:0;' === $value) {
             return false;
         }
@@ -230,29 +261,45 @@ trait AbstractTrait
         }
     }
 
-    private function getId($key)
+    private function getId($key): string
     {
-        CacheItem::validateKey($key);
-
         if ($this->versioningIsEnabled && '' === $this->namespaceVersion) {
+            $this->ids = [];
             $this->namespaceVersion = '1'.static::NS_SEPARATOR;
             try {
                 foreach ($this->doFetch([static::NS_SEPARATOR.$this->namespace]) as $v) {
                     $this->namespaceVersion = $v;
                 }
+                $e = true;
                 if ('1'.static::NS_SEPARATOR === $this->namespaceVersion) {
-                    $this->namespaceVersion = substr_replace(base64_encode(pack('V', time())), static::NS_SEPARATOR, 5);
-                    $this->doSave([static::NS_SEPARATOR.$this->namespace => $this->namespaceVersion], 0);
+                    $this->namespaceVersion = self::formatNamespaceVersion(time());
+                    $e = $this->doSave([static::NS_SEPARATOR.$this->namespace => $this->namespaceVersion], 0);
                 }
             } catch (\Exception $e) {
             }
+            if (true !== $e && [] !== $e) {
+                $message = 'Failed to save the new namespace'.($e instanceof \Exception ? ': '.$e->getMessage() : '.');
+                CacheItem::log($this->logger, $message, ['exception' => $e instanceof \Exception ? $e : null]);
+            }
+        }
+
+        if (\is_string($key) && isset($this->ids[$key])) {
+            return $this->namespace.$this->namespaceVersion.$this->ids[$key];
+        }
+        CacheItem::validateKey($key);
+        $this->ids[$key] = $key;
+
+        if (\count($this->ids) > 1000) {
+            $this->ids = \array_slice($this->ids, 500, null, true); // stop memory leak if there are many keys
         }
 
         if (null === $this->maxIdLength) {
             return $this->namespace.$this->namespaceVersion.$key;
         }
         if (\strlen($id = $this->namespace.$this->namespaceVersion.$key) > $this->maxIdLength) {
-            $id = $this->namespace.$this->namespaceVersion.substr_replace(base64_encode(hash('sha256', $key, true)), static::NS_SEPARATOR, -(\strlen($this->namespaceVersion) + 22));
+            // Use MD5 to favor speed over security, which is not an issue here
+            $this->ids[$key] = $id = substr_replace(base64_encode(hash('md5', $key, true)), static::NS_SEPARATOR, -(\strlen($this->namespaceVersion) + 2));
+            $id = $this->namespace.$this->namespaceVersion.$id;
         }
 
         return $id;
@@ -265,4 +312,9 @@ trait AbstractTrait
     {
         throw new \DomainException('Class not found: '.$class);
     }
+
+    private static function formatNamespaceVersion(int $value): string
+    {
+        return strtr(substr_replace(base64_encode(pack('V', $value)), static::NS_SEPARATOR, 5), '/', '_');
+    }
 }
index 2f47f8e6d6f730b4f7f36df8644de297f62d5c9d..46bd20fe2f81491ba8bd0e6c21cc36edc7f3e11c 100644 (file)
@@ -23,10 +23,10 @@ trait ApcuTrait
 {
     public static function isSupported()
     {
-        return \function_exists('apcu_fetch') && filter_var(ini_get('apc.enabled'), \FILTER_VALIDATE_BOOLEAN);
+        return \function_exists('apcu_fetch') && filter_var(\ini_get('apc.enabled'), \FILTER_VALIDATE_BOOLEAN);
     }
 
-    private function init($namespace, $defaultLifetime, $version)
+    private function init(string $namespace, int $defaultLifetime, ?string $version)
     {
         if (!static::isSupported()) {
             throw new CacheException('APCu is not enabled.');
@@ -51,14 +51,27 @@ trait ApcuTrait
      */
     protected function doFetch(array $ids)
     {
+        $unserializeCallbackHandler = ini_set('unserialize_callback_func', __CLASS__.'::handleUnserializeCallback');
         try {
-            foreach (apcu_fetch($ids, $ok) ?: [] as $k => $v) {
+            $values = [];
+            $ids = array_flip($ids);
+            foreach (apcu_fetch(array_keys($ids), $ok) ?: [] as $k => $v) {
+                if (!isset($ids[$k])) {
+                    // work around https://github.com/krakjoe/apcu/issues/247
+                    $k = key($ids);
+                }
+                unset($ids[$k]);
+
                 if (null !== $v || $ok) {
-                    yield $k => $v;
+                    $values[$k] = $v;
                 }
             }
+
+            return $values;
         } catch (\Error $e) {
             throw new \ErrorException($e->getMessage(), $e->getCode(), \E_ERROR, $e->getFile(), $e->getLine());
+        } finally {
+            ini_set('unserialize_callback_func', $unserializeCallbackHandler);
         }
     }
 
@@ -75,8 +88,8 @@ trait ApcuTrait
      */
     protected function doClear($namespace)
     {
-        return isset($namespace[0]) && class_exists('APCuIterator', false) && ('cli' !== \PHP_SAPI || filter_var(ini_get('apc.enable_cli'), \FILTER_VALIDATE_BOOLEAN))
-            ? apcu_delete(new \APCuIterator(sprintf('/^%s/', preg_quote($namespace, '/')), \APC_ITER_KEY))
+        return isset($namespace[0]) && class_exists(\APCUIterator::class, false) && ('cli' !== \PHP_SAPI || filter_var(\ini_get('apc.enable_cli'), \FILTER_VALIDATE_BOOLEAN))
+            ? apcu_delete(new \APCUIterator(sprintf('/^%s/', preg_quote($namespace, '/')), \APC_ITER_KEY))
             : apcu_clear_cache();
     }
 
@@ -95,7 +108,7 @@ trait ApcuTrait
     /**
      * {@inheritdoc}
      */
-    protected function doSave(array $values, $lifetime)
+    protected function doSave(array $values, int $lifetime)
     {
         try {
             if (false === $failures = apcu_store($values, null, $lifetime)) {
@@ -103,15 +116,13 @@ trait ApcuTrait
             }
 
             return array_keys($failures);
-        } catch (\Error $e) {
-        } catch (\Exception $e) {
-        }
+        } catch (\Throwable $e) {
+            if (1 === \count($values)) {
+                // Workaround https://github.com/krakjoe/apcu/issues/170
+                apcu_delete(array_key_first($values));
+            }
 
-        if (1 === \count($values)) {
-            // Workaround https://github.com/krakjoe/apcu/issues/170
-            apcu_delete(key($values));
+            throw $e;
         }
-
-        throw $e;
     }
 }
index 0a60968e9b39787a73a2ebb35b534ca41fe1c283..e41daebc6af0c950eb031e40bc6415472f9f0d81 100644 (file)
@@ -34,36 +34,72 @@ trait ArrayTrait
      */
     public function getValues()
     {
-        return $this->values;
+        if (!$this->storeSerialized) {
+            return $this->values;
+        }
+
+        $values = $this->values;
+        foreach ($values as $k => $v) {
+            if (null === $v || 'N;' === $v) {
+                continue;
+            }
+            if (!\is_string($v) || !isset($v[2]) || ':' !== $v[1]) {
+                $values[$k] = serialize($v);
+            }
+        }
+
+        return $values;
     }
 
     /**
      * {@inheritdoc}
+     *
+     * @return bool
      */
     public function hasItem($key)
     {
+        if (\is_string($key) && isset($this->expiries[$key]) && $this->expiries[$key] > microtime(true)) {
+            return true;
+        }
         CacheItem::validateKey($key);
 
-        return isset($this->expiries[$key]) && ($this->expiries[$key] > time() || !$this->deleteItem($key));
+        return isset($this->expiries[$key]) && !$this->deleteItem($key);
     }
 
     /**
      * {@inheritdoc}
+     *
+     * @param string $prefix
+     *
+     * @return bool
      */
-    public function clear()
+    public function clear(/* string $prefix = '' */)
     {
-        $this->values = $this->expiries = [];
+        $prefix = 0 < \func_num_args() ? (string) func_get_arg(0) : '';
+
+        if ('' !== $prefix) {
+            foreach ($this->values as $key => $value) {
+                if (str_starts_with($key, $prefix)) {
+                    unset($this->values[$key], $this->expiries[$key]);
+                }
+            }
+        } else {
+            $this->values = $this->expiries = [];
+        }
 
         return true;
     }
 
     /**
      * {@inheritdoc}
+     *
+     * @return bool
      */
     public function deleteItem($key)
     {
-        CacheItem::validateKey($key);
-
+        if (!\is_string($key) || !isset($this->expiries[$key])) {
+            CacheItem::validateKey($key);
+        }
         unset($this->values[$key], $this->expiries[$key]);
 
         return true;
@@ -77,24 +113,13 @@ trait ArrayTrait
         $this->clear();
     }
 
-    private function generateItems(array $keys, $now, $f)
+    private function generateItems(array $keys, float $now, callable $f): iterable
     {
         foreach ($keys as $i => $key) {
-            try {
-                if (!$isHit = isset($this->expiries[$key]) && ($this->expiries[$key] > $now || !$this->deleteItem($key))) {
-                    $this->values[$key] = $value = null;
-                } elseif (!$this->storeSerialized) {
-                    $value = $this->values[$key];
-                } elseif ('b:0;' === $value = $this->values[$key]) {
-                    $value = false;
-                } elseif (false === $value = unserialize($value)) {
-                    $this->values[$key] = $value = null;
-                    $isHit = false;
-                }
-            } catch (\Exception $e) {
-                CacheItem::log($this->logger, 'Failed to unserialize key "{key}"', ['key' => $key, 'exception' => $e]);
+            if (!$isHit = isset($this->expiries[$key]) && ($this->expiries[$key] > $now || !$this->deleteItem($key))) {
                 $this->values[$key] = $value = null;
-                $isHit = false;
+            } else {
+                $value = $this->storeSerialized ? $this->unfreeze($key, $isHit) : $this->values[$key];
             }
             unset($keys[$i]);
 
@@ -105,4 +130,55 @@ trait ArrayTrait
             yield $key => $f($key, null, false);
         }
     }
+
+    private function freeze($value, $key)
+    {
+        if (null === $value) {
+            return 'N;';
+        }
+        if (\is_string($value)) {
+            // Serialize strings if they could be confused with serialized objects or arrays
+            if ('N;' === $value || (isset($value[2]) && ':' === $value[1])) {
+                return serialize($value);
+            }
+        } elseif (!\is_scalar($value)) {
+            try {
+                $serialized = serialize($value);
+            } catch (\Exception $e) {
+                unset($this->values[$key]);
+                $type = \is_object($value) ? \get_class($value) : \gettype($value);
+                $message = sprintf('Failed to save key "{key}" of type %s: ', $type).$e->getMessage();
+                CacheItem::log($this->logger, $message, ['key' => $key, 'exception' => $e]);
+
+                return null;
+            }
+            // Keep value serialized if it contains any objects or any internal references
+            if ('C' === $serialized[0] || 'O' === $serialized[0] || preg_match('/;[OCRr]:[1-9]/', $serialized)) {
+                return $serialized;
+            }
+        }
+
+        return $value;
+    }
+
+    private function unfreeze(string $key, bool &$isHit)
+    {
+        if ('N;' === $value = $this->values[$key]) {
+            return null;
+        }
+        if (\is_string($value) && isset($value[2]) && ':' === $value[1]) {
+            try {
+                $value = unserialize($value);
+            } catch (\Exception $e) {
+                CacheItem::log($this->logger, 'Failed to unserialize key "{key}": '.$e->getMessage(), ['key' => $key, 'exception' => $e]);
+                $value = false;
+            }
+            if (false === $value) {
+                $this->values[$key] = $value = null;
+                $isHit = false;
+            }
+        }
+
+        return $value;
+    }
 }
diff --git a/advancedcontentfilter/vendor/symfony/cache/Traits/ContractsTrait.php b/advancedcontentfilter/vendor/symfony/cache/Traits/ContractsTrait.php
new file mode 100644 (file)
index 0000000..49a96ee
--- /dev/null
@@ -0,0 +1,109 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien@symfony.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Cache\Traits;
+
+use Psr\Log\LoggerInterface;
+use Symfony\Component\Cache\Adapter\AdapterInterface;
+use Symfony\Component\Cache\CacheItem;
+use Symfony\Component\Cache\Exception\InvalidArgumentException;
+use Symfony\Component\Cache\LockRegistry;
+use Symfony\Contracts\Cache\CacheInterface;
+use Symfony\Contracts\Cache\CacheTrait;
+use Symfony\Contracts\Cache\ItemInterface;
+
+/**
+ * @author Nicolas Grekas <p@tchwork.com>
+ *
+ * @internal
+ */
+trait ContractsTrait
+{
+    use CacheTrait {
+        doGet as private contractsGet;
+    }
+
+    private $callbackWrapper;
+    private $computing = [];
+
+    /**
+     * Wraps the callback passed to ->get() in a callable.
+     *
+     * @return callable the previous callback wrapper
+     */
+    public function setCallbackWrapper(?callable $callbackWrapper): callable
+    {
+        if (!isset($this->callbackWrapper)) {
+            $this->callbackWrapper = \Closure::fromCallable([LockRegistry::class, 'compute']);
+
+            if (\in_array(\PHP_SAPI, ['cli', 'phpdbg'], true)) {
+                $this->setCallbackWrapper(null);
+            }
+        }
+
+        $previousWrapper = $this->callbackWrapper;
+        $this->callbackWrapper = $callbackWrapper ?? static function (callable $callback, ItemInterface $item, bool &$save, CacheInterface $pool, \Closure $setMetadata, ?LoggerInterface $logger) {
+            return $callback($item, $save);
+        };
+
+        return $previousWrapper;
+    }
+
+    private function doGet(AdapterInterface $pool, string $key, callable $callback, ?float $beta, array &$metadata = null)
+    {
+        if (0 > $beta = $beta ?? 1.0) {
+            throw new InvalidArgumentException(sprintf('Argument "$beta" provided to "%s::get()" must be a positive number, %f given.', static::class, $beta));
+        }
+
+        static $setMetadata;
+
+        $setMetadata = $setMetadata ?? \Closure::bind(
+            static function (CacheItem $item, float $startTime, ?array &$metadata) {
+                if ($item->expiry > $endTime = microtime(true)) {
+                    $item->newMetadata[CacheItem::METADATA_EXPIRY] = $metadata[CacheItem::METADATA_EXPIRY] = $item->expiry;
+                    $item->newMetadata[CacheItem::METADATA_CTIME] = $metadata[CacheItem::METADATA_CTIME] = (int) ceil(1000 * ($endTime - $startTime));
+                } else {
+                    unset($metadata[CacheItem::METADATA_EXPIRY], $metadata[CacheItem::METADATA_CTIME]);
+                }
+            },
+            null,
+            CacheItem::class
+        );
+
+        return $this->contractsGet($pool, $key, function (CacheItem $item, bool &$save) use ($pool, $callback, $setMetadata, &$metadata, $key) {
+            // don't wrap nor save recursive calls
+            if (isset($this->computing[$key])) {
+                $value = $callback($item, $save);
+                $save = false;
+
+                return $value;
+            }
+
+            $this->computing[$key] = $key;
+            $startTime = microtime(true);
+
+            if (!isset($this->callbackWrapper)) {
+                $this->setCallbackWrapper($this->setCallbackWrapper(null));
+            }
+
+            try {
+                $value = ($this->callbackWrapper)($callback, $item, $save, $pool, function (CacheItem $item) use ($setMetadata, $startTime, &$metadata) {
+                    $setMetadata($item, $startTime, $metadata);
+                }, $this->logger ?? null);
+                $setMetadata($item, $startTime, $metadata);
+
+                return $value;
+            } finally {
+                unset($this->computing[$key]);
+            }
+        }, $beta, $metadata, $this->logger ?? null);
+    }
+}
index 48623e67c0e015aac135af504c0bea4f01aa4805..ae14db01ee521a0c0a4023a26ba13d0e468ba462 100644 (file)
@@ -91,7 +91,7 @@ trait DoctrineTrait
     /**
      * {@inheritdoc}
      */
-    protected function doSave(array $values, $lifetime)
+    protected function doSave(array $values, int $lifetime)
     {
         return $this->provider->saveMultiple($values, $lifetime);
     }
index 8071a382bbe1e71a78bfcd22f335cde55563a7ac..4e06495d5b42ab9fa2518671e57011ca05d2a323 100644 (file)
@@ -23,10 +23,10 @@ trait FilesystemCommonTrait
     private $directory;
     private $tmp;
 
-    private function init($namespace, $directory)
+    private function init(string $namespace, ?string $directory)
     {
         if (!isset($directory[0])) {
-            $directory = sys_get_temp_dir().'/symfony-cache';
+            $directory = sys_get_temp_dir().\DIRECTORY_SEPARATOR.'symfony-cache';
         } else {
             $directory = realpath($directory) ?: $directory;
         }
@@ -35,6 +35,8 @@ trait FilesystemCommonTrait
                 throw new InvalidArgumentException(sprintf('Namespace contains "%s" but only characters in [-+_.A-Za-z0-9] are allowed.', $match[0]));
             }
             $directory .= \DIRECTORY_SEPARATOR.$namespace;
+        } else {
+            $directory .= \DIRECTORY_SEPARATOR.'@';
         }
         if (!file_exists($directory)) {
             @mkdir($directory, 0777, true);
@@ -55,8 +57,12 @@ trait FilesystemCommonTrait
     {
         $ok = true;
 
-        foreach (new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($this->directory, \FilesystemIterator::SKIP_DOTS)) as $file) {
-            $ok = ($file->isDir() || @unlink($file) || !file_exists($file)) && $ok;
+        foreach ($this->scanHashDir($this->directory) as $file) {
+            if ('' !== $namespace && !str_starts_with($this->getFileKey($file), $namespace)) {
+                continue;
+            }
+
+            $ok = ($this->doUnlink($file) || !file_exists($file)) && $ok;
         }
 
         return $ok;
@@ -71,23 +77,39 @@ trait FilesystemCommonTrait
 
         foreach ($ids as $id) {
             $file = $this->getFile($id);
-            $ok = (!file_exists($file) || @unlink($file) || !file_exists($file)) && $ok;
+            $ok = (!file_exists($file) || $this->doUnlink($file) || !file_exists($file)) && $ok;
         }
 
         return $ok;
     }
 
-    private function write($file, $data, $expiresAt = null)
+    protected function doUnlink($file)
+    {
+        return @unlink($file);
+    }
+
+    private function write(string $file, string $data, int $expiresAt = null)
     {
         set_error_handler(__CLASS__.'::throwError');
         try {
             if (null === $this->tmp) {
-                $this->tmp = $this->directory.uniqid('', true);
+                $this->tmp = $this->directory.bin2hex(random_bytes(6));
             }
-            file_put_contents($this->tmp, $data);
+            try {
+                $h = fopen($this->tmp, 'x');
+            } catch (\ErrorException $e) {
+                if (!str_contains($e->getMessage(), 'File exists')) {
+                    throw $e;
+                }
+
+                $this->tmp = $this->directory.bin2hex(random_bytes(6));
+                $h = fopen($this->tmp, 'x');
+            }
+            fwrite($h, $data);
+            fclose($h);
 
             if (null !== $expiresAt) {
-                touch($this->tmp, $expiresAt);
+                touch($this->tmp, $expiresAt ?: time() + 31556952); // 1 year in seconds
             }
 
             return rename($this->tmp, $file);
@@ -96,10 +118,11 @@ trait FilesystemCommonTrait
         }
     }
 
-    private function getFile($id, $mkdir = false)
+    private function getFile(string $id, bool $mkdir = false, string $directory = null)
     {
-        $hash = str_replace('/', '-', base64_encode(hash('sha256', static::class.$id, true)));
-        $dir = $this->directory.strtoupper($hash[0].\DIRECTORY_SEPARATOR.$hash[1].\DIRECTORY_SEPARATOR);
+        // Use MD5 to favor speed over security, which is not an issue here
+        $hash = str_replace('/', '-', base64_encode(hash('md5', static::class.$id, true)));
+        $dir = ($directory ?? $this->directory).strtoupper($hash[0].\DIRECTORY_SEPARATOR.$hash[1].\DIRECTORY_SEPARATOR);
 
         if ($mkdir && !file_exists($dir)) {
             @mkdir($dir, 0777, true);
@@ -108,6 +131,38 @@ trait FilesystemCommonTrait
         return $dir.substr($hash, 2, 20);
     }
 
+    private function getFileKey(string $file): string
+    {
+        return '';
+    }
+
+    private function scanHashDir(string $directory): \Generator
+    {
+        if (!file_exists($directory)) {
+            return;
+        }
+
+        $chars = '+-ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
+
+        for ($i = 0; $i < 38; ++$i) {
+            if (!file_exists($directory.$chars[$i])) {
+                continue;
+            }
+
+            for ($j = 0; $j < 38; ++$j) {
+                if (!file_exists($dir = $directory.$chars[$i].\DIRECTORY_SEPARATOR.$chars[$j])) {
+                    continue;
+                }
+
+                foreach (@scandir($dir, \SCANDIR_SORT_NONE) ?: [] as $file) {
+                    if ('.' !== $file && '..' !== $file) {
+                        yield $dir.\DIRECTORY_SEPARATOR.$file;
+                    }
+                }
+            }
+        }
+    }
+
     /**
      * @internal
      */
@@ -116,6 +171,9 @@ trait FilesystemCommonTrait
         throw new \ErrorException($message, 0, $type, $file, $line);
     }
 
+    /**
+     * @return array
+     */
     public function __sleep()
     {
         throw new \BadMethodCallException('Cannot serialize '.__CLASS__);
index 9d7f55784a65f4faf7ac7f58d28e64bd1d86da9f..72118eaae5d257593cd52009e96d7e6a15e7c477 100644 (file)
@@ -23,6 +23,8 @@ trait FilesystemTrait
 {
     use FilesystemCommonTrait;
 
+    private $marshaller;
+
     /**
      * @return bool
      */
@@ -31,8 +33,8 @@ trait FilesystemTrait
         $time = time();
         $pruned = true;
 
-        foreach (new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($this->directory, \FilesystemIterator::SKIP_DOTS), \RecursiveIteratorIterator::LEAVES_ONLY) as $file) {
-            if (!$h = @fopen($file, 'rb')) {
+        foreach ($this->scanHashDir($this->directory) as $file) {
+            if (!$h = @fopen($file, 'r')) {
                 continue;
             }
 
@@ -57,7 +59,7 @@ trait FilesystemTrait
 
         foreach ($ids as $id) {
             $file = $this->getFile($id);
-            if (!file_exists($file) || !$h = @fopen($file, 'rb')) {
+            if (!file_exists($file) || !$h = @fopen($file, 'r')) {
                 continue;
             }
             if (($expiresAt = (int) fgets($h)) && $now >= $expiresAt) {
@@ -68,7 +70,7 @@ trait FilesystemTrait
                 $value = stream_get_contents($h);
                 fclose($h);
                 if ($i === $id) {
-                    $values[$id] = parent::unserialize($value);
+                    $values[$id] = $this->marshaller->unmarshall($value);
                 }
             }
         }
@@ -89,19 +91,34 @@ trait FilesystemTrait
     /**
      * {@inheritdoc}
      */
-    protected function doSave(array $values, $lifetime)
+    protected function doSave(array $values, int $lifetime)
     {
-        $ok = true;
         $expiresAt = $lifetime ? (time() + $lifetime) : 0;
+        $values = $this->marshaller->marshall($values, $failed);
 
         foreach ($values as $id => $value) {
-            $ok = $this->write($this->getFile($id, true), $expiresAt."\n".rawurlencode($id)."\n".serialize($value), $expiresAt) && $ok;
+            if (!$this->write($this->getFile($id, true), $expiresAt."\n".rawurlencode($id)."\n".$value, $expiresAt)) {
+                $failed[] = $id;
+            }
         }
 
-        if (!$ok && !is_writable($this->directory)) {
+        if ($failed && !is_writable($this->directory)) {
             throw new CacheException(sprintf('Cache directory is not writable (%s).', $this->directory));
         }
 
-        return $ok;
+        return $failed;
+    }
+
+    private function getFileKey(string $file): string
+    {
+        if (!$h = @fopen($file, 'r')) {
+            return '';
+        }
+
+        fgets($h); // expiry
+        $encodedKey = fgets($h);
+        fclose($h);
+
+        return rawurldecode(rtrim($encodedKey));
     }
 }
index 34d0208efb2820b1e868a57968fecb72020f8a3f..ebcb160c6188805aab17246d07a04cf0d8e0a26e 100644 (file)
@@ -13,6 +13,8 @@ namespace Symfony\Component\Cache\Traits;
 
 use Symfony\Component\Cache\Exception\CacheException;
 use Symfony\Component\Cache\Exception\InvalidArgumentException;
+use Symfony\Component\Cache\Marshaller\DefaultMarshaller;
+use Symfony\Component\Cache\Marshaller\MarshallerInterface;
 
 /**
  * @author Rob Frawley 2nd <rmf@src.run>
@@ -29,18 +31,27 @@ trait MemcachedTrait
         \Memcached::OPT_SERIALIZER => \Memcached::SERIALIZER_PHP,
     ];
 
+    /**
+     * We are replacing characters that are illegal in Memcached keys with reserved characters from
+     * {@see \Symfony\Contracts\Cache\ItemInterface::RESERVED_CHARACTERS} that are legal in Memcached.
+     * Note: don’t use {@see \Symfony\Component\Cache\Adapter\AbstractAdapter::NS_SEPARATOR}.
+     */
+    private static $RESERVED_MEMCACHED = " \n\r\t\v\f\0";
+    private static $RESERVED_PSR6 = '@()\{}/';
+
+    private $marshaller;
     private $client;
     private $lazyClient;
 
     public static function isSupported()
     {
-        return \extension_loaded('memcached') && version_compare(phpversion('memcached'), '2.2.0', '>=');
+        return \extension_loaded('memcached') && version_compare(phpversion('memcached'), \PHP_VERSION_ID >= 80100 ? '3.1.6' : '2.2.0', '>=');
     }
 
-    private function init(\Memcached $client, $namespace, $defaultLifetime)
+    private function init(\Memcached $client, string $namespace, int $defaultLifetime, ?MarshallerInterface $marshaller)
     {
         if (!static::isSupported()) {
-            throw new CacheException('Memcached >= 2.2.0 is required.');
+            throw new CacheException('Memcached '.(\PHP_VERSION_ID >= 80100 ? '> 3.1.5' : '>= 2.2.0').' is required.');
         }
         if ('Memcached' === \get_class($client)) {
             $opt = $client->getOption(\Memcached::OPT_SERIALIZER);
@@ -55,6 +66,7 @@ trait MemcachedTrait
 
         parent::__construct($namespace, $defaultLifetime);
         $this->enableVersioning();
+        $this->marshaller = $marshaller ?? new DefaultMarshaller();
     }
 
     /**
@@ -67,7 +79,6 @@ trait MemcachedTrait
      * - [['localhost', 11211, 33]]
      *
      * @param array[]|string|string[] $servers An array of servers, a DSN, or an array of DSNs
-     * @param array                   $options An array of options
      *
      * @return \Memcached
      *
@@ -81,7 +92,7 @@ trait MemcachedTrait
             throw new InvalidArgumentException(sprintf('MemcachedAdapter::createClient() expects array or string as first argument, "%s" given.', \gettype($servers)));
         }
         if (!static::isSupported()) {
-            throw new CacheException('Memcached >= 2.2.0 is required.');
+            throw new CacheException('Memcached '.(\PHP_VERSION_ID >= 80100 ? '> 3.1.5' : '>= 2.2.0').' is required.');
         }
         set_error_handler(function ($type, $msg, $file, $line) { throw new \ErrorException($msg, 0, $type, $file, $line); });
         try {
@@ -95,19 +106,43 @@ trait MemcachedTrait
                 if (\is_array($dsn)) {
                     continue;
                 }
-                if (0 !== strpos($dsn, 'memcached://')) {
-                    throw new InvalidArgumentException(sprintf('Invalid Memcached DSN: "%s" does not start with "memcached://".', $dsn));
+                if (!str_starts_with($dsn, 'memcached:')) {
+                    throw new InvalidArgumentException(sprintf('Invalid Memcached DSN: "%s" does not start with "memcached:".', $dsn));
                 }
-                $params = preg_replace_callback('#^memcached://(?:([^@]*+)@)?#', function ($m) use (&$username, &$password) {
-                    if (!empty($m[1])) {
-                        list($username, $password) = explode(':', $m[1], 2) + [1 => null];
+                $params = preg_replace_callback('#^memcached:(//)?(?:([^@]*+)@)?#', function ($m) use (&$username, &$password) {
+                    if (!empty($m[2])) {
+                        [$username, $password] = explode(':', $m[2], 2) + [1 => null];
                     }
 
-                    return 'file://';
+                    return 'file:'.($m[1] ?? '');
                 }, $dsn);
                 if (false === $params = parse_url($params)) {
                     throw new InvalidArgumentException(sprintf('Invalid Memcached DSN: "%s".', $dsn));
                 }
+                $query = $hosts = [];
+                if (isset($params['query'])) {
+                    parse_str($params['query'], $query);
+
+                    if (isset($query['host'])) {
+                        if (!\is_array($hosts = $query['host'])) {
+                            throw new InvalidArgumentException(sprintf('Invalid Memcached DSN: "%s".', $dsn));
+                        }
+                        foreach ($hosts as $host => $weight) {
+                            if (false === $port = strrpos($host, ':')) {
+                                $hosts[$host] = [$host, 11211, (int) $weight];
+                            } else {
+                                $hosts[$host] = [substr($host, 0, $port), (int) substr($host, 1 + $port), (int) $weight];
+                            }
+                        }
+                        $hosts = array_values($hosts);
+                        unset($query['host']);
+                    }
+                    if ($hosts && !isset($params['host']) && !isset($params['path'])) {
+                        unset($servers[$i]);
+                        $servers = array_merge($servers, $hosts);
+                        continue;
+                    }
+                }
                 if (!isset($params['host']) && !isset($params['path'])) {
                     throw new InvalidArgumentException(sprintf('Invalid Memcached DSN: "%s".', $dsn));
                 }
@@ -116,17 +151,20 @@ trait MemcachedTrait
                     $params['path'] = substr($params['path'], 0, -\strlen($m[0]));
                 }
                 $params += [
-                    'host' => isset($params['host']) ? $params['host'] : $params['path'],
+                    'host' => $params['host'] ?? $params['path'],
                     'port' => isset($params['host']) ? 11211 : null,
                     'weight' => 0,
                 ];
-                if (isset($params['query'])) {
-                    parse_str($params['query'], $query);
+                if ($query) {
                     $params += $query;
                     $options = $query + $options;
                 }
 
                 $servers[$i] = [$params['host'], $params['port'], $params['weight']];
+
+                if ($hosts) {
+                    $servers = array_merge($servers, $hosts);
+                }
             }
 
             // set client's options
@@ -193,18 +231,22 @@ trait MemcachedTrait
     /**
      * {@inheritdoc}
      */
-    protected function doSave(array $values, $lifetime)
+    protected function doSave(array $values, int $lifetime)
     {
+        if (!$values = $this->marshaller->marshall($values, $failed)) {
+            return $failed;
+        }
+
         if ($lifetime && $lifetime > 30 * 86400) {
             $lifetime += time();
         }
 
         $encodedValues = [];
         foreach ($values as $key => $value) {
-            $encodedValues[rawurlencode($key)] = $value;
+            $encodedValues[self::encodeKey($key)] = $value;
         }
 
-        return $this->checkResultCode($this->getClient()->setMulti($encodedValues, $lifetime));
+        return $this->checkResultCode($this->getClient()->setMulti($encodedValues, $lifetime)) ? $failed : false;
     }
 
     /**
@@ -212,22 +254,19 @@ trait MemcachedTrait
      */
     protected function doFetch(array $ids)
     {
-        $unserializeCallbackHandler = ini_set('unserialize_callback_func', __CLASS__.'::handleUnserializeCallback');
         try {
-            $encodedIds = array_map('rawurlencode', $ids);
+            $encodedIds = array_map([__CLASS__, 'encodeKey'], $ids);
 
             $encodedResult = $this->checkResultCode($this->getClient()->getMulti($encodedIds));
 
             $result = [];
             foreach ($encodedResult as $key => $value) {
-                $result[rawurldecode($key)] = $value;
+                $result[self::decodeKey($key)] = $this->marshaller->unmarshall($value);
             }
 
             return $result;
         } catch (\Error $e) {
             throw new \ErrorException($e->getMessage(), $e->getCode(), \E_ERROR, $e->getFile(), $e->getLine());
-        } finally {
-            ini_set('unserialize_callback_func', $unserializeCallbackHandler);
         }
     }
 
@@ -236,7 +275,7 @@ trait MemcachedTrait
      */
     protected function doHave($id)
     {
-        return false !== $this->getClient()->get(rawurlencode($id)) || $this->checkResultCode(\Memcached::RES_SUCCESS === $this->client->getResultCode());
+        return false !== $this->getClient()->get(self::encodeKey($id)) || $this->checkResultCode(\Memcached::RES_SUCCESS === $this->client->getResultCode());
     }
 
     /**
@@ -245,7 +284,7 @@ trait MemcachedTrait
     protected function doDelete(array $ids)
     {
         $ok = true;
-        $encodedIds = array_map('rawurlencode', $ids);
+        $encodedIds = array_map([__CLASS__, 'encodeKey'], $ids);
         foreach ($this->checkResultCode($this->getClient()->deleteMulti($encodedIds)) as $result) {
             if (\Memcached::RES_SUCCESS !== $result && \Memcached::RES_NOTFOUND !== $result) {
                 $ok = false;
@@ -275,10 +314,7 @@ trait MemcachedTrait
         throw new CacheException('MemcachedAdapter client error: '.strtolower($this->client->getResultMessage()));
     }
 
-    /**
-     * @return \Memcached
-     */
-    private function getClient()
+    private function getClient(): \Memcached
     {
         if ($this->client) {
             return $this->client;
@@ -294,4 +330,14 @@ trait MemcachedTrait
 
         return $this->client = $this->lazyClient;
     }
+
+    private static function encodeKey(string $key): string
+    {
+        return strtr($key, self::$RESERVED_MEMCACHED, self::$RESERVED_PSR6);
+    }
+
+    private static function decodeKey(string $key): string
+    {
+        return strtr($key, self::$RESERVED_PSR6, self::$RESERVED_MEMCACHED);
+    }
 }
index 917e8dd13f02a46ca9ee6429c0496801b4438d6b..4d5e123005877a374be5ea78084a1cadc2d902af 100644 (file)
@@ -14,14 +14,22 @@ namespace Symfony\Component\Cache\Traits;
 use Doctrine\DBAL\Connection;
 use Doctrine\DBAL\DBALException;
 use Doctrine\DBAL\Driver\ServerInfoAwareConnection;
+use Doctrine\DBAL\DriverManager;
+use Doctrine\DBAL\Exception;
+use Doctrine\DBAL\Exception\TableNotFoundException;
+use Doctrine\DBAL\ParameterType;
 use Doctrine\DBAL\Schema\Schema;
+use Doctrine\DBAL\Statement;
 use Symfony\Component\Cache\Exception\InvalidArgumentException;
+use Symfony\Component\Cache\Marshaller\DefaultMarshaller;
+use Symfony\Component\Cache\Marshaller\MarshallerInterface;
 
 /**
  * @internal
  */
 trait PdoTrait
 {
+    private $marshaller;
     private $conn;
     private $dsn;
     private $driver;
@@ -36,7 +44,7 @@ trait PdoTrait
     private $connectionOptions = [];
     private $namespace;
 
-    private function init($connOrDsn, $namespace, $defaultLifetime, array $options)
+    private function init($connOrDsn, string $namespace, int $defaultLifetime, array $options, ?MarshallerInterface $marshaller)
     {
         if (isset($namespace[0]) && preg_match('#[^-+.A-Za-z0-9]#', $namespace, $match)) {
             throw new InvalidArgumentException(sprintf('Namespace contains "%s" but only characters in [-+.A-Za-z0-9] are allowed.', $match[0]));
@@ -56,15 +64,16 @@ trait PdoTrait
             throw new InvalidArgumentException(sprintf('"%s" requires PDO or Doctrine\DBAL\Connection instance or DSN string as first argument, "%s" given.', __CLASS__, \is_object($connOrDsn) ? \get_class($connOrDsn) : \gettype($connOrDsn)));
         }
 
-        $this->table = isset($options['db_table']) ? $options['db_table'] : $this->table;
-        $this->idCol = isset($options['db_id_col']) ? $options['db_id_col'] : $this->idCol;
-        $this->dataCol = isset($options['db_data_col']) ? $options['db_data_col'] : $this->dataCol;
-        $this->lifetimeCol = isset($options['db_lifetime_col']) ? $options['db_lifetime_col'] : $this->lifetimeCol;
-        $this->timeCol = isset($options['db_time_col']) ? $options['db_time_col'] : $this->timeCol;
-        $this->username = isset($options['db_username']) ? $options['db_username'] : $this->username;
-        $this->password = isset($options['db_password']) ? $options['db_password'] : $this->password;
-        $this->connectionOptions = isset($options['db_connection_options']) ? $options['db_connection_options'] : $this->connectionOptions;
+        $this->table = $options['db_table'] ?? $this->table;
+        $this->idCol = $options['db_id_col'] ?? $this->idCol;
+        $this->dataCol = $options['db_data_col'] ?? $this->dataCol;
+        $this->lifetimeCol = $options['db_lifetime_col'] ?? $this->lifetimeCol;
+        $this->timeCol = $options['db_time_col'] ?? $this->timeCol;
+        $this->username = $options['db_username'] ?? $this->username;
+        $this->password = $options['db_password'] ?? $this->password;
+        $this->connectionOptions = $options['db_connection_options'] ?? $this->connectionOptions;
         $this->namespace = $namespace;
+        $this->marshaller = $marshaller ?? new DefaultMarshaller();
 
         parent::__construct($namespace, $defaultLifetime);
     }
@@ -77,6 +86,7 @@ trait PdoTrait
      *
      * @throws \PDOException    When the table already exists
      * @throws DBALException    When the table already exists
+     * @throws Exception        When the table already exists
      * @throws \DomainException When an unsupported PDO driver is used
      */
     public function createTable()
@@ -140,7 +150,7 @@ trait PdoTrait
                 throw new \DomainException(sprintf('Creating the cache table is currently not implemented for PDO driver "%s".', $this->driver));
         }
 
-        if (method_exists($conn, 'executeStatement')) {
+        if ($conn instanceof Connection && method_exists($conn, 'executeStatement')) {
             $conn->executeStatement($sql);
         } else {
             $conn->exec($sql);
@@ -158,14 +168,35 @@ trait PdoTrait
             $deleteSql .= " AND $this->idCol LIKE :namespace";
         }
 
-        $delete = $this->getConnection()->prepare($deleteSql);
-        $delete->bindValue(':time', time(), \PDO::PARAM_INT);
+        $connection = $this->getConnection();
+        $useDbalConstants = $connection instanceof Connection;
+
+        try {
+            $delete = $connection->prepare($deleteSql);
+        } catch (TableNotFoundException $e) {
+            return true;
+        } catch (\PDOException $e) {
+            return true;
+        }
+        $delete->bindValue(':time', time(), $useDbalConstants ? ParameterType::INTEGER : \PDO::PARAM_INT);
 
         if ('' !== $this->namespace) {
-            $delete->bindValue(':namespace', sprintf('%s%%', $this->namespace), \PDO::PARAM_STR);
+            $delete->bindValue(':namespace', sprintf('%s%%', $this->namespace), $useDbalConstants ? ParameterType::STRING : \PDO::PARAM_STR);
         }
+        try {
+            // Doctrine DBAL ^2.13 || >= 3.1
+            if ($delete instanceof Statement && method_exists($delete, 'executeStatement')) {
+                $delete->executeStatement();
 
-        return $delete->execute();
+                return true;
+            }
+
+            return $delete->execute();
+        } catch (TableNotFoundException $e) {
+            return true;
+        } catch (\PDOException $e) {
+            return true;
+        }
     }
 
     /**
@@ -173,13 +204,16 @@ trait PdoTrait
      */
     protected function doFetch(array $ids)
     {
+        $connection = $this->getConnection();
+        $useDbalConstants = $connection instanceof Connection;
+
         $now = time();
         $expired = [];
 
         $sql = str_pad('', (\count($ids) << 1) - 1, '?,');
         $sql = "SELECT $this->idCol, CASE WHEN $this->lifetimeCol IS NULL OR $this->lifetimeCol + $this->timeCol > ? THEN $this->dataCol ELSE NULL END FROM $this->table WHERE $this->idCol IN ($sql)";
-        $stmt = $this->getConnection()->prepare($sql);
-        $stmt->bindValue($i = 1, $now, \PDO::PARAM_INT);
+        $stmt = $connection->prepare($sql);
+        $stmt->bindValue($i = 1, $now, $useDbalConstants ? ParameterType::INTEGER : \PDO::PARAM_INT);
         foreach ($ids as $id) {
             $stmt->bindValue(++$i, $id);
         }
@@ -196,15 +230,15 @@ trait PdoTrait
             if (null === $row[1]) {
                 $expired[] = $row[0];
             } else {
-                yield $row[0] => parent::unserialize(\is_resource($row[1]) ? stream_get_contents($row[1]) : $row[1]);
+                yield $row[0] => $this->marshaller->unmarshall(\is_resource($row[1]) ? stream_get_contents($row[1]) : $row[1]);
             }
         }
 
         if ($expired) {
             $sql = str_pad('', (\count($expired) << 1) - 1, '?,');
             $sql = "DELETE FROM $this->table WHERE $this->lifetimeCol + $this->timeCol <= ? AND $this->idCol IN ($sql)";
-            $stmt = $this->getConnection()->prepare($sql);
-            $stmt->bindValue($i = 1, $now, \PDO::PARAM_INT);
+            $stmt = $connection->prepare($sql);
+            $stmt->bindValue($i = 1, $now, $useDbalConstants ? ParameterType::INTEGER : \PDO::PARAM_INT);
             foreach ($expired as $id) {
                 $stmt->bindValue(++$i, $id);
             }
@@ -217,11 +251,14 @@ trait PdoTrait
      */
     protected function doHave($id)
     {
+        $connection = $this->getConnection();
+        $useDbalConstants = $connection instanceof Connection;
+
         $sql = "SELECT 1 FROM $this->table WHERE $this->idCol = :id AND ($this->lifetimeCol IS NULL OR $this->lifetimeCol + $this->timeCol > :time)";
-        $stmt = $this->getConnection()->prepare($sql);
+        $stmt = $connection->prepare($sql);
 
         $stmt->bindValue(':id', $id);
-        $stmt->bindValue(':time', time(), \PDO::PARAM_INT);
+        $stmt->bindValue(':time', time(), $useDbalConstants ? ParameterType::INTEGER : \PDO::PARAM_INT);
         $result = $stmt->execute();
 
         return (bool) (\is_object($result) ? $result->fetchOne() : $stmt->fetchColumn());
@@ -244,10 +281,14 @@ trait PdoTrait
             $sql = "DELETE FROM $this->table WHERE $this->idCol LIKE '$namespace%'";
         }
 
-        if (method_exists($conn, 'executeStatement')) {
-            $conn->executeStatement($sql);
-        } else {
-            $conn->exec($sql);
+        try {
+            if ($conn instanceof Connection && method_exists($conn, 'executeStatement')) {
+                $conn->executeStatement($sql);
+            } else {
+                $conn->exec($sql);
+            }
+        } catch (TableNotFoundException $e) {
+        } catch (\PDOException $e) {
         }
 
         return true;
@@ -260,8 +301,12 @@ trait PdoTrait
     {
         $sql = str_pad('', (\count($ids) << 1) - 1, '?,');
         $sql = "DELETE FROM $this->table WHERE $this->idCol IN ($sql)";
-        $stmt = $this->getConnection()->prepare($sql);
-        $stmt->execute(array_values($ids));
+        try {
+            $stmt = $this->getConnection()->prepare($sql);
+            $stmt->execute(array_values($ids));
+        } catch (TableNotFoundException $e) {
+        } catch (\PDOException $e) {
+        }
 
         return true;
     }
@@ -269,24 +314,15 @@ trait PdoTrait
     /**
      * {@inheritdoc}
      */
-    protected function doSave(array $values, $lifetime)
+    protected function doSave(array $values, int $lifetime)
     {
-        $serialized = [];
-        $failed = [];
-
-        foreach ($values as $id => $value) {
-            try {
-                $serialized[$id] = serialize($value);
-            } catch (\Exception $e) {
-                $failed[] = $id;
-            }
-        }
-
-        if (!$serialized) {
+        if (!$values = $this->marshaller->marshall($values, $failed)) {
             return $failed;
         }
 
         $conn = $this->getConnection();
+        $useDbalConstants = $conn instanceof Connection;
+
         $driver = $this->driver;
         $insertSql = "INSERT INTO $this->table ($this->idCol, $this->dataCol, $this->lifetimeCol, $this->timeCol) VALUES (:id, :data, :lifetime, :time)";
 
@@ -321,39 +357,62 @@ trait PdoTrait
 
         $now = time();
         $lifetime = $lifetime ?: null;
-        $stmt = $conn->prepare($sql);
+        try {
+            $stmt = $conn->prepare($sql);
+        } catch (TableNotFoundException $e) {
+            if (!$conn->isTransactionActive() || \in_array($this->driver, ['pgsql', 'sqlite', 'sqlsrv'], true)) {
+                $this->createTable();
+            }
+            $stmt = $conn->prepare($sql);
+        } catch (\PDOException $e) {
+            if (!$conn->inTransaction() || \in_array($this->driver, ['pgsql', 'sqlite', 'sqlsrv'], true)) {
+                $this->createTable();
+            }
+            $stmt = $conn->prepare($sql);
+        }
 
         if ('sqlsrv' === $driver || 'oci' === $driver) {
             $stmt->bindParam(1, $id);
             $stmt->bindParam(2, $id);
-            $stmt->bindParam(3, $data, \PDO::PARAM_LOB);
-            $stmt->bindValue(4, $lifetime, \PDO::PARAM_INT);
-            $stmt->bindValue(5, $now, \PDO::PARAM_INT);
-            $stmt->bindParam(6, $data, \PDO::PARAM_LOB);
-            $stmt->bindValue(7, $lifetime, \PDO::PARAM_INT);
-            $stmt->bindValue(8, $now, \PDO::PARAM_INT);
+            $stmt->bindParam(3, $data, $useDbalConstants ? ParameterType::LARGE_OBJECT : \PDO::PARAM_LOB);
+            $stmt->bindValue(4, $lifetime, $useDbalConstants ? ParameterType::INTEGER : \PDO::PARAM_INT);
+            $stmt->bindValue(5, $now, $useDbalConstants ? ParameterType::INTEGER : \PDO::PARAM_INT);
+            $stmt->bindParam(6, $data, $useDbalConstants ? ParameterType::LARGE_OBJECT : \PDO::PARAM_LOB);
+            $stmt->bindValue(7, $lifetime, $useDbalConstants ? ParameterType::INTEGER : \PDO::PARAM_INT);
+            $stmt->bindValue(8, $now, $useDbalConstants ? ParameterType::INTEGER : \PDO::PARAM_INT);
         } else {
             $stmt->bindParam(':id', $id);
-            $stmt->bindParam(':data', $data, \PDO::PARAM_LOB);
-            $stmt->bindValue(':lifetime', $lifetime, \PDO::PARAM_INT);
-            $stmt->bindValue(':time', $now, \PDO::PARAM_INT);
+            $stmt->bindParam(':data', $data, $useDbalConstants ? ParameterType::LARGE_OBJECT : \PDO::PARAM_LOB);
+            $stmt->bindValue(':lifetime', $lifetime, $useDbalConstants ? ParameterType::INTEGER : \PDO::PARAM_INT);
+            $stmt->bindValue(':time', $now, $useDbalConstants ? ParameterType::INTEGER : \PDO::PARAM_INT);
         }
         if (null === $driver) {
             $insertStmt = $conn->prepare($insertSql);
 
             $insertStmt->bindParam(':id', $id);
-            $insertStmt->bindParam(':data', $data, \PDO::PARAM_LOB);
-            $insertStmt->bindValue(':lifetime', $lifetime, \PDO::PARAM_INT);
-            $insertStmt->bindValue(':time', $now, \PDO::PARAM_INT);
+            $insertStmt->bindParam(':data', $data, $useDbalConstants ? ParameterType::LARGE_OBJECT : \PDO::PARAM_LOB);
+            $insertStmt->bindValue(':lifetime', $lifetime, $useDbalConstants ? ParameterType::INTEGER : \PDO::PARAM_INT);
+            $insertStmt->bindValue(':time', $now, $useDbalConstants ? ParameterType::INTEGER : \PDO::PARAM_INT);
         }
 
-        foreach ($serialized as $id => $data) {
-            $result = $stmt->execute();
-
+        foreach ($values as $id => $data) {
+            try {
+                $result = $stmt->execute();
+            } catch (TableNotFoundException $e) {
+                if (!$conn->isTransactionActive() || \in_array($this->driver, ['pgsql', 'sqlite', 'sqlsrv'], true)) {
+                    $this->createTable();
+                }
+                $result = $stmt->execute();
+            } catch (\PDOException $e) {
+                if (!$conn->inTransaction() || \in_array($this->driver, ['pgsql', 'sqlite', 'sqlsrv'], true)) {
+                    $this->createTable();
+                }
+                $result = $stmt->execute();
+            }
             if (null === $driver && !(\is_object($result) ? $result->rowCount() : $stmt->rowCount())) {
                 try {
                     $insertStmt->execute();
-                } catch (DBALException $e) {
+                } catch (DBALException|Exception $e) {
                 } catch (\PDOException $e) {
                     // A concurrent write won, let it be
                 }
@@ -369,8 +428,15 @@ trait PdoTrait
     private function getConnection()
     {
         if (null === $this->conn) {
-            $this->conn = new \PDO($this->dsn, $this->username, $this->password, $this->connectionOptions);
-            $this->conn->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION);
+            if (strpos($this->dsn, '://')) {
+                if (!class_exists(DriverManager::class)) {
+                    throw new InvalidArgumentException(sprintf('Failed to parse the DSN "%s". Try running "composer require doctrine/dbal".', $this->dsn));
+                }
+                $this->conn = DriverManager::getConnection(['url' => $this->dsn]);
+            } else {
+                $this->conn = new \PDO($this->dsn, $this->username, $this->password, $this->connectionOptions);
+                $this->conn->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION);
+            }
         }
         if (null === $this->driver) {
             if ($this->conn instanceof \PDO) {
@@ -379,11 +445,9 @@ trait PdoTrait
                 $driver = $this->conn->getDriver();
 
                 switch (true) {
-                    case $driver instanceof \Doctrine\DBAL\Driver\AbstractMySQLDriver:
-                    case $driver instanceof \Doctrine\DBAL\Driver\DrizzlePDOMySql\Driver:
                     case $driver instanceof \Doctrine\DBAL\Driver\Mysqli\Driver:
-                    case $driver instanceof \Doctrine\DBAL\Driver\PDOMySql\Driver:
-                    case $driver instanceof \Doctrine\DBAL\Driver\PDO\MySQL\Driver:
+                        throw new \LogicException(sprintf('The adapter "%s" does not support the mysqli driver, use pdo_mysql instead.', static::class));
+                    case $driver instanceof \Doctrine\DBAL\Driver\AbstractMySQLDriver:
                         $this->driver = 'mysql';
                         break;
                     case $driver instanceof \Doctrine\DBAL\Driver\PDOSqlite\Driver:
@@ -404,6 +468,15 @@ trait PdoTrait
                     case $driver instanceof \Doctrine\DBAL\Driver\PDO\SQLSrv\Driver:
                         $this->driver = 'sqlsrv';
                         break;
+                    case $driver instanceof \Doctrine\DBAL\Driver:
+                        $this->driver = [
+                                'mssql' => 'sqlsrv',
+                                'oracle' => 'oci',
+                                'postgresql' => 'pgsql',
+                                'sqlite' => 'sqlite',
+                                'mysql' => 'mysql',
+                            ][$driver->getDatabasePlatform()->getName()] ?? \get_class($driver);
+                        break;
                     default:
                         $this->driver = \get_class($driver);
                         break;
@@ -414,10 +487,7 @@ trait PdoTrait
         return $this->conn;
     }
 
-    /**
-     * @return string
-     */
-    private function getServerVersion()
+    private function getServerVersion(): string
     {
         if (null === $this->serverVersion) {
             $conn = $this->conn instanceof \PDO ? $this->conn : $this->conn->getWrappedConnection();
index 972c75121d4876a774d19784ce0d79b23a07f827..230c7bd4275c44239812301eb58109a75b9dc375 100644 (file)
 
 namespace Symfony\Component\Cache\Traits;
 
+use Symfony\Component\Cache\Adapter\AdapterInterface;
 use Symfony\Component\Cache\CacheItem;
 use Symfony\Component\Cache\Exception\InvalidArgumentException;
+use Symfony\Component\VarExporter\VarExporter;
 
 /**
  * @author Titouan Galopin <galopintitouan@gmail.com>
@@ -25,8 +27,8 @@ trait PhpArrayTrait
     use ProxyTrait;
 
     private $file;
+    private $keys;
     private $values;
-    private $zendDetectUnicode;
 
     private static $valuesCache = [];
 
@@ -57,56 +59,63 @@ trait PhpArrayTrait
             }
         }
 
+        $dumpedValues = '';
+        $dumpedMap = [];
         $dump = <<<'EOF'
 <?php
 
 // This file has been auto-generated by the Symfony Cache Component.
 
-return [
+return [[
 
 
 EOF;
 
         foreach ($values as $key => $value) {
             CacheItem::validateKey(\is_int($key) ? (string) $key : $key);
+            $isStaticValue = true;
 
-            if (null === $value || \is_object($value)) {
+            if (null === $value) {
+                $value = "'N;'";
+            } elseif (\is_object($value) || \is_array($value)) {
                 try {
-                    $value = serialize($value);
+                    $value = VarExporter::export($value, $isStaticValue);
                 } catch (\Exception $e) {
-                    throw new InvalidArgumentException(sprintf('Cache key "%s" has non-serializable "%s" value.', $key, \get_class($value)), 0, $e);
-                }
-            } elseif (\is_array($value)) {
-                try {
-                    $serialized = serialize($value);
-                    $unserialized = unserialize($serialized);
-                } catch (\Exception $e) {
-                    throw new InvalidArgumentException(sprintf('Cache key "%s" has non-serializable array value.', $key), 0, $e);
-                }
-                // Store arrays serialized if they contain any objects or references
-                if ($unserialized !== $value || (false !== strpos($serialized, ';R:') && preg_match('/;R:[1-9]/', $serialized))) {
-                    $value = $serialized;
+                    throw new InvalidArgumentException(sprintf('Cache key "%s" has non-serializable "%s" value.', $key, \is_object($value) ? \get_class($value) : 'array'), 0, $e);
                 }
             } elseif (\is_string($value)) {
-                // Serialize strings if they could be confused with serialized objects or arrays
-                if ('N;' === $value || (isset($value[2]) && ':' === $value[1])) {
-                    $value = serialize($value);
+                // Wrap "N;" in a closure to not confuse it with an encoded `null`
+                if ('N;' === $value) {
+                    $isStaticValue = false;
                 }
-            } elseif (!is_scalar($value)) {
+                $value = var_export($value, true);
+            } elseif (!\is_scalar($value)) {
                 throw new InvalidArgumentException(sprintf('Cache key "%s" has non-serializable "%s" value.', $key, \gettype($value)));
+            } else {
+                $value = var_export($value, true);
+            }
+
+            if (!$isStaticValue) {
+                $value = str_replace("\n", "\n    ", $value);
+                $value = "static function () {\n    return {$value};\n}";
+            }
+            $hash = hash('md5', $value);
+
+            if (null === $id = $dumpedMap[$hash] ?? null) {
+                $id = $dumpedMap[$hash] = \count($dumpedMap);
+                $dumpedValues .= "{$id} => {$value},\n";
             }
 
-            $dump .= var_export($key, true).' => '.var_export($value, true).",\n";
+            $dump .= var_export($key, true)." => {$id},\n";
         }
 
-        $dump .= "\n];\n";
-        $dump = str_replace("' . \"\\0\" . '", "\0", $dump);
+        $dump .= "\n], [\n\n{$dumpedValues}\n]];\n";
 
         $tmpFile = uniqid($this->file, true);
 
         file_put_contents($tmpFile, $dump);
         @chmod($tmpFile, 0666 & ~umask());
-        unset($serialized, $unserialized, $value, $dump);
+        unset($serialized, $value, $dump);
 
         @rename($tmpFile, $this->file);
         unset(self::$valuesCache[$this->file]);
@@ -116,14 +125,23 @@ EOF;
 
     /**
      * {@inheritdoc}
+     *
+     * @param string $prefix
+     *
+     * @return bool
      */
-    public function clear()
+    public function clear(/* string $prefix = '' */)
     {
-        $this->values = [];
+        $prefix = 0 < \func_num_args() ? (string) func_get_arg(0) : '';
+        $this->keys = $this->values = [];
 
         $cleared = @unlink($this->file) || !file_exists($this->file);
         unset(self::$valuesCache[$this->file]);
 
+        if ($this->pool instanceof AdapterInterface) {
+            return $this->pool->clear($prefix) && $cleared;
+        }
+
         return $this->pool->clear() && $cleared;
     }
 
@@ -133,20 +151,19 @@ EOF;
     private function initialize()
     {
         if (isset(self::$valuesCache[$this->file])) {
-            $this->values = self::$valuesCache[$this->file];
+            $values = self::$valuesCache[$this->file];
+        } elseif (!file_exists($this->file)) {
+            $this->keys = $this->values = [];
 
             return;
+        } else {
+            $values = self::$valuesCache[$this->file] = (include $this->file) ?: [[], []];
         }
 
-        if ($this->zendDetectUnicode) {
-            $zmb = ini_set('zend.detect_unicode', 0);
-        }
-        try {
-            $this->values = self::$valuesCache[$this->file] = file_exists($this->file) ? (include $this->file ?: []) : [];
-        } finally {
-            if ($this->zendDetectUnicode) {
-                ini_set('zend.detect_unicode', $zmb);
-            }
+        if (2 !== \count($values) || !isset($values[0], $values[1])) {
+            $this->keys = $this->values = [];
+        } else {
+            [$this->keys, $this->values] = $values;
         }
     }
 }
index 2668b26c106777bca850b874185ad51a86d62f99..c76e7fe312bc947ed5c967ef84e987a81feb3c9e 100644 (file)
@@ -13,6 +13,7 @@ namespace Symfony\Component\Cache\Traits;
 
 use Symfony\Component\Cache\Exception\CacheException;
 use Symfony\Component\Cache\Exception\InvalidArgumentException;
+use Symfony\Component\VarExporter\VarExporter;
 
 /**
  * @author Piotr Stankowski <git@trakos.pl>
@@ -23,14 +24,24 @@ use Symfony\Component\Cache\Exception\InvalidArgumentException;
  */
 trait PhpFilesTrait
 {
-    use FilesystemCommonTrait;
+    use FilesystemCommonTrait {
+        doClear as private doCommonClear;
+        doDelete as private doCommonDelete;
+    }
 
     private $includeHandler;
-    private $zendDetectUnicode;
+    private $appendOnly;
+    private $values = [];
+    private $files = [];
+
+    private static $startTime;
+    private static $valuesCache = [];
 
     public static function isSupported()
     {
-        return \function_exists('opcache_invalidate') && filter_var(ini_get('opcache.enable'), \FILTER_VALIDATE_BOOLEAN);
+        self::$startTime = self::$startTime ?? $_SERVER['REQUEST_TIME'] ?? time();
+
+        return \function_exists('opcache_invalidate') && filter_var(\ini_get('opcache.enable'), \FILTER_VALIDATE_BOOLEAN) && (!\in_array(\PHP_SAPI, ['cli', 'phpdbg'], true) || filter_var(\ini_get('opcache.enable_cli'), \FILTER_VALIDATE_BOOLEAN));
     }
 
     /**
@@ -40,19 +51,21 @@ trait PhpFilesTrait
     {
         $time = time();
         $pruned = true;
-        $allowCompile = 'cli' !== \PHP_SAPI || filter_var(ini_get('opcache.enable_cli'), \FILTER_VALIDATE_BOOLEAN);
+        $getExpiry = true;
 
         set_error_handler($this->includeHandler);
         try {
-            foreach (new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($this->directory, \FilesystemIterator::SKIP_DOTS), \RecursiveIteratorIterator::LEAVES_ONLY) as $file) {
-                list($expiresAt) = include $file;
+            foreach ($this->scanHashDir($this->directory) as $file) {
+                try {
+                    if (\is_array($expiresAt = include $file)) {
+                        $expiresAt = $expiresAt[0];
+                    }
+                } catch (\ErrorException $e) {
+                    $expiresAt = $time;
+                }
 
                 if ($time >= $expiresAt) {
-                    $pruned = @unlink($file) && !file_exists($file) && $pruned;
-
-                    if ($allowCompile) {
-                        @opcache_invalidate($file, true);
-                    }
+                    $pruned = $this->doUnlink($file) && !file_exists($file) && $pruned;
                 }
             }
         } finally {
@@ -67,41 +80,75 @@ trait PhpFilesTrait
      */
     protected function doFetch(array $ids)
     {
+        if ($this->appendOnly) {
+            $now = 0;
+            $missingIds = [];
+        } else {
+            $now = time();
+            $missingIds = $ids;
+            $ids = [];
+        }
         $values = [];
-        $now = time();
 
-        if ($this->zendDetectUnicode) {
-            $zmb = ini_set('zend.detect_unicode', 0);
+        begin:
+        $getExpiry = false;
+
+        foreach ($ids as $id) {
+            if (null === $value = $this->values[$id] ?? null) {
+                $missingIds[] = $id;
+            } elseif ('N;' === $value) {
+                $values[$id] = null;
+            } elseif (!\is_object($value)) {
+                $values[$id] = $value;
+            } elseif (!$value instanceof LazyValue) {
+                $values[$id] = $value();
+            } elseif (false === $values[$id] = include $value->file) {
+                unset($values[$id], $this->values[$id]);
+                $missingIds[] = $id;
+            }
+            if (!$this->appendOnly) {
+                unset($this->values[$id]);
+            }
         }
+
+        if (!$missingIds) {
+            return $values;
+        }
+
         set_error_handler($this->includeHandler);
         try {
-            foreach ($ids as $id) {
+            $getExpiry = true;
+
+            foreach ($missingIds as $k => $id) {
                 try {
-                    $file = $this->getFile($id);
-                    list($expiresAt, $values[$id]) = include $file;
+                    $file = $this->files[$id] ?? $this->files[$id] = $this->getFile($id);
+
+                    if (isset(self::$valuesCache[$file])) {
+                        [$expiresAt, $this->values[$id]] = self::$valuesCache[$file];
+                    } elseif (\is_array($expiresAt = include $file)) {
+                        if ($this->appendOnly) {
+                            self::$valuesCache[$file] = $expiresAt;
+                        }
+
+                        [$expiresAt, $this->values[$id]] = $expiresAt;
+                    } elseif ($now < $expiresAt) {
+                        $this->values[$id] = new LazyValue($file);
+                    }
+
                     if ($now >= $expiresAt) {
-                        unset($values[$id]);
+                        unset($this->values[$id], $missingIds[$k], self::$valuesCache[$file]);
                     }
-                } catch (\Exception $e) {
-                    continue;
+                } catch (\ErrorException $e) {
+                    unset($missingIds[$k]);
                 }
             }
         } finally {
             restore_error_handler();
-            if ($this->zendDetectUnicode) {
-                ini_set('zend.detect_unicode', $zmb);
-            }
-        }
-
-        foreach ($values as $id => $value) {
-            if ('N;' === $value) {
-                $values[$id] = null;
-            } elseif (\is_string($value) && isset($value[2]) && ':' === $value[1]) {
-                $values[$id] = parent::unserialize($value);
-            }
         }
 
-        return $values;
+        $ids = $missingIds;
+        $missingIds = [];
+        goto begin;
     }
 
     /**
@@ -109,44 +156,94 @@ trait PhpFilesTrait
      */
     protected function doHave($id)
     {
-        return (bool) $this->doFetch([$id]);
+        if ($this->appendOnly && isset($this->values[$id])) {
+            return true;
+        }
+
+        set_error_handler($this->includeHandler);
+        try {
+            $file = $this->files[$id] ?? $this->files[$id] = $this->getFile($id);
+            $getExpiry = true;
+
+            if (isset(self::$valuesCache[$file])) {
+                [$expiresAt, $value] = self::$valuesCache[$file];
+            } elseif (\is_array($expiresAt = include $file)) {
+                if ($this->appendOnly) {
+                    self::$valuesCache[$file] = $expiresAt;
+                }
+
+                [$expiresAt, $value] = $expiresAt;
+            } elseif ($this->appendOnly) {
+                $value = new LazyValue($file);
+            }
+        } catch (\ErrorException $e) {
+            return false;
+        } finally {
+            restore_error_handler();
+        }
+        if ($this->appendOnly) {
+            $now = 0;
+            $this->values[$id] = $value;
+        } else {
+            $now = time();
+        }
+
+        return $now < $expiresAt;
     }
 
     /**
      * {@inheritdoc}
      */
-    protected function doSave(array $values, $lifetime)
+    protected function doSave(array $values, int $lifetime)
     {
         $ok = true;
-        $data = [$lifetime ? time() + $lifetime : \PHP_INT_MAX, ''];
-        $allowCompile = 'cli' !== \PHP_SAPI || filter_var(ini_get('opcache.enable_cli'), \FILTER_VALIDATE_BOOLEAN);
+        $expiry = $lifetime ? time() + $lifetime : 'PHP_INT_MAX';
+        $allowCompile = self::isSupported();
 
         foreach ($values as $key => $value) {
-            if (null === $value || \is_object($value)) {
-                $value = serialize($value);
-            } elseif (\is_array($value)) {
-                $serialized = serialize($value);
-                $unserialized = parent::unserialize($serialized);
-                // Store arrays serialized if they contain any objects or references
-                if ($unserialized !== $value || (false !== strpos($serialized, ';R:') && preg_match('/;R:[1-9]/', $serialized))) {
-                    $value = $serialized;
+            unset($this->values[$key]);
+            $isStaticValue = true;
+            if (null === $value) {
+                $value = "'N;'";
+            } elseif (\is_object($value) || \is_array($value)) {
+                try {
+                    $value = VarExporter::export($value, $isStaticValue);
+                } catch (\Exception $e) {
+                    throw new InvalidArgumentException(sprintf('Cache key "%s" has non-serializable "%s" value.', $key, \is_object($value) ? \get_class($value) : 'array'), 0, $e);
                 }
             } elseif (\is_string($value)) {
-                // Serialize strings if they could be confused with serialized objects or arrays
-                if ('N;' === $value || (isset($value[2]) && ':' === $value[1])) {
-                    $value = serialize($value);
+                // Wrap "N;" in a closure to not confuse it with an encoded `null`
+                if ('N;' === $value) {
+                    $isStaticValue = false;
                 }
-            } elseif (!is_scalar($value)) {
+                $value = var_export($value, true);
+            } elseif (!\is_scalar($value)) {
                 throw new InvalidArgumentException(sprintf('Cache key "%s" has non-serializable "%s" value.', $key, \gettype($value)));
+            } else {
+                $value = var_export($value, true);
             }
 
-            $data[1] = $value;
-            $file = $this->getFile($key, true);
-            $ok = $this->write($file, '<?php return '.var_export($data, true).';') && $ok;
+            $encodedKey = rawurlencode($key);
+
+            if ($isStaticValue) {
+                $value = "return [{$expiry}, {$value}];";
+            } elseif ($this->appendOnly) {
+                $value = "return [{$expiry}, static function () { return {$value}; }];";
+            } else {
+                // We cannot use a closure here because of https://bugs.php.net/76982
+                $value = str_replace('\Symfony\Component\VarExporter\Internal\\', '', $value);
+                $value = "namespace Symfony\Component\VarExporter\Internal;\n\nreturn \$getExpiry ? {$expiry} : {$value};";
+            }
+
+            $file = $this->files[$key] = $this->getFile($key, true);
+            // Since OPcache only compiles files older than the script execution start, set the file's mtime in the past
+            $ok = $this->write($file, "<?php //{$encodedKey}\n\n{$value}\n", self::$startTime - 10) && $ok;
 
             if ($allowCompile) {
                 @opcache_invalidate($file, true);
+                @opcache_compile_file($file);
             }
+            unset(self::$valuesCache[$file]);
         }
 
         if (!$ok && !is_writable($this->directory)) {
@@ -155,4 +252,62 @@ trait PhpFilesTrait
 
         return $ok;
     }
+
+    /**
+     * {@inheritdoc}
+     */
+    protected function doClear($namespace)
+    {
+        $this->values = [];
+
+        return $this->doCommonClear($namespace);
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    protected function doDelete(array $ids)
+    {
+        foreach ($ids as $id) {
+            unset($this->values[$id]);
+        }
+
+        return $this->doCommonDelete($ids);
+    }
+
+    protected function doUnlink($file)
+    {
+        unset(self::$valuesCache[$file]);
+
+        if (self::isSupported()) {
+            @opcache_invalidate($file, true);
+        }
+
+        return @unlink($file);
+    }
+
+    private function getFileKey(string $file): string
+    {
+        if (!$h = @fopen($file, 'r')) {
+            return '';
+        }
+
+        $encodedKey = substr(fgets($h), 8);
+        fclose($h);
+
+        return rawurldecode(rtrim($encodedKey));
+    }
+}
+
+/**
+ * @internal
+ */
+class LazyValue
+{
+    public $file;
+
+    public function __construct(string $file)
+    {
+        $this->file = $file;
+    }
 }
index d9e085b9ea88714d253377ceb5052e971158b8c4..c86f360ab752a246c0949cedc88ec42ce1063028 100644 (file)
@@ -12,7 +12,7 @@
 namespace Symfony\Component\Cache\Traits;
 
 use Symfony\Component\Cache\PruneableInterface;
-use Symfony\Component\Cache\ResettableInterface;
+use Symfony\Contracts\Service\ResetInterface;
 
 /**
  * @author Nicolas Grekas <p@tchwork.com>
@@ -36,7 +36,7 @@ trait ProxyTrait
      */
     public function reset()
     {
-        if ($this->pool instanceof ResettableInterface) {
+        if ($this->pool instanceof ResetInterface) {
             $this->pool->reset();
         }
     }
diff --git a/advancedcontentfilter/vendor/symfony/cache/Traits/RedisClusterNodeProxy.php b/advancedcontentfilter/vendor/symfony/cache/Traits/RedisClusterNodeProxy.php
new file mode 100644 (file)
index 0000000..deba74f
--- /dev/null
@@ -0,0 +1,53 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien@symfony.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Cache\Traits;
+
+/**
+ * This file acts as a wrapper to the \RedisCluster implementation so it can accept the same type of calls as
+ *  individual \Redis objects.
+ *
+ * Calls are made to individual nodes via: RedisCluster->{method}($host, ...args)'
+ *  according to https://github.com/phpredis/phpredis/blob/develop/cluster.markdown#directed-node-commands
+ *
+ * @author Jack Thomas <jack.thomas@solidalpha.com>
+ *
+ * @internal
+ */
+class RedisClusterNodeProxy
+{
+    private $host;
+    private $redis;
+
+    /**
+     * @param \RedisCluster|RedisClusterProxy $redis
+     */
+    public function __construct(array $host, $redis)
+    {
+        $this->host = $host;
+        $this->redis = $redis;
+    }
+
+    public function __call(string $method, array $args)
+    {
+        return $this->redis->{$method}($this->host, ...$args);
+    }
+
+    public function scan(&$iIterator, $strPattern = null, $iCount = null)
+    {
+        return $this->redis->scan($iIterator, $this->host, $strPattern, $iCount);
+    }
+
+    public function getOption($name)
+    {
+        return $this->redis->getOption($name);
+    }
+}
diff --git a/advancedcontentfilter/vendor/symfony/cache/Traits/RedisClusterProxy.php b/advancedcontentfilter/vendor/symfony/cache/Traits/RedisClusterProxy.php
new file mode 100644 (file)
index 0000000..b4cef59
--- /dev/null
@@ -0,0 +1,63 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien@symfony.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Cache\Traits;
+
+/**
+ * @author Alessandro Chitolina <alekitto@gmail.com>
+ *
+ * @internal
+ */
+class RedisClusterProxy
+{
+    private $redis;
+    private $initializer;
+
+    public function __construct(\Closure $initializer)
+    {
+        $this->initializer = $initializer;
+    }
+
+    public function __call($method, array $args)
+    {
+        $this->redis ?: $this->redis = $this->initializer->__invoke();
+
+        return $this->redis->{$method}(...$args);
+    }
+
+    public function hscan($strKey, &$iIterator, $strPattern = null, $iCount = null)
+    {
+        $this->redis ?: $this->redis = $this->initializer->__invoke();
+
+        return $this->redis->hscan($strKey, $iIterator, $strPattern, $iCount);
+    }
+
+    public function scan(&$iIterator, $strPattern = null, $iCount = null)
+    {
+        $this->redis ?: $this->redis = $this->initializer->__invoke();
+
+        return $this->redis->scan($iIterator, $strPattern, $iCount);
+    }
+
+    public function sscan($strKey, &$iIterator, $strPattern = null, $iCount = null)
+    {
+        $this->redis ?: $this->redis = $this->initializer->__invoke();
+
+        return $this->redis->sscan($strKey, $iIterator, $strPattern, $iCount);
+    }
+
+    public function zscan($strKey, &$iIterator, $strPattern = null, $iCount = null)
+    {
+        $this->redis ?: $this->redis = $this->initializer->__invoke();
+
+        return $this->redis->zscan($strKey, $iIterator, $strPattern, $iCount);
+    }
+}
index 98ea3aba766d17eaf955d824592700814e2d33ac..2b0b85736720b0b6678be83c274bdedd75a5e491 100644 (file)
@@ -32,7 +32,7 @@ class RedisProxy
     {
         $this->ready ?: $this->ready = $this->initializer->__invoke($this->redis);
 
-        return \call_user_func_array([$this->redis, $method], $args);
+        return $this->redis->{$method}(...$args);
     }
 
     public function hscan($strKey, &$iIterator, $strPattern = null, $iCount = null)
index a30d6d3fa52a0218d7598be55d0963f81fa09b63..dabdde4e705ce95ca257b80381bfe4516053245d 100644 (file)
@@ -13,10 +13,13 @@ namespace Symfony\Component\Cache\Traits;
 
 use Predis\Connection\Aggregate\ClusterInterface;
 use Predis\Connection\Aggregate\RedisCluster;
-use Predis\Connection\Factory;
+use Predis\Connection\Aggregate\ReplicationInterface;
+use Predis\Response\ErrorInterface;
 use Predis\Response\Status;
 use Symfony\Component\Cache\Exception\CacheException;
 use Symfony\Component\Cache\Exception\InvalidArgumentException;
+use Symfony\Component\Cache\Marshaller\DefaultMarshaller;
+use Symfony\Component\Cache\Marshaller\MarshallerInterface;
 
 /**
  * @author Aurimas Niekis <aurimas@niekis.lt>
@@ -33,24 +36,40 @@ trait RedisTrait
         'timeout' => 30,
         'read_timeout' => 0,
         'retry_interval' => 0,
-        'lazy' => false,
+        'tcp_keepalive' => 0,
+        'lazy' => null,
+        'redis_cluster' => false,
+        'redis_sentinel' => null,
+        'dbindex' => 0,
+        'failover' => 'none',
+        'ssl' => null, // see https://php.net/context.ssl
     ];
     private $redis;
+    private $marshaller;
 
     /**
-     * @param \Redis|\RedisArray|\RedisCluster|\Predis\Client $redisClient
+     * @param \Redis|\RedisArray|\RedisCluster|\Predis\ClientInterface|RedisProxy|RedisClusterProxy $redis
      */
-    private function init($redisClient, $namespace = '', $defaultLifetime = 0)
+    private function init($redis, string $namespace, int $defaultLifetime, ?MarshallerInterface $marshaller)
     {
         parent::__construct($namespace, $defaultLifetime);
 
         if (preg_match('#[^-+_.A-Za-z0-9]#', $namespace, $match)) {
             throw new InvalidArgumentException(sprintf('RedisAdapter namespace contains "%s" but only characters in [-+_.A-Za-z0-9] are allowed.', $match[0]));
         }
-        if (!$redisClient instanceof \Redis && !$redisClient instanceof \RedisArray && !$redisClient instanceof \RedisCluster && !$redisClient instanceof \Predis\Client && !$redisClient instanceof RedisProxy) {
-            throw new InvalidArgumentException(sprintf('"%s()" expects parameter 1 to be Redis, RedisArray, RedisCluster or Predis\Client, "%s" given.', __METHOD__, \is_object($redisClient) ? \get_class($redisClient) : \gettype($redisClient)));
+
+        if (!$redis instanceof \Redis && !$redis instanceof \RedisArray && !$redis instanceof \RedisCluster && !$redis instanceof \Predis\ClientInterface && !$redis instanceof RedisProxy && !$redis instanceof RedisClusterProxy) {
+            throw new InvalidArgumentException(sprintf('"%s()" expects parameter 1 to be Redis, RedisArray, RedisCluster or Predis\ClientInterface, "%s" given.', __METHOD__, \is_object($redis) ? \get_class($redis) : \gettype($redis)));
+        }
+
+        if ($redis instanceof \Predis\ClientInterface && $redis->getOptions()->exceptions) {
+            $options = clone $redis->getOptions();
+            \Closure::bind(function () { $this->options['exceptions'] = false; }, $options, $options)();
+            $redis = new $redis($redis->getConnection(), $options);
         }
-        $this->redis = $redisClient;
+
+        $this->redis = $redis;
+        $this->marshaller = $marshaller ?? new DefaultMarshaller();
     }
 
     /**
@@ -68,57 +87,117 @@ trait RedisTrait
      *
      * @throws InvalidArgumentException when the DSN is invalid
      *
-     * @return \Redis|\Predis\Client According to the "class" option
+     * @return \Redis|\RedisCluster|RedisClusterProxy|RedisProxy|\Predis\ClientInterface According to the "class" option
      */
     public static function createConnection($dsn, array $options = [])
     {
-        if (0 !== strpos($dsn, 'redis://')) {
-            throw new InvalidArgumentException(sprintf('Invalid Redis DSN: "%s" does not start with "redis://".', $dsn));
+        if (str_starts_with($dsn, 'redis:')) {
+            $scheme = 'redis';
+        } elseif (str_starts_with($dsn, 'rediss:')) {
+            $scheme = 'rediss';
+        } else {
+            throw new InvalidArgumentException(sprintf('Invalid Redis DSN: "%s" does not start with "redis:" or "rediss".', $dsn));
+        }
+
+        if (!\extension_loaded('redis') && !class_exists(\Predis\Client::class)) {
+            throw new CacheException(sprintf('Cannot find the "redis" extension nor the "predis/predis" package: "%s".', $dsn));
         }
-        $params = preg_replace_callback('#^redis://(?:(?:[^:@]*+:)?([^@]*+)@)?#', function ($m) use (&$auth) {
-            if (isset($m[1])) {
-                $auth = $m[1];
+
+        $params = preg_replace_callback('#^'.$scheme.':(//)?(?:(?:[^:@]*+:)?([^@]*+)@)?#', function ($m) use (&$auth) {
+            if (isset($m[2])) {
+                $auth = $m[2];
+
+                if ('' === $auth) {
+                    $auth = null;
+                }
             }
 
-            return 'file://';
+            return 'file:'.($m[1] ?? '');
         }, $dsn);
+
         if (false === $params = parse_url($params)) {
             throw new InvalidArgumentException(sprintf('Invalid Redis DSN: "%s".', $dsn));
         }
-        if (!isset($params['host']) && !isset($params['path'])) {
-            throw new InvalidArgumentException(sprintf('Invalid Redis DSN: "%s".', $dsn));
+
+        $query = $hosts = [];
+
+        $tls = 'rediss' === $scheme;
+        $tcpScheme = $tls ? 'tls' : 'tcp';
+
+        if (isset($params['query'])) {
+            parse_str($params['query'], $query);
+
+            if (isset($query['host'])) {
+                if (!\is_array($hosts = $query['host'])) {
+                    throw new InvalidArgumentException(sprintf('Invalid Redis DSN: "%s".', $dsn));
+                }
+                foreach ($hosts as $host => $parameters) {
+                    if (\is_string($parameters)) {
+                        parse_str($parameters, $parameters);
+                    }
+                    if (false === $i = strrpos($host, ':')) {
+                        $hosts[$host] = ['scheme' => $tcpScheme, 'host' => $host, 'port' => 6379] + $parameters;
+                    } elseif ($port = (int) substr($host, 1 + $i)) {
+                        $hosts[$host] = ['scheme' => $tcpScheme, 'host' => substr($host, 0, $i), 'port' => $port] + $parameters;
+                    } else {
+                        $hosts[$host] = ['scheme' => 'unix', 'path' => substr($host, 0, $i)] + $parameters;
+                    }
+                }
+                $hosts = array_values($hosts);
+            }
         }
-        if (isset($params['path']) && preg_match('#/(\d+)$#', $params['path'], $m)) {
-            $params['dbindex'] = $m[1];
-            $params['path'] = substr($params['path'], 0, -\strlen($m[0]));
+
+        if (isset($params['host']) || isset($params['path'])) {
+            if (!isset($params['dbindex']) && isset($params['path'])) {
+                if (preg_match('#/(\d+)$#', $params['path'], $m)) {
+                    $params['dbindex'] = $m[1];
+                    $params['path'] = substr($params['path'], 0, -\strlen($m[0]));
+                } elseif (isset($params['host'])) {
+                    throw new InvalidArgumentException(sprintf('Invalid Redis DSN: "%s", the "dbindex" parameter must be a number.', $dsn));
+                }
+            }
+
+            if (isset($params['host'])) {
+                array_unshift($hosts, ['scheme' => $tcpScheme, 'host' => $params['host'], 'port' => $params['port'] ?? 6379]);
+            } else {
+                array_unshift($hosts, ['scheme' => 'unix', 'path' => $params['path']]);
+            }
         }
-        if (isset($params['host'])) {
-            $scheme = 'tcp';
-        } else {
-            $scheme = 'unix';
+
+        if (!$hosts) {
+            throw new InvalidArgumentException(sprintf('Invalid Redis DSN: "%s".', $dsn));
         }
-        $params += [
-            'host' => isset($params['host']) ? $params['host'] : $params['path'],
-            'port' => isset($params['host']) ? 6379 : null,
-            'dbindex' => 0,
-        ];
-        if (isset($params['query'])) {
-            parse_str($params['query'], $query);
-            $params += $query;
+
+        $params += $query + $options + self::$defaultConnectionOptions;
+
+        if (isset($params['redis_sentinel']) && !class_exists(\Predis\Client::class)) {
+            throw new CacheException(sprintf('Redis Sentinel support requires the "predis/predis" package: "%s".', $dsn));
         }
-        $params += $options + self::$defaultConnectionOptions;
-        if (null === $params['class'] && !\extension_loaded('redis') && !class_exists(\Predis\Client::class)) {
-            throw new CacheException(sprintf('Cannot find the "redis" extension, and "predis/predis" is not installed: "%s".', $dsn));
+
+        if (null === $params['class'] && !isset($params['redis_sentinel']) && \extension_loaded('redis')) {
+            $class = $params['redis_cluster'] ? \RedisCluster::class : (1 < \count($hosts) ? \RedisArray::class : \Redis::class);
+        } else {
+            $class = $params['class'] ?? \Predis\Client::class;
+
+            if (isset($params['redis_sentinel']) && !is_a($class, \Predis\Client::class, true)) {
+                throw new CacheException(sprintf('Cannot use Redis Sentinel: class "%s" does not extend "Predis\Client": "%s".', $class, $dsn));
+            }
         }
-        $class = null === $params['class'] ? (\extension_loaded('redis') ? \Redis::class : \Predis\Client::class) : $params['class'];
 
         if (is_a($class, \Redis::class, true)) {
             $connect = $params['persistent'] || $params['persistent_id'] ? 'pconnect' : 'connect';
             $redis = new $class();
 
-            $initializer = function ($redis) use ($connect, $params, $dsn, $auth) {
+            $initializer = static function ($redis) use ($connect, $params, $dsn, $auth, $hosts, $tls) {
+                $host = $hosts[0]['host'] ?? $hosts[0]['path'];
+                $port = $hosts[0]['port'] ?? 0;
+
+                if (isset($hosts[0]['host']) && $tls) {
+                    $host = 'tls://'.$host;
+                }
+
                 try {
-                    @$redis->{$connect}($params['host'], $params['port'], $params['timeout'], $params['persistent_id'], $params['retry_interval']);
+                    @$redis->{$connect}($host, $port, $params['timeout'], (string) $params['persistent_id'], $params['retry_interval'], $params['read_timeout'], ...\defined('Redis::SCAN_PREFIX') ? [['stream' => $params['ssl'] ?? null]] : []);
 
                     set_error_handler(function ($type, $msg) use (&$error) { $error = $msg; });
                     $isConnected = $redis->isConnected();
@@ -130,11 +209,14 @@ trait RedisTrait
 
                     if ((null !== $auth && !$redis->auth($auth))
                         || ($params['dbindex'] && !$redis->select($params['dbindex']))
-                        || ($params['read_timeout'] && !$redis->setOption(\Redis::OPT_READ_TIMEOUT, $params['read_timeout']))
                     ) {
                         $e = preg_replace('/^ERR /', '', $redis->getLastError());
                         throw new InvalidArgumentException(sprintf('Redis connection "%s" failed: ', $dsn).$e.'.');
                     }
+
+                    if (0 < $params['tcp_keepalive'] && \defined('Redis::OPT_TCP_KEEPALIVE')) {
+                        $redis->setOption(\Redis::OPT_TCP_KEEPALIVE, $params['tcp_keepalive']);
+                    }
                 } catch (\RedisException $e) {
                     throw new InvalidArgumentException(sprintf('Redis connection "%s" failed: ', $dsn).$e->getMessage());
                 }
@@ -147,13 +229,92 @@ trait RedisTrait
             } else {
                 $initializer($redis);
             }
-        } elseif (is_a($class, \Predis\Client::class, true)) {
-            $params['scheme'] = $scheme;
-            $params['database'] = $params['dbindex'] ?: null;
-            $params['password'] = $auth;
-            $redis = new $class((new Factory())->create($params));
+        } elseif (is_a($class, \RedisArray::class, true)) {
+            foreach ($hosts as $i => $host) {
+                switch ($host['scheme']) {
+                    case 'tcp': $hosts[$i] = $host['host'].':'.$host['port']; break;
+                    case 'tls': $hosts[$i] = 'tls://'.$host['host'].':'.$host['port']; break;
+                    default: $hosts[$i] = $host['path'];
+                }
+            }
+            $params['lazy_connect'] = $params['lazy'] ?? true;
+            $params['connect_timeout'] = $params['timeout'];
+
+            try {
+                $redis = new $class($hosts, $params);
+            } catch (\RedisClusterException $e) {
+                throw new InvalidArgumentException(sprintf('Redis connection "%s" failed: ', $dsn).$e->getMessage());
+            }
+
+            if (0 < $params['tcp_keepalive'] && \defined('Redis::OPT_TCP_KEEPALIVE')) {
+                $redis->setOption(\Redis::OPT_TCP_KEEPALIVE, $params['tcp_keepalive']);
+            }
+        } elseif (is_a($class, \RedisCluster::class, true)) {
+            $initializer = static function () use ($class, $params, $dsn, $hosts) {
+                foreach ($hosts as $i => $host) {
+                    switch ($host['scheme']) {
+                        case 'tcp': $hosts[$i] = $host['host'].':'.$host['port']; break;
+                        case 'tls': $hosts[$i] = 'tls://'.$host['host'].':'.$host['port']; break;
+                        default: $hosts[$i] = $host['path'];
+                    }
+                }
+
+                try {
+                    $redis = new $class(null, $hosts, $params['timeout'], $params['read_timeout'], (bool) $params['persistent'], $params['auth'] ?? '', ...\defined('Redis::SCAN_PREFIX') ? [$params['ssl'] ?? null] : []);
+                } catch (\RedisClusterException $e) {
+                    throw new InvalidArgumentException(sprintf('Redis connection "%s" failed: ', $dsn).$e->getMessage());
+                }
+
+                if (0 < $params['tcp_keepalive'] && \defined('Redis::OPT_TCP_KEEPALIVE')) {
+                    $redis->setOption(\Redis::OPT_TCP_KEEPALIVE, $params['tcp_keepalive']);
+                }
+                switch ($params['failover']) {
+                    case 'error': $redis->setOption(\RedisCluster::OPT_SLAVE_FAILOVER, \RedisCluster::FAILOVER_ERROR); break;
+                    case 'distribute': $redis->setOption(\RedisCluster::OPT_SLAVE_FAILOVER, \RedisCluster::FAILOVER_DISTRIBUTE); break;
+                    case 'slaves': $redis->setOption(\RedisCluster::OPT_SLAVE_FAILOVER, \RedisCluster::FAILOVER_DISTRIBUTE_SLAVES); break;
+                }
+
+                return $redis;
+            };
+
+            $redis = $params['lazy'] ? new RedisClusterProxy($initializer) : $initializer();
+        } elseif (is_a($class, \Predis\ClientInterface::class, true)) {
+            if ($params['redis_cluster']) {
+                $params['cluster'] = 'redis';
+                if (isset($params['redis_sentinel'])) {
+                    throw new InvalidArgumentException(sprintf('Cannot use both "redis_cluster" and "redis_sentinel" at the same time: "%s".', $dsn));
+                }
+            } elseif (isset($params['redis_sentinel'])) {
+                $params['replication'] = 'sentinel';
+                $params['service'] = $params['redis_sentinel'];
+            }
+            $params += ['parameters' => []];
+            $params['parameters'] += [
+                'persistent' => $params['persistent'],
+                'timeout' => $params['timeout'],
+                'read_write_timeout' => $params['read_timeout'],
+                'tcp_nodelay' => true,
+            ];
+            if ($params['dbindex']) {
+                $params['parameters']['database'] = $params['dbindex'];
+            }
+            if (null !== $auth) {
+                $params['parameters']['password'] = $auth;
+            }
+            if (1 === \count($hosts) && !($params['redis_cluster'] || $params['redis_sentinel'])) {
+                $hosts = $hosts[0];
+            } elseif (\in_array($params['failover'], ['slaves', 'distribute'], true) && !isset($params['replication'])) {
+                $params['replication'] = true;
+                $hosts[0] += ['alias' => 'master'];
+            }
+            $params['exceptions'] = false;
+
+            $redis = new $class($hosts, array_diff_key($params, array_diff_key(self::$defaultConnectionOptions, ['ssl' => null])));
+            if (isset($params['redis_sentinel'])) {
+                $redis->getConnection()->setSentinelTimeout($params['timeout']);
+            }
         } elseif (class_exists($class, false)) {
-            throw new InvalidArgumentException(sprintf('"%s" is not a subclass of "Redis" or "Predis\Client".', $class));
+            throw new InvalidArgumentException(sprintf('"%s" is not a subclass of "Redis", "RedisArray", "RedisCluster" nor "Predis\ClientInterface".', $class));
         } else {
             throw new InvalidArgumentException(sprintf('Class "%s" does not exist.', $class));
         }
@@ -172,7 +333,7 @@ trait RedisTrait
 
         $result = [];
 
-        if ($this->redis instanceof \Predis\Client && $this->redis->getConnection() instanceof ClusterInterface) {
+        if ($this->redis instanceof \Predis\ClientInterface && $this->redis->getConnection() instanceof ClusterInterface) {
             $values = $this->pipeline(function () use ($ids) {
                 foreach ($ids as $id) {
                     yield 'get' => [$id];
@@ -190,7 +351,7 @@ trait RedisTrait
 
         foreach ($values as $id => $v) {
             if ($v) {
-                $result[$id] = parent::unserialize($v);
+                $result[$id] = $this->marshaller->unmarshall($v);
             }
         }
 
@@ -210,32 +371,19 @@ trait RedisTrait
      */
     protected function doClear($namespace)
     {
-        $cleared = true;
-        $hosts = [$this->redis];
-        $evalArgs = [[$namespace], 0];
-
-        if ($this->redis instanceof \Predis\Client) {
-            $evalArgs = [0, $namespace];
+        if ($this->redis instanceof \Predis\ClientInterface) {
+            $prefix = $this->redis->getOptions()->prefix ? $this->redis->getOptions()->prefix->getPrefix() : '';
+            $prefixLen = \strlen($prefix ?? '');
+        }
 
-            $connection = $this->redis->getConnection();
-            if ($connection instanceof ClusterInterface && $connection instanceof \Traversable) {
-                $hosts = [];
-                foreach ($connection as $c) {
-                    $hosts[] = new \Predis\Client($c);
-                }
-            }
-        } elseif ($this->redis instanceof \RedisArray) {
-            $hosts = [];
-            foreach ($this->redis->_hosts() as $host) {
-                $hosts[] = $this->redis->_instance($host);
-            }
-        } elseif ($this->redis instanceof \RedisCluster) {
-            $hosts = [];
-            foreach ($this->redis->_masters() as $host) {
-                $hosts[] = $h = new \Redis();
-                $h->connect($host[0], $host[1]);
-            }
+        $cleared = true;
+        $hosts = $this->getHosts();
+        $host = reset($hosts);
+        if ($host instanceof \Predis\Client && $host->getConnection() instanceof ReplicationInterface) {
+            // Predis supports info command only on the master in replication environments
+            $hosts = [$host->getClientFor('master')];
         }
+
         foreach ($hosts as $host) {
             if (!isset($namespace[0])) {
                 $cleared = $host->flushDb() && $cleared;
@@ -243,24 +391,36 @@ trait RedisTrait
             }
 
             $info = $host->info('Server');
-            $info = isset($info['Server']) ? $info['Server'] : $info;
+            $info = !$info instanceof ErrorInterface ? $info['Server'] ?? $info : ['redis_version' => '2.0'];
+
+            if (!$host instanceof \Predis\ClientInterface) {
+                $prefix = \defined('Redis::SCAN_PREFIX') && (\Redis::SCAN_PREFIX & $host->getOption(\Redis::OPT_SCAN)) ? '' : $host->getOption(\Redis::OPT_PREFIX);
+                $prefixLen = \strlen($host->getOption(\Redis::OPT_PREFIX) ?? '');
+            }
+            $pattern = $prefix.$namespace.'*';
 
             if (!version_compare($info['redis_version'], '2.8', '>=')) {
                 // As documented in Redis documentation (http://redis.io/commands/keys) using KEYS
                 // can hang your server when it is executed against large databases (millions of items).
                 // Whenever you hit this scale, you should really consider upgrading to Redis 2.8 or above.
-                $cleared = $host->eval("local keys=redis.call('KEYS',ARGV[1]..'*') for i=1,#keys,5000 do redis.call('DEL',unpack(keys,i,math.min(i+4999,#keys))) end return 1", $evalArgs[0], $evalArgs[1]) && $cleared;
+                $args = $this->redis instanceof \Predis\ClientInterface ? [0, $pattern] : [[$pattern], 0];
+                $cleared = $host->eval("local keys=redis.call('KEYS',ARGV[1]) for i=1,#keys,5000 do redis.call('DEL',unpack(keys,i,math.min(i+4999,#keys))) end return 1", $args[0], $args[1]) && $cleared;
                 continue;
             }
 
             $cursor = null;
             do {
-                $keys = $host instanceof \Predis\Client ? $host->scan($cursor, 'MATCH', $namespace.'*', 'COUNT', 1000) : $host->scan($cursor, $namespace.'*', 1000);
+                $keys = $host instanceof \Predis\ClientInterface ? $host->scan($cursor, 'MATCH', $pattern, 'COUNT', 1000) : $host->scan($cursor, $pattern, 1000);
                 if (isset($keys[1]) && \is_array($keys[1])) {
                     $cursor = $keys[0];
                     $keys = $keys[1];
                 }
                 if ($keys) {
+                    if ($prefixLen) {
+                        foreach ($keys as $i => $key) {
+                            $keys[$i] = substr($key, $prefixLen);
+                        }
+                    }
                     $this->doDelete($keys);
                 }
             } while ($cursor = (int) $cursor);
@@ -278,7 +438,7 @@ trait RedisTrait
             return true;
         }
 
-        if ($this->redis instanceof \Predis\Client && $this->redis->getConnection() instanceof ClusterInterface) {
+        if ($this->redis instanceof \Predis\ClientInterface && $this->redis->getConnection() instanceof ClusterInterface) {
             $this->pipeline(function () use ($ids) {
                 foreach ($ids as $id) {
                     yield 'del' => [$id];
@@ -294,25 +454,14 @@ trait RedisTrait
     /**
      * {@inheritdoc}
      */
-    protected function doSave(array $values, $lifetime)
+    protected function doSave(array $values, int $lifetime)
     {
-        $serialized = [];
-        $failed = [];
-
-        foreach ($values as $id => $value) {
-            try {
-                $serialized[$id] = serialize($value);
-            } catch (\Exception $e) {
-                $failed[] = $id;
-            }
-        }
-
-        if (!$serialized) {
+        if (!$values = $this->marshaller->marshall($values, $failed)) {
             return $failed;
         }
 
-        $results = $this->pipeline(function () use ($serialized, $lifetime) {
-            foreach ($serialized as $id => $value) {
+        $results = $this->pipeline(function () use ($values, $lifetime) {
+            foreach ($values as $id => $value) {
                 if (0 >= $lifetime) {
                     yield 'set' => [$id, $value];
                 } else {
@@ -320,8 +469,9 @@ trait RedisTrait
                 }
             }
         });
+
         foreach ($results as $id => $result) {
-            if (true !== $result && (!$result instanceof Status || $result !== Status::get('OK'))) {
+            if (true !== $result && (!$result instanceof Status || Status::get('OK') !== $result)) {
                 $failed[] = $id;
             }
         }
@@ -329,54 +479,87 @@ trait RedisTrait
         return $failed;
     }
 
-    private function pipeline(\Closure $generator)
+    private function pipeline(\Closure $generator, $redis = null): \Generator
     {
         $ids = [];
+        $redis = $redis ?? $this->redis;
 
-        if ($this->redis instanceof \RedisCluster || ($this->redis instanceof \Predis\Client && $this->redis->getConnection() instanceof RedisCluster)) {
+        if ($redis instanceof RedisClusterProxy || $redis instanceof \RedisCluster || ($redis instanceof \Predis\ClientInterface && $redis->getConnection() instanceof RedisCluster)) {
             // phpredis & predis don't support pipelining with RedisCluster
             // see https://github.com/phpredis/phpredis/blob/develop/cluster.markdown#pipelining
             // see https://github.com/nrk/predis/issues/267#issuecomment-123781423
             $results = [];
             foreach ($generator() as $command => $args) {
-                $results[] = \call_user_func_array([$this->redis, $command], $args);
-                $ids[] = $args[0];
+                $results[] = $redis->{$command}(...$args);
+                $ids[] = 'eval' === $command ? ($redis instanceof \Predis\ClientInterface ? $args[2] : $args[1][0]) : $args[0];
             }
-        } elseif ($this->redis instanceof \Predis\Client) {
-            $results = $this->redis->pipeline(function ($redis) use ($generator, &$ids) {
+        } elseif ($redis instanceof \Predis\ClientInterface) {
+            $results = $redis->pipeline(static function ($redis) use ($generator, &$ids) {
                 foreach ($generator() as $command => $args) {
-                    \call_user_func_array([$redis, $command], $args);
-                    $ids[] = $args[0];
+                    $redis->{$command}(...$args);
+                    $ids[] = 'eval' === $command ? $args[2] : $args[0];
                 }
             });
-        } elseif ($this->redis instanceof \RedisArray) {
+        } elseif ($redis instanceof \RedisArray) {
             $connections = $results = $ids = [];
             foreach ($generator() as $command => $args) {
-                if (!isset($connections[$h = $this->redis->_target($args[0])])) {
-                    $connections[$h] = [$this->redis->_instance($h), -1];
+                $id = 'eval' === $command ? $args[1][0] : $args[0];
+                if (!isset($connections[$h = $redis->_target($id)])) {
+                    $connections[$h] = [$redis->_instance($h), -1];
                     $connections[$h][0]->multi(\Redis::PIPELINE);
                 }
-                \call_user_func_array([$connections[$h][0], $command], $args);
+                $connections[$h][0]->{$command}(...$args);
                 $results[] = [$h, ++$connections[$h][1]];
-                $ids[] = $args[0];
+                $ids[] = $id;
             }
             foreach ($connections as $h => $c) {
                 $connections[$h] = $c[0]->exec();
             }
-            foreach ($results as $k => list($h, $c)) {
+            foreach ($results as $k => [$h, $c]) {
                 $results[$k] = $connections[$h][$c];
             }
         } else {
-            $this->redis->multi(\Redis::PIPELINE);
+            $redis->multi(\Redis::PIPELINE);
             foreach ($generator() as $command => $args) {
-                \call_user_func_array([$this->redis, $command], $args);
-                $ids[] = $args[0];
+                $redis->{$command}(...$args);
+                $ids[] = 'eval' === $command ? $args[1][0] : $args[0];
             }
-            $results = $this->redis->exec();
+            $results = $redis->exec();
+        }
+
+        if (!$redis instanceof \Predis\ClientInterface && 'eval' === $command && $redis->getLastError()) {
+            $e = new \RedisException($redis->getLastError());
+            $results = array_map(function ($v) use ($e) { return false === $v ? $e : $v; }, $results);
         }
 
         foreach ($ids as $k => $id) {
             yield $id => $results[$k];
         }
     }
+
+    private function getHosts(): array
+    {
+        $hosts = [$this->redis];
+        if ($this->redis instanceof \Predis\ClientInterface) {
+            $connection = $this->redis->getConnection();
+            if ($connection instanceof ClusterInterface && $connection instanceof \Traversable) {
+                $hosts = [];
+                foreach ($connection as $c) {
+                    $hosts[] = new \Predis\Client($c);
+                }
+            }
+        } elseif ($this->redis instanceof \RedisArray) {
+            $hosts = [];
+            foreach ($this->redis->_hosts() as $host) {
+                $hosts[] = $this->redis->_instance($host);
+            }
+        } elseif ($this->redis instanceof RedisClusterProxy || $this->redis instanceof \RedisCluster) {
+            $hosts = [];
+            foreach ($this->redis->_masters() as $host) {
+                $hosts[] = new RedisClusterNodeProxy($host, $this->redis);
+            }
+        }
+
+        return $hosts;
+    }
 }
index f412e4f1706877e26c92efb8c73eb9806c7a2c71..7a9e8df5a40e4e94036e9c372fc251be3d38fd70 100644 (file)
@@ -1,7 +1,7 @@
 {
     "name": "symfony/cache",
     "type": "library",
-    "description": "Symfony Cache component with PSR-6, PSR-16, and tags",
+    "description": "Provides extended PSR-6, PSR-16 (and tags) implementations",
     "keywords": ["caching", "psr6"],
     "homepage": "https://symfony.com",
     "license": "MIT",
         }
     ],
     "provide": {
-        "psr/cache-implementation": "1.0",
-        "psr/simple-cache-implementation": "1.0"
+        "psr/cache-implementation": "1.0|2.0",
+        "psr/simple-cache-implementation": "1.0|2.0",
+        "symfony/cache-implementation": "1.0|2.0"
     },
     "require": {
-        "php": "^5.5.9|>=7.0.8",
-        "psr/cache": "~1.0",
-        "psr/log": "~1.0",
-        "psr/simple-cache": "^1.0",
-        "symfony/polyfill-apcu": "~1.1"
+        "php": ">=7.1.3",
+        "psr/cache": "^1.0|^2.0",
+        "psr/log": "^1|^2|^3",
+        "symfony/cache-contracts": "^1.1.7|^2",
+        "symfony/polyfill-php73": "^1.9",
+        "symfony/polyfill-php80": "^1.16",
+        "symfony/service-contracts": "^1.1|^2",
+        "symfony/var-exporter": "^4.2|^5.0"
     },
     "require-dev": {
         "cache/integration-tests": "dev-master",
-        "doctrine/cache": "^1.6",
-        "doctrine/dbal": "^2.4|^3.0",
-        "predis/predis": "^1.0"
+        "doctrine/cache": "^1.6|^2.0",
+        "doctrine/dbal": "^2.7|^3.0",
+        "predis/predis": "^1.1",
+        "psr/simple-cache": "^1.0|^2.0",
+        "symfony/config": "^4.2|^5.0",
+        "symfony/dependency-injection": "^3.4|^4.1|^5.0",
+        "symfony/filesystem": "^4.4|^5.0",
+        "symfony/http-kernel": "^4.4",
+        "symfony/var-dumper": "^4.4|^5.0"
     },
     "conflict": {
-        "symfony/var-dumper": "<3.3"
+        "doctrine/dbal": "<2.7",
+        "symfony/dependency-injection": "<3.4",
+        "symfony/http-kernel": "<4.4|>=5.0",
+        "symfony/var-dumper": "<4.4"
     },
     "autoload": {
         "psr-4": { "Symfony\\Component\\Cache\\": "" },
diff --git a/advancedcontentfilter/vendor/symfony/deprecation-contracts/.gitignore b/advancedcontentfilter/vendor/symfony/deprecation-contracts/.gitignore
new file mode 100644 (file)
index 0000000..c49a5d8
--- /dev/null
@@ -0,0 +1,3 @@
+vendor/
+composer.lock
+phpunit.xml
diff --git a/advancedcontentfilter/vendor/symfony/deprecation-contracts/CHANGELOG.md b/advancedcontentfilter/vendor/symfony/deprecation-contracts/CHANGELOG.md
new file mode 100644 (file)
index 0000000..7932e26
--- /dev/null
@@ -0,0 +1,5 @@
+CHANGELOG
+=========
+
+The changelog is maintained for all Symfony contracts at the following URL:
+https://github.com/symfony/contracts/blob/main/CHANGELOG.md
diff --git a/advancedcontentfilter/vendor/symfony/deprecation-contracts/LICENSE b/advancedcontentfilter/vendor/symfony/deprecation-contracts/LICENSE
new file mode 100644 (file)
index 0000000..406242f
--- /dev/null
@@ -0,0 +1,19 @@
+Copyright (c) 2020-2022 Fabien Potencier
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is furnished
+to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
diff --git a/advancedcontentfilter/vendor/symfony/deprecation-contracts/README.md b/advancedcontentfilter/vendor/symfony/deprecation-contracts/README.md
new file mode 100644 (file)
index 0000000..4957933
--- /dev/null
@@ -0,0 +1,26 @@
+Symfony Deprecation Contracts
+=============================
+
+A generic function and convention to trigger deprecation notices.
+
+This package provides a single global function named `trigger_deprecation()` that triggers silenced deprecation notices.
+
+By using a custom PHP error handler such as the one provided by the Symfony ErrorHandler component,
+the triggered deprecations can be caught and logged for later discovery, both on dev and prod environments.
+
+The function requires at least 3 arguments:
+ - the name of the Composer package that is triggering the deprecation
+ - the version of the package that introduced the deprecation
+ - the message of the deprecation
+ - more arguments can be provided: they will be inserted in the message using `printf()` formatting
+
+Example:
+```php
+trigger_deprecation('symfony/blockchain', '8.9', 'Using "%s" is deprecated, use "%s" instead.', 'bitcoin', 'fabcoin');
+```
+
+This will generate the following message:
+`Since symfony/blockchain 8.9: Using "bitcoin" is deprecated, use "fabcoin" instead.`
+
+While not necessarily recommended, the deprecation notices can be completely ignored by declaring an empty
+`function trigger_deprecation() {}` in your application.
diff --git a/advancedcontentfilter/vendor/symfony/deprecation-contracts/composer.json b/advancedcontentfilter/vendor/symfony/deprecation-contracts/composer.json
new file mode 100644 (file)
index 0000000..cc7cc12
--- /dev/null
@@ -0,0 +1,35 @@
+{
+    "name": "symfony/deprecation-contracts",
+    "type": "library",
+    "description": "A generic function and convention to trigger deprecation notices",
+    "homepage": "https://symfony.com",
+    "license": "MIT",
+    "authors": [
+        {
+            "name": "Nicolas Grekas",
+            "email": "p@tchwork.com"
+        },
+        {
+            "name": "Symfony Community",
+            "homepage": "https://symfony.com/contributors"
+        }
+    ],
+    "require": {
+        "php": ">=7.1"
+    },
+    "autoload": {
+        "files": [
+            "function.php"
+        ]
+    },
+    "minimum-stability": "dev",
+    "extra": {
+        "branch-alias": {
+            "dev-main": "2.5-dev"
+        },
+        "thanks": {
+            "name": "symfony/contracts",
+            "url": "https://github.com/symfony/contracts"
+        }
+    }
+}
diff --git a/advancedcontentfilter/vendor/symfony/deprecation-contracts/function.php b/advancedcontentfilter/vendor/symfony/deprecation-contracts/function.php
new file mode 100644 (file)
index 0000000..d437150
--- /dev/null
@@ -0,0 +1,27 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien@symfony.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+if (!function_exists('trigger_deprecation')) {
+    /**
+     * Triggers a silenced deprecation notice.
+     *
+     * @param string $package The name of the Composer package that is triggering the deprecation
+     * @param string $version The version of the package that introduced the deprecation
+     * @param string $message The message of the deprecation
+     * @param mixed  ...$args Values to insert in the message using printf() formatting
+     *
+     * @author Nicolas Grekas <p@tchwork.com>
+     */
+    function trigger_deprecation(string $package, string $version, string $message, ...$args): void
+    {
+        @trigger_error(($package || $version ? "Since $package $version: " : '').($args ? vsprintf($message, $args) : $message), \E_USER_DEPRECATED);
+    }
+}
diff --git a/advancedcontentfilter/vendor/symfony/polyfill-php73/LICENSE b/advancedcontentfilter/vendor/symfony/polyfill-php73/LICENSE
new file mode 100644 (file)
index 0000000..7536cae
--- /dev/null
@@ -0,0 +1,19 @@
+Copyright (c) 2018-present Fabien Potencier
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is furnished
+to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
diff --git a/advancedcontentfilter/vendor/symfony/polyfill-php73/Php73.php b/advancedcontentfilter/vendor/symfony/polyfill-php73/Php73.php
new file mode 100644 (file)
index 0000000..65c35a6
--- /dev/null
@@ -0,0 +1,43 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien@symfony.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Polyfill\Php73;
+
+/**
+ * @author Gabriel Caruso <carusogabriel34@gmail.com>
+ * @author Ion Bazan <ion.bazan@gmail.com>
+ *
+ * @internal
+ */
+final class Php73
+{
+    public static $startAt = 1533462603;
+
+    /**
+     * @param bool $asNum
+     *
+     * @return array|float|int
+     */
+    public static function hrtime($asNum = false)
+    {
+        $ns = microtime(false);
+        $s = substr($ns, 11) - self::$startAt;
+        $ns = 1E9 * (float) $ns;
+
+        if ($asNum) {
+            $ns += $s * 1E9;
+
+            return \PHP_INT_SIZE === 4 ? $ns : (int) $ns;
+        }
+
+        return [$s, (int) $ns];
+    }
+}
diff --git a/advancedcontentfilter/vendor/symfony/polyfill-php73/README.md b/advancedcontentfilter/vendor/symfony/polyfill-php73/README.md
new file mode 100644 (file)
index 0000000..032fafb
--- /dev/null
@@ -0,0 +1,18 @@
+Symfony Polyfill / Php73
+========================
+
+This component provides functions added to PHP 7.3 core:
+
+- [`array_key_first`](https://php.net/array_key_first)
+- [`array_key_last`](https://php.net/array_key_last)
+- [`hrtime`](https://php.net/function.hrtime)
+- [`is_countable`](https://php.net/is_countable)
+- [`JsonException`](https://php.net/JsonException)
+
+More information can be found in the
+[main Polyfill README](https://github.com/symfony/polyfill/blob/main/README.md).
+
+License
+=======
+
+This library is released under the [MIT license](LICENSE).
diff --git a/advancedcontentfilter/vendor/symfony/polyfill-php73/Resources/stubs/JsonException.php b/advancedcontentfilter/vendor/symfony/polyfill-php73/Resources/stubs/JsonException.php
new file mode 100644 (file)
index 0000000..f06d6c2
--- /dev/null
@@ -0,0 +1,16 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien@symfony.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+if (\PHP_VERSION_ID < 70300) {
+    class JsonException extends Exception
+    {
+    }
+}
diff --git a/advancedcontentfilter/vendor/symfony/polyfill-php73/bootstrap.php b/advancedcontentfilter/vendor/symfony/polyfill-php73/bootstrap.php
new file mode 100644 (file)
index 0000000..d6b2153
--- /dev/null
@@ -0,0 +1,31 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien@symfony.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+use Symfony\Polyfill\Php73 as p;
+
+if (\PHP_VERSION_ID >= 70300) {
+    return;
+}
+
+if (!function_exists('is_countable')) {
+    function is_countable($value) { return is_array($value) || $value instanceof Countable || $value instanceof ResourceBundle || $value instanceof SimpleXmlElement; }
+}
+if (!function_exists('hrtime')) {
+    require_once __DIR__.'/Php73.php';
+    p\Php73::$startAt = (int) microtime(true);
+    function hrtime($as_number = false) { return p\Php73::hrtime($as_number); }
+}
+if (!function_exists('array_key_first')) {
+    function array_key_first(array $array) { foreach ($array as $key => $value) { return $key; } }
+}
+if (!function_exists('array_key_last')) {
+    function array_key_last(array $array) { return key(array_slice($array, -1, 1, true)); }
+}
diff --git a/advancedcontentfilter/vendor/symfony/polyfill-php73/composer.json b/advancedcontentfilter/vendor/symfony/polyfill-php73/composer.json
new file mode 100644 (file)
index 0000000..3d47d15
--- /dev/null
@@ -0,0 +1,33 @@
+{
+    "name": "symfony/polyfill-php73",
+    "type": "library",
+    "description": "Symfony polyfill backporting some PHP 7.3+ features to lower PHP versions",
+    "keywords": ["polyfill", "shim", "compatibility", "portable"],
+    "homepage": "https://symfony.com",
+    "license": "MIT",
+    "authors": [
+        {
+            "name": "Nicolas Grekas",
+            "email": "p@tchwork.com"
+        },
+        {
+            "name": "Symfony Community",
+            "homepage": "https://symfony.com/contributors"
+        }
+    ],
+    "require": {
+        "php": ">=7.1"
+    },
+    "autoload": {
+        "psr-4": { "Symfony\\Polyfill\\Php73\\": "" },
+        "files": [ "bootstrap.php" ],
+        "classmap": [ "Resources/stubs" ]
+    },
+    "minimum-stability": "dev",
+    "extra": {
+        "thanks": {
+            "name": "symfony/polyfill",
+            "url": "https://github.com/symfony/polyfill"
+        }
+    }
+}
diff --git a/advancedcontentfilter/vendor/symfony/polyfill-php80/LICENSE b/advancedcontentfilter/vendor/symfony/polyfill-php80/LICENSE
new file mode 100644 (file)
index 0000000..0ed3a24
--- /dev/null
@@ -0,0 +1,19 @@
+Copyright (c) 2020-present Fabien Potencier
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is furnished
+to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
diff --git a/advancedcontentfilter/vendor/symfony/polyfill-php80/Php80.php b/advancedcontentfilter/vendor/symfony/polyfill-php80/Php80.php
new file mode 100644 (file)
index 0000000..362dd1a
--- /dev/null
@@ -0,0 +1,115 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien@symfony.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Polyfill\Php80;
+
+/**
+ * @author Ion Bazan <ion.bazan@gmail.com>
+ * @author Nico Oelgart <nicoswd@gmail.com>
+ * @author Nicolas Grekas <p@tchwork.com>
+ *
+ * @internal
+ */
+final class Php80
+{
+    public static function fdiv(float $dividend, float $divisor): float
+    {
+        return @($dividend / $divisor);
+    }
+
+    public static function get_debug_type($value): string
+    {
+        switch (true) {
+            case null === $value: return 'null';
+            case \is_bool($value): return 'bool';
+            case \is_string($value): return 'string';
+            case \is_array($value): return 'array';
+            case \is_int($value): return 'int';
+            case \is_float($value): return 'float';
+            case \is_object($value): break;
+            case $value instanceof \__PHP_Incomplete_Class: return '__PHP_Incomplete_Class';
+            default:
+                if (null === $type = @get_resource_type($value)) {
+                    return 'unknown';
+                }
+
+                if ('Unknown' === $type) {
+                    $type = 'closed';
+                }
+
+                return "resource ($type)";
+        }
+
+        $class = \get_class($value);
+
+        if (false === strpos($class, '@')) {
+            return $class;
+        }
+
+        return (get_parent_class($class) ?: key(class_implements($class)) ?: 'class').'@anonymous';
+    }
+
+    public static function get_resource_id($res): int
+    {
+        if (!\is_resource($res) && null === @get_resource_type($res)) {
+            throw new \TypeError(sprintf('Argument 1 passed to get_resource_id() must be of the type resource, %s given', get_debug_type($res)));
+        }
+
+        return (int) $res;
+    }
+
+    public static function preg_last_error_msg(): string
+    {
+        switch (preg_last_error()) {
+            case \PREG_INTERNAL_ERROR:
+                return 'Internal error';
+            case \PREG_BAD_UTF8_ERROR:
+                return 'Malformed UTF-8 characters, possibly incorrectly encoded';
+            case \PREG_BAD_UTF8_OFFSET_ERROR:
+                return 'The offset did not correspond to the beginning of a valid UTF-8 code point';
+            case \PREG_BACKTRACK_LIMIT_ERROR:
+                return 'Backtrack limit exhausted';
+            case \PREG_RECURSION_LIMIT_ERROR:
+                return 'Recursion limit exhausted';
+            case \PREG_JIT_STACKLIMIT_ERROR:
+                return 'JIT stack limit exhausted';
+            case \PREG_NO_ERROR:
+                return 'No error';
+            default:
+                return 'Unknown error';
+        }
+    }
+
+    public static function str_contains(string $haystack, string $needle): bool
+    {
+        return '' === $needle || false !== strpos($haystack, $needle);
+    }
+
+    public static function str_starts_with(string $haystack, string $needle): bool
+    {
+        return 0 === strncmp($haystack, $needle, \strlen($needle));
+    }
+
+    public static function str_ends_with(string $haystack, string $needle): bool
+    {
+        if ('' === $needle || $needle === $haystack) {
+            return true;
+        }
+
+        if ('' === $haystack) {
+            return false;
+        }
+
+        $needleLength = \strlen($needle);
+
+        return $needleLength <= \strlen($haystack) && 0 === substr_compare($haystack, $needle, -$needleLength);
+    }
+}
diff --git a/advancedcontentfilter/vendor/symfony/polyfill-php80/PhpToken.php b/advancedcontentfilter/vendor/symfony/polyfill-php80/PhpToken.php
new file mode 100644 (file)
index 0000000..fe6e691
--- /dev/null
@@ -0,0 +1,103 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien@symfony.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Polyfill\Php80;
+
+/**
+ * @author Fedonyuk Anton <info@ensostudio.ru>
+ *
+ * @internal
+ */
+class PhpToken implements \Stringable
+{
+    /**
+     * @var int
+     */
+    public $id;
+
+    /**
+     * @var string
+     */
+    public $text;
+
+    /**
+     * @var int
+     */
+    public $line;
+
+    /**
+     * @var int
+     */
+    public $pos;
+
+    public function __construct(int $id, string $text, int $line = -1, int $position = -1)
+    {
+        $this->id = $id;
+        $this->text = $text;
+        $this->line = $line;
+        $this->pos = $position;
+    }
+
+    public function getTokenName(): ?string
+    {
+        if ('UNKNOWN' === $name = token_name($this->id)) {
+            $name = \strlen($this->text) > 1 || \ord($this->text) < 32 ? null : $this->text;
+        }
+
+        return $name;
+    }
+
+    /**
+     * @param int|string|array $kind
+     */
+    public function is($kind): bool
+    {
+        foreach ((array) $kind as $value) {
+            if (\in_array($value, [$this->id, $this->text], true)) {
+                return true;
+            }
+        }
+
+        return false;
+    }
+
+    public function isIgnorable(): bool
+    {
+        return \in_array($this->id, [\T_WHITESPACE, \T_COMMENT, \T_DOC_COMMENT, \T_OPEN_TAG], true);
+    }
+
+    public function __toString(): string
+    {
+        return (string) $this->text;
+    }
+
+    /**
+     * @return static[]
+     */
+    public static function tokenize(string $code, int $flags = 0): array
+    {
+        $line = 1;
+        $position = 0;
+        $tokens = token_get_all($code, $flags);
+        foreach ($tokens as $index => $token) {
+            if (\is_string($token)) {
+                $id = \ord($token);
+                $text = $token;
+            } else {
+                [$id, $text, $line] = $token;
+            }
+            $tokens[$index] = new static($id, $text, $line, $position);
+            $position += \strlen($text);
+        }
+
+        return $tokens;
+    }
+}
diff --git a/advancedcontentfilter/vendor/symfony/polyfill-php80/README.md b/advancedcontentfilter/vendor/symfony/polyfill-php80/README.md
new file mode 100644 (file)
index 0000000..3816c55
--- /dev/null
@@ -0,0 +1,25 @@
+Symfony Polyfill / Php80
+========================
+
+This component provides features added to PHP 8.0 core:
+
+- [`Stringable`](https://php.net/stringable) interface
+- [`fdiv`](https://php.net/fdiv)
+- [`ValueError`](https://php.net/valueerror) class
+- [`UnhandledMatchError`](https://php.net/unhandledmatcherror) class
+- `FILTER_VALIDATE_BOOL` constant
+- [`get_debug_type`](https://php.net/get_debug_type)
+- [`PhpToken`](https://php.net/phptoken) class
+- [`preg_last_error_msg`](https://php.net/preg_last_error_msg)
+- [`str_contains`](https://php.net/str_contains)
+- [`str_starts_with`](https://php.net/str_starts_with)
+- [`str_ends_with`](https://php.net/str_ends_with)
+- [`get_resource_id`](https://php.net/get_resource_id)
+
+More information can be found in the
+[main Polyfill README](https://github.com/symfony/polyfill/blob/main/README.md).
+
+License
+=======
+
+This library is released under the [MIT license](LICENSE).
diff --git a/advancedcontentfilter/vendor/symfony/polyfill-php80/Resources/stubs/Attribute.php b/advancedcontentfilter/vendor/symfony/polyfill-php80/Resources/stubs/Attribute.php
new file mode 100644 (file)
index 0000000..2b95542
--- /dev/null
@@ -0,0 +1,31 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien@symfony.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+#[Attribute(Attribute::TARGET_CLASS)]
+final class Attribute
+{
+    public const TARGET_CLASS = 1;
+    public const TARGET_FUNCTION = 2;
+    public const TARGET_METHOD = 4;
+    public const TARGET_PROPERTY = 8;
+    public const TARGET_CLASS_CONSTANT = 16;
+    public const TARGET_PARAMETER = 32;
+    public const TARGET_ALL = 63;
+    public const IS_REPEATABLE = 64;
+
+    /** @var int */
+    public $flags;
+
+    public function __construct(int $flags = self::TARGET_ALL)
+    {
+        $this->flags = $flags;
+    }
+}
diff --git a/advancedcontentfilter/vendor/symfony/polyfill-php80/Resources/stubs/PhpToken.php b/advancedcontentfilter/vendor/symfony/polyfill-php80/Resources/stubs/PhpToken.php
new file mode 100644 (file)
index 0000000..bd1212f
--- /dev/null
@@ -0,0 +1,16 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien@symfony.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+if (\PHP_VERSION_ID < 80000 && extension_loaded('tokenizer')) {
+    class PhpToken extends Symfony\Polyfill\Php80\PhpToken
+    {
+    }
+}
diff --git a/advancedcontentfilter/vendor/symfony/polyfill-php80/Resources/stubs/Stringable.php b/advancedcontentfilter/vendor/symfony/polyfill-php80/Resources/stubs/Stringable.php
new file mode 100644 (file)
index 0000000..7c62d75
--- /dev/null
@@ -0,0 +1,20 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien@symfony.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+if (\PHP_VERSION_ID < 80000) {
+    interface Stringable
+    {
+        /**
+         * @return string
+         */
+        public function __toString();
+    }
+}
diff --git a/advancedcontentfilter/vendor/symfony/polyfill-php80/Resources/stubs/UnhandledMatchError.php b/advancedcontentfilter/vendor/symfony/polyfill-php80/Resources/stubs/UnhandledMatchError.php
new file mode 100644 (file)
index 0000000..01c6c6c
--- /dev/null
@@ -0,0 +1,16 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien@symfony.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+if (\PHP_VERSION_ID < 80000) {
+    class UnhandledMatchError extends Error
+    {
+    }
+}
diff --git a/advancedcontentfilter/vendor/symfony/polyfill-php80/Resources/stubs/ValueError.php b/advancedcontentfilter/vendor/symfony/polyfill-php80/Resources/stubs/ValueError.php
new file mode 100644 (file)
index 0000000..783dbc2
--- /dev/null
@@ -0,0 +1,16 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien@symfony.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+if (\PHP_VERSION_ID < 80000) {
+    class ValueError extends Error
+    {
+    }
+}
diff --git a/advancedcontentfilter/vendor/symfony/polyfill-php80/bootstrap.php b/advancedcontentfilter/vendor/symfony/polyfill-php80/bootstrap.php
new file mode 100644 (file)
index 0000000..e5f7dbc
--- /dev/null
@@ -0,0 +1,42 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien@symfony.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+use Symfony\Polyfill\Php80 as p;
+
+if (\PHP_VERSION_ID >= 80000) {
+    return;
+}
+
+if (!defined('FILTER_VALIDATE_BOOL') && defined('FILTER_VALIDATE_BOOLEAN')) {
+    define('FILTER_VALIDATE_BOOL', \FILTER_VALIDATE_BOOLEAN);
+}
+
+if (!function_exists('fdiv')) {
+    function fdiv(float $num1, float $num2): float { return p\Php80::fdiv($num1, $num2); }
+}
+if (!function_exists('preg_last_error_msg')) {
+    function preg_last_error_msg(): string { return p\Php80::preg_last_error_msg(); }
+}
+if (!function_exists('str_contains')) {
+    function str_contains(?string $haystack, ?string $needle): bool { return p\Php80::str_contains($haystack ?? '', $needle ?? ''); }
+}
+if (!function_exists('str_starts_with')) {
+    function str_starts_with(?string $haystack, ?string $needle): bool { return p\Php80::str_starts_with($haystack ?? '', $needle ?? ''); }
+}
+if (!function_exists('str_ends_with')) {
+    function str_ends_with(?string $haystack, ?string $needle): bool { return p\Php80::str_ends_with($haystack ?? '', $needle ?? ''); }
+}
+if (!function_exists('get_debug_type')) {
+    function get_debug_type($value): string { return p\Php80::get_debug_type($value); }
+}
+if (!function_exists('get_resource_id')) {
+    function get_resource_id($resource): int { return p\Php80::get_resource_id($resource); }
+}
diff --git a/advancedcontentfilter/vendor/symfony/polyfill-php80/composer.json b/advancedcontentfilter/vendor/symfony/polyfill-php80/composer.json
new file mode 100644 (file)
index 0000000..46ccde2
--- /dev/null
@@ -0,0 +1,37 @@
+{
+    "name": "symfony/polyfill-php80",
+    "type": "library",
+    "description": "Symfony polyfill backporting some PHP 8.0+ features to lower PHP versions",
+    "keywords": ["polyfill", "shim", "compatibility", "portable"],
+    "homepage": "https://symfony.com",
+    "license": "MIT",
+    "authors": [
+        {
+            "name": "Ion Bazan",
+            "email": "ion.bazan@gmail.com"
+        },
+        {
+            "name": "Nicolas Grekas",
+            "email": "p@tchwork.com"
+        },
+        {
+            "name": "Symfony Community",
+            "homepage": "https://symfony.com/contributors"
+        }
+    ],
+    "require": {
+        "php": ">=7.1"
+    },
+    "autoload": {
+        "psr-4": { "Symfony\\Polyfill\\Php80\\": "" },
+        "files": [ "bootstrap.php" ],
+        "classmap": [ "Resources/stubs" ]
+    },
+    "minimum-stability": "dev",
+    "extra": {
+        "thanks": {
+            "name": "symfony/polyfill",
+            "url": "https://github.com/symfony/polyfill"
+        }
+    }
+}
diff --git a/advancedcontentfilter/vendor/symfony/service-contracts/.gitignore b/advancedcontentfilter/vendor/symfony/service-contracts/.gitignore
new file mode 100644 (file)
index 0000000..c49a5d8
--- /dev/null
@@ -0,0 +1,3 @@
+vendor/
+composer.lock
+phpunit.xml
diff --git a/advancedcontentfilter/vendor/symfony/service-contracts/Attribute/Required.php b/advancedcontentfilter/vendor/symfony/service-contracts/Attribute/Required.php
new file mode 100644 (file)
index 0000000..9df8511
--- /dev/null
@@ -0,0 +1,25 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien@symfony.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Contracts\Service\Attribute;
+
+/**
+ * A required dependency.
+ *
+ * This attribute indicates that a property holds a required dependency. The annotated property or method should be
+ * considered during the instantiation process of the containing class.
+ *
+ * @author Alexander M. Turek <me@derrabus.de>
+ */
+#[\Attribute(\Attribute::TARGET_METHOD | \Attribute::TARGET_PROPERTY)]
+final class Required
+{
+}
diff --git a/advancedcontentfilter/vendor/symfony/service-contracts/Attribute/SubscribedService.php b/advancedcontentfilter/vendor/symfony/service-contracts/Attribute/SubscribedService.php
new file mode 100644 (file)
index 0000000..10d1bc3
--- /dev/null
@@ -0,0 +1,33 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien@symfony.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Contracts\Service\Attribute;
+
+use Symfony\Contracts\Service\ServiceSubscriberTrait;
+
+/**
+ * Use with {@see ServiceSubscriberTrait} to mark a method's return type
+ * as a subscribed service.
+ *
+ * @author Kevin Bond <kevinbond@gmail.com>
+ */
+#[\Attribute(\Attribute::TARGET_METHOD)]
+final class SubscribedService
+{
+    /**
+     * @param string|null $key The key to use for the service
+     *                         If null, use "ClassName::methodName"
+     */
+    public function __construct(
+        public ?string $key = null
+    ) {
+    }
+}
diff --git a/advancedcontentfilter/vendor/symfony/service-contracts/CHANGELOG.md b/advancedcontentfilter/vendor/symfony/service-contracts/CHANGELOG.md
new file mode 100644 (file)
index 0000000..7932e26
--- /dev/null
@@ -0,0 +1,5 @@
+CHANGELOG
+=========
+
+The changelog is maintained for all Symfony contracts at the following URL:
+https://github.com/symfony/contracts/blob/main/CHANGELOG.md
diff --git a/advancedcontentfilter/vendor/symfony/service-contracts/LICENSE b/advancedcontentfilter/vendor/symfony/service-contracts/LICENSE
new file mode 100644 (file)
index 0000000..74cdc2d
--- /dev/null
@@ -0,0 +1,19 @@
+Copyright (c) 2018-2022 Fabien Potencier
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is furnished
+to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
diff --git a/advancedcontentfilter/vendor/symfony/service-contracts/README.md b/advancedcontentfilter/vendor/symfony/service-contracts/README.md
new file mode 100644 (file)
index 0000000..41e054a
--- /dev/null
@@ -0,0 +1,9 @@
+Symfony Service Contracts
+=========================
+
+A set of abstractions extracted out of the Symfony components.
+
+Can be used to build on semantics that the Symfony components proved useful - and
+that already have battle tested implementations.
+
+See https://github.com/symfony/contracts/blob/main/README.md for more information.
diff --git a/advancedcontentfilter/vendor/symfony/service-contracts/ResetInterface.php b/advancedcontentfilter/vendor/symfony/service-contracts/ResetInterface.php
new file mode 100644 (file)
index 0000000..1af1075
--- /dev/null
@@ -0,0 +1,30 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien@symfony.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Contracts\Service;
+
+/**
+ * Provides a way to reset an object to its initial state.
+ *
+ * When calling the "reset()" method on an object, it should be put back to its
+ * initial state. This usually means clearing any internal buffers and forwarding
+ * the call to internal dependencies. All properties of the object should be put
+ * back to the same state it had when it was first ready to use.
+ *
+ * This method could be called, for example, to recycle objects that are used as
+ * services, so that they can be used to handle several requests in the same
+ * process loop (note that we advise making your services stateless instead of
+ * implementing this interface when possible.)
+ */
+interface ResetInterface
+{
+    public function reset();
+}
diff --git a/advancedcontentfilter/vendor/symfony/service-contracts/ServiceLocatorTrait.php b/advancedcontentfilter/vendor/symfony/service-contracts/ServiceLocatorTrait.php
new file mode 100644 (file)
index 0000000..74dfa43
--- /dev/null
@@ -0,0 +1,128 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien@symfony.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Contracts\Service;
+
+use Psr\Container\ContainerExceptionInterface;
+use Psr\Container\NotFoundExceptionInterface;
+
+// Help opcache.preload discover always-needed symbols
+class_exists(ContainerExceptionInterface::class);
+class_exists(NotFoundExceptionInterface::class);
+
+/**
+ * A trait to help implement ServiceProviderInterface.
+ *
+ * @author Robin Chalas <robin.chalas@gmail.com>
+ * @author Nicolas Grekas <p@tchwork.com>
+ */
+trait ServiceLocatorTrait
+{
+    private $factories;
+    private $loading = [];
+    private $providedTypes;
+
+    /**
+     * @param callable[] $factories
+     */
+    public function __construct(array $factories)
+    {
+        $this->factories = $factories;
+    }
+
+    /**
+     * {@inheritdoc}
+     *
+     * @return bool
+     */
+    public function has(string $id)
+    {
+        return isset($this->factories[$id]);
+    }
+
+    /**
+     * {@inheritdoc}
+     *
+     * @return mixed
+     */
+    public function get(string $id)
+    {
+        if (!isset($this->factories[$id])) {
+            throw $this->createNotFoundException($id);
+        }
+
+        if (isset($this->loading[$id])) {
+            $ids = array_values($this->loading);
+            $ids = \array_slice($this->loading, array_search($id, $ids));
+            $ids[] = $id;
+
+            throw $this->createCircularReferenceException($id, $ids);
+        }
+
+        $this->loading[$id] = $id;
+        try {
+            return $this->factories[$id]($this);
+        } finally {
+            unset($this->loading[$id]);
+        }
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function getProvidedServices(): array
+    {
+        if (null === $this->providedTypes) {
+            $this->providedTypes = [];
+
+            foreach ($this->factories as $name => $factory) {
+                if (!\is_callable($factory)) {
+                    $this->providedTypes[$name] = '?';
+                } else {
+                    $type = (new \ReflectionFunction($factory))->getReturnType();
+
+                    $this->providedTypes[$name] = $type ? ($type->allowsNull() ? '?' : '').($type instanceof \ReflectionNamedType ? $type->getName() : $type) : '?';
+                }
+            }
+        }
+
+        return $this->providedTypes;
+    }
+
+    private function createNotFoundException(string $id): NotFoundExceptionInterface
+    {
+        if (!$alternatives = array_keys($this->factories)) {
+            $message = 'is empty...';
+        } else {
+            $last = array_pop($alternatives);
+            if ($alternatives) {
+                $message = sprintf('only knows about the "%s" and "%s" services.', implode('", "', $alternatives), $last);
+            } else {
+                $message = sprintf('only knows about the "%s" service.', $last);
+            }
+        }
+
+        if ($this->loading) {
+            $message = sprintf('The service "%s" has a dependency on a non-existent service "%s". This locator %s', end($this->loading), $id, $message);
+        } else {
+            $message = sprintf('Service "%s" not found: the current service locator %s', $id, $message);
+        }
+
+        return new class($message) extends \InvalidArgumentException implements NotFoundExceptionInterface {
+        };
+    }
+
+    private function createCircularReferenceException(string $id, array $path): ContainerExceptionInterface
+    {
+        return new class(sprintf('Circular reference detected for service "%s", path: "%s".', $id, implode(' -> ', $path))) extends \RuntimeException implements ContainerExceptionInterface {
+        };
+    }
+}
diff --git a/advancedcontentfilter/vendor/symfony/service-contracts/ServiceProviderInterface.php b/advancedcontentfilter/vendor/symfony/service-contracts/ServiceProviderInterface.php
new file mode 100644 (file)
index 0000000..c60ad0b
--- /dev/null
@@ -0,0 +1,36 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien@symfony.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Contracts\Service;
+
+use Psr\Container\ContainerInterface;
+
+/**
+ * A ServiceProviderInterface exposes the identifiers and the types of services provided by a container.
+ *
+ * @author Nicolas Grekas <p@tchwork.com>
+ * @author Mateusz Sip <mateusz.sip@gmail.com>
+ */
+interface ServiceProviderInterface extends ContainerInterface
+{
+    /**
+     * Returns an associative array of service types keyed by the identifiers provided by the current container.
+     *
+     * Examples:
+     *
+     *  * ['logger' => 'Psr\Log\LoggerInterface'] means the object provides a service named "logger" that implements Psr\Log\LoggerInterface
+     *  * ['foo' => '?'] means the container provides service name "foo" of unspecified type
+     *  * ['bar' => '?Bar\Baz'] means the container provides a service "bar" of type Bar\Baz|null
+     *
+     * @return string[] The provided service types, keyed by service names
+     */
+    public function getProvidedServices(): array;
+}
diff --git a/advancedcontentfilter/vendor/symfony/service-contracts/ServiceSubscriberInterface.php b/advancedcontentfilter/vendor/symfony/service-contracts/ServiceSubscriberInterface.php
new file mode 100644 (file)
index 0000000..098ab90
--- /dev/null
@@ -0,0 +1,53 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien@symfony.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Contracts\Service;
+
+/**
+ * A ServiceSubscriber exposes its dependencies via the static {@link getSubscribedServices} method.
+ *
+ * The getSubscribedServices method returns an array of service types required by such instances,
+ * optionally keyed by the service names used internally. Service types that start with an interrogation
+ * mark "?" are optional, while the other ones are mandatory service dependencies.
+ *
+ * The injected service locators SHOULD NOT allow access to any other services not specified by the method.
+ *
+ * It is expected that ServiceSubscriber instances consume PSR-11-based service locators internally.
+ * This interface does not dictate any injection method for these service locators, although constructor
+ * injection is recommended.
+ *
+ * @author Nicolas Grekas <p@tchwork.com>
+ */
+interface ServiceSubscriberInterface
+{
+    /**
+     * Returns an array of service types required by such instances, optionally keyed by the service names used internally.
+     *
+     * For mandatory dependencies:
+     *
+     *  * ['logger' => 'Psr\Log\LoggerInterface'] means the objects use the "logger" name
+     *    internally to fetch a service which must implement Psr\Log\LoggerInterface.
+     *  * ['loggers' => 'Psr\Log\LoggerInterface[]'] means the objects use the "loggers" name
+     *    internally to fetch an iterable of Psr\Log\LoggerInterface instances.
+     *  * ['Psr\Log\LoggerInterface'] is a shortcut for
+     *  * ['Psr\Log\LoggerInterface' => 'Psr\Log\LoggerInterface']
+     *
+     * otherwise:
+     *
+     *  * ['logger' => '?Psr\Log\LoggerInterface'] denotes an optional dependency
+     *  * ['loggers' => '?Psr\Log\LoggerInterface[]'] denotes an optional iterable dependency
+     *  * ['?Psr\Log\LoggerInterface'] is a shortcut for
+     *  * ['Psr\Log\LoggerInterface' => '?Psr\Log\LoggerInterface']
+     *
+     * @return string[] The required service types, optionally keyed by service names
+     */
+    public static function getSubscribedServices();
+}
diff --git a/advancedcontentfilter/vendor/symfony/service-contracts/ServiceSubscriberTrait.php b/advancedcontentfilter/vendor/symfony/service-contracts/ServiceSubscriberTrait.php
new file mode 100644 (file)
index 0000000..16e3eb2
--- /dev/null
@@ -0,0 +1,109 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien@symfony.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Contracts\Service;
+
+use Psr\Container\ContainerInterface;
+use Symfony\Contracts\Service\Attribute\SubscribedService;
+
+/**
+ * Implementation of ServiceSubscriberInterface that determines subscribed services from
+ * method return types. Service ids are available as "ClassName::methodName".
+ *
+ * @author Kevin Bond <kevinbond@gmail.com>
+ */
+trait ServiceSubscriberTrait
+{
+    /** @var ContainerInterface */
+    protected $container;
+
+    /**
+     * {@inheritdoc}
+     */
+    public static function getSubscribedServices(): array
+    {
+        $services = method_exists(get_parent_class(self::class) ?: '', __FUNCTION__) ? parent::getSubscribedServices() : [];
+        $attributeOptIn = false;
+
+        if (\PHP_VERSION_ID >= 80000) {
+            foreach ((new \ReflectionClass(self::class))->getMethods() as $method) {
+                if (self::class !== $method->getDeclaringClass()->name) {
+                    continue;
+                }
+
+                if (!$attribute = $method->getAttributes(SubscribedService::class)[0] ?? null) {
+                    continue;
+                }
+
+                if ($method->isStatic() || $method->isAbstract() || $method->isGenerator() || $method->isInternal() || $method->getNumberOfRequiredParameters()) {
+                    throw new \LogicException(sprintf('Cannot use "%s" on method "%s::%s()" (can only be used on non-static, non-abstract methods with no parameters).', SubscribedService::class, self::class, $method->name));
+                }
+
+                if (!$returnType = $method->getReturnType()) {
+                    throw new \LogicException(sprintf('Cannot use "%s" on methods without a return type in "%s::%s()".', SubscribedService::class, $method->name, self::class));
+                }
+
+                $serviceId = $returnType instanceof \ReflectionNamedType ? $returnType->getName() : (string) $returnType;
+
+                if ($returnType->allowsNull()) {
+                    $serviceId = '?'.$serviceId;
+                }
+
+                $services[$attribute->newInstance()->key ?? self::class.'::'.$method->name] = $serviceId;
+                $attributeOptIn = true;
+            }
+        }
+
+        if (!$attributeOptIn) {
+            foreach ((new \ReflectionClass(self::class))->getMethods() as $method) {
+                if ($method->isStatic() || $method->isAbstract() || $method->isGenerator() || $method->isInternal() || $method->getNumberOfRequiredParameters()) {
+                    continue;
+                }
+
+                if (self::class !== $method->getDeclaringClass()->name) {
+                    continue;
+                }
+
+                if (!($returnType = $method->getReturnType()) instanceof \ReflectionNamedType) {
+                    continue;
+                }
+
+                if ($returnType->isBuiltin()) {
+                    continue;
+                }
+
+                if (\PHP_VERSION_ID >= 80000) {
+                    trigger_deprecation('symfony/service-contracts', '2.5', 'Using "%s" in "%s" without using the "%s" attribute on any method is deprecated.', ServiceSubscriberTrait::class, self::class, SubscribedService::class);
+                }
+
+                $services[self::class.'::'.$method->name] = '?'.($returnType instanceof \ReflectionNamedType ? $returnType->getName() : $returnType);
+            }
+        }
+
+        return $services;
+    }
+
+    /**
+     * @required
+     *
+     * @return ContainerInterface|null
+     */
+    public function setContainer(ContainerInterface $container)
+    {
+        $this->container = $container;
+
+        if (method_exists(get_parent_class(self::class) ?: '', __FUNCTION__)) {
+            return parent::setContainer($container);
+        }
+
+        return null;
+    }
+}
diff --git a/advancedcontentfilter/vendor/symfony/service-contracts/Test/ServiceLocatorTest.php b/advancedcontentfilter/vendor/symfony/service-contracts/Test/ServiceLocatorTest.php
new file mode 100644 (file)
index 0000000..2a1b565
--- /dev/null
@@ -0,0 +1,95 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien@symfony.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Contracts\Service\Test;
+
+use PHPUnit\Framework\TestCase;
+use Psr\Container\ContainerInterface;
+use Symfony\Contracts\Service\ServiceLocatorTrait;
+
+abstract class ServiceLocatorTest extends TestCase
+{
+    /**
+     * @return ContainerInterface
+     */
+    protected function getServiceLocator(array $factories)
+    {
+        return new class($factories) implements ContainerInterface {
+            use ServiceLocatorTrait;
+        };
+    }
+
+    public function testHas()
+    {
+        $locator = $this->getServiceLocator([
+            'foo' => function () { return 'bar'; },
+            'bar' => function () { return 'baz'; },
+            function () { return 'dummy'; },
+        ]);
+
+        $this->assertTrue($locator->has('foo'));
+        $this->assertTrue($locator->has('bar'));
+        $this->assertFalse($locator->has('dummy'));
+    }
+
+    public function testGet()
+    {
+        $locator = $this->getServiceLocator([
+            'foo' => function () { return 'bar'; },
+            'bar' => function () { return 'baz'; },
+        ]);
+
+        $this->assertSame('bar', $locator->get('foo'));
+        $this->assertSame('baz', $locator->get('bar'));
+    }
+
+    public function testGetDoesNotMemoize()
+    {
+        $i = 0;
+        $locator = $this->getServiceLocator([
+            'foo' => function () use (&$i) {
+                ++$i;
+
+                return 'bar';
+            },
+        ]);
+
+        $this->assertSame('bar', $locator->get('foo'));
+        $this->assertSame('bar', $locator->get('foo'));
+        $this->assertSame(2, $i);
+    }
+
+    public function testThrowsOnUndefinedInternalService()
+    {
+        if (!$this->getExpectedException()) {
+            $this->expectException(\Psr\Container\NotFoundExceptionInterface::class);
+            $this->expectExceptionMessage('The service "foo" has a dependency on a non-existent service "bar". This locator only knows about the "foo" service.');
+        }
+        $locator = $this->getServiceLocator([
+            'foo' => function () use (&$locator) { return $locator->get('bar'); },
+        ]);
+
+        $locator->get('foo');
+    }
+
+    public function testThrowsOnCircularReference()
+    {
+        $this->expectException(\Psr\Container\ContainerExceptionInterface::class);
+        $this->expectExceptionMessage('Circular reference detected for service "bar", path: "bar -> baz -> bar".');
+        $locator = $this->getServiceLocator([
+            'foo' => function () use (&$locator) { return $locator->get('bar'); },
+            'bar' => function () use (&$locator) { return $locator->get('baz'); },
+            'baz' => function () use (&$locator) { return $locator->get('bar'); },
+        ]);
+
+        $locator->get('foo');
+    }
+}
diff --git a/advancedcontentfilter/vendor/symfony/service-contracts/composer.json b/advancedcontentfilter/vendor/symfony/service-contracts/composer.json
new file mode 100644 (file)
index 0000000..f058637
--- /dev/null
@@ -0,0 +1,42 @@
+{
+    "name": "symfony/service-contracts",
+    "type": "library",
+    "description": "Generic abstractions related to writing services",
+    "keywords": ["abstractions", "contracts", "decoupling", "interfaces", "interoperability", "standards"],
+    "homepage": "https://symfony.com",
+    "license": "MIT",
+    "authors": [
+        {
+            "name": "Nicolas Grekas",
+            "email": "p@tchwork.com"
+        },
+        {
+            "name": "Symfony Community",
+            "homepage": "https://symfony.com/contributors"
+        }
+    ],
+    "require": {
+        "php": ">=7.2.5",
+        "psr/container": "^1.1",
+        "symfony/deprecation-contracts": "^2.1|^3"
+    },
+    "conflict": {
+        "ext-psr": "<1.1|>=2"
+    },
+    "suggest": {
+        "symfony/service-implementation": ""
+    },
+    "autoload": {
+        "psr-4": { "Symfony\\Contracts\\Service\\": "" }
+    },
+    "minimum-stability": "dev",
+    "extra": {
+        "branch-alias": {
+            "dev-main": "2.5-dev"
+        },
+        "thanks": {
+            "name": "symfony/contracts",
+            "url": "https://github.com/symfony/contracts"
+        }
+    }
+}
diff --git a/advancedcontentfilter/vendor/symfony/var-exporter/CHANGELOG.md b/advancedcontentfilter/vendor/symfony/var-exporter/CHANGELOG.md
new file mode 100644 (file)
index 0000000..3406c30
--- /dev/null
@@ -0,0 +1,12 @@
+CHANGELOG
+=========
+
+5.1.0
+-----
+
+ * added argument `array &$foundClasses` to `VarExporter::export()` to ease with preloading exported values
+
+4.2.0
+-----
+
+ * added the component
diff --git a/advancedcontentfilter/vendor/symfony/var-exporter/Exception/ClassNotFoundException.php b/advancedcontentfilter/vendor/symfony/var-exporter/Exception/ClassNotFoundException.php
new file mode 100644 (file)
index 0000000..379a765
--- /dev/null
@@ -0,0 +1,20 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien@symfony.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\VarExporter\Exception;
+
+class ClassNotFoundException extends \Exception implements ExceptionInterface
+{
+    public function __construct(string $class, ?\Throwable $previous = null)
+    {
+        parent::__construct(sprintf('Class "%s" not found.', $class), 0, $previous);
+    }
+}
diff --git a/advancedcontentfilter/vendor/symfony/var-exporter/Exception/ExceptionInterface.php b/advancedcontentfilter/vendor/symfony/var-exporter/Exception/ExceptionInterface.php
new file mode 100644 (file)
index 0000000..adfaed4
--- /dev/null
@@ -0,0 +1,16 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien@symfony.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\VarExporter\Exception;
+
+interface ExceptionInterface extends \Throwable
+{
+}
diff --git a/advancedcontentfilter/vendor/symfony/var-exporter/Exception/NotInstantiableTypeException.php b/advancedcontentfilter/vendor/symfony/var-exporter/Exception/NotInstantiableTypeException.php
new file mode 100644 (file)
index 0000000..b9ba225
--- /dev/null
@@ -0,0 +1,20 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien@symfony.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\VarExporter\Exception;
+
+class NotInstantiableTypeException extends \Exception implements ExceptionInterface
+{
+    public function __construct(string $type, ?\Throwable $previous = null)
+    {
+        parent::__construct(sprintf('Type "%s" is not instantiable.', $type), 0, $previous);
+    }
+}
diff --git a/advancedcontentfilter/vendor/symfony/var-exporter/Instantiator.php b/advancedcontentfilter/vendor/symfony/var-exporter/Instantiator.php
new file mode 100644 (file)
index 0000000..368c769
--- /dev/null
@@ -0,0 +1,92 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien@symfony.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\VarExporter;
+
+use Symfony\Component\VarExporter\Exception\ExceptionInterface;
+use Symfony\Component\VarExporter\Exception\NotInstantiableTypeException;
+use Symfony\Component\VarExporter\Internal\Hydrator;
+use Symfony\Component\VarExporter\Internal\Registry;
+
+/**
+ * A utility class to create objects without calling their constructor.
+ *
+ * @author Nicolas Grekas <p@tchwork.com>
+ */
+final class Instantiator
+{
+    /**
+     * Creates an object and sets its properties without calling its constructor nor any other methods.
+     *
+     * For example:
+     *
+     *     // creates an empty instance of Foo
+     *     Instantiator::instantiate(Foo::class);
+     *
+     *     // creates a Foo instance and sets one of its properties
+     *     Instantiator::instantiate(Foo::class, ['propertyName' => $propertyValue]);
+     *
+     *     // creates a Foo instance and sets a private property defined on its parent Bar class
+     *     Instantiator::instantiate(Foo::class, [], [
+     *         Bar::class => ['privateBarProperty' => $propertyValue],
+     *     ]);
+     *
+     * Instances of ArrayObject, ArrayIterator and SplObjectStorage can be created
+     * by using the special "\0" property name to define their internal value:
+     *
+     *     // creates an SplObjectStorage where $info1 is attached to $obj1, etc.
+     *     Instantiator::instantiate(SplObjectStorage::class, ["\0" => [$obj1, $info1, $obj2, $info2...]]);
+     *
+     *     // creates an ArrayObject populated with $inputArray
+     *     Instantiator::instantiate(ArrayObject::class, ["\0" => [$inputArray]]);
+     *
+     * @param string $class             The class of the instance to create
+     * @param array  $properties        The properties to set on the instance
+     * @param array  $privateProperties The private properties to set on the instance,
+     *                                  keyed by their declaring class
+     *
+     * @throws ExceptionInterface When the instance cannot be created
+     */
+    public static function instantiate(string $class, array $properties = [], array $privateProperties = []): object
+    {
+        $reflector = Registry::$reflectors[$class] ?? Registry::getClassReflector($class);
+
+        if (Registry::$cloneable[$class]) {
+            $wrappedInstance = [clone Registry::$prototypes[$class]];
+        } elseif (Registry::$instantiableWithoutConstructor[$class]) {
+            $wrappedInstance = [$reflector->newInstanceWithoutConstructor()];
+        } elseif (null === Registry::$prototypes[$class]) {
+            throw new NotInstantiableTypeException($class);
+        } elseif ($reflector->implementsInterface('Serializable') && (\PHP_VERSION_ID < 70400 || !method_exists($class, '__unserialize'))) {
+            $wrappedInstance = [unserialize('C:'.\strlen($class).':"'.$class.'":0:{}')];
+        } else {
+            $wrappedInstance = [unserialize('O:'.\strlen($class).':"'.$class.'":0:{}')];
+        }
+
+        if ($properties) {
+            $privateProperties[$class] = isset($privateProperties[$class]) ? $properties + $privateProperties[$class] : $properties;
+        }
+
+        foreach ($privateProperties as $class => $properties) {
+            if (!$properties) {
+                continue;
+            }
+            foreach ($properties as $name => $value) {
+                // because they're also used for "unserialization", hydrators
+                // deal with array of instances, so we need to wrap values
+                $properties[$name] = [$value];
+            }
+            (Hydrator::$hydrators[$class] ?? Hydrator::getHydrator($class))($properties, $wrappedInstance);
+        }
+
+        return $wrappedInstance[0];
+    }
+}
diff --git a/advancedcontentfilter/vendor/symfony/var-exporter/Internal/Exporter.php b/advancedcontentfilter/vendor/symfony/var-exporter/Internal/Exporter.php
new file mode 100644 (file)
index 0000000..51c29e4
--- /dev/null
@@ -0,0 +1,417 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien@symfony.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\VarExporter\Internal;
+
+use Symfony\Component\VarExporter\Exception\NotInstantiableTypeException;
+
+/**
+ * @author Nicolas Grekas <p@tchwork.com>
+ *
+ * @internal
+ */
+class Exporter
+{
+    /**
+     * Prepares an array of values for VarExporter.
+     *
+     * For performance this method is public and has no type-hints.
+     *
+     * @param array             &$values
+     * @param \SplObjectStorage $objectsPool
+     * @param array             &$refsPool
+     * @param int               &$objectsCount
+     * @param bool              &$valuesAreStatic
+     *
+     * @throws NotInstantiableTypeException When a value cannot be serialized
+     */
+    public static function prepare($values, $objectsPool, &$refsPool, &$objectsCount, &$valuesAreStatic): array
+    {
+        $refs = $values;
+        foreach ($values as $k => $value) {
+            if (\is_resource($value)) {
+                throw new NotInstantiableTypeException(get_resource_type($value).' resource');
+            }
+            $refs[$k] = $objectsPool;
+
+            if ($isRef = !$valueIsStatic = $values[$k] !== $objectsPool) {
+                $values[$k] = &$value; // Break hard references to make $values completely
+                unset($value);         // independent from the original structure
+                $refs[$k] = $value = $values[$k];
+                if ($value instanceof Reference && 0 > $value->id) {
+                    $valuesAreStatic = false;
+                    ++$value->count;
+                    continue;
+                }
+                $refsPool[] = [&$refs[$k], $value, &$value];
+                $refs[$k] = $values[$k] = new Reference(-\count($refsPool), $value);
+            }
+
+            if (\is_array($value)) {
+                if ($value) {
+                    $value = self::prepare($value, $objectsPool, $refsPool, $objectsCount, $valueIsStatic);
+                }
+                goto handle_value;
+            } elseif (!\is_object($value) || $value instanceof \UnitEnum) {
+                goto handle_value;
+            }
+
+            $valueIsStatic = false;
+            if (isset($objectsPool[$value])) {
+                ++$objectsCount;
+                $value = new Reference($objectsPool[$value][0]);
+                goto handle_value;
+            }
+
+            $class = \get_class($value);
+            $reflector = Registry::$reflectors[$class] ?? Registry::getClassReflector($class);
+            $properties = [];
+
+            if ($reflector->hasMethod('__serialize')) {
+                if (!$reflector->getMethod('__serialize')->isPublic()) {
+                    throw new \Error(sprintf('Call to %s method "%s::__serialize()".', $reflector->getMethod('__serialize')->isProtected() ? 'protected' : 'private', $class));
+                }
+
+                if (!\is_array($serializeProperties = $value->__serialize())) {
+                    throw new \TypeError($class.'::__serialize() must return an array');
+                }
+
+                if ($reflector->hasMethod('__unserialize')) {
+                    $properties = $serializeProperties;
+                } else {
+                    foreach ($serializeProperties as $n => $v) {
+                        $c = \PHP_VERSION_ID >= 80100 && $reflector->hasProperty($n) && ($p = $reflector->getProperty($n))->isReadOnly() ? $p->class : 'stdClass';
+                        $properties[$c][$n] = $v;
+                    }
+                }
+
+                goto prepare_value;
+            }
+
+            $sleep = null;
+            $proto = Registry::$prototypes[$class];
+
+            if (($value instanceof \ArrayIterator || $value instanceof \ArrayObject) && null !== $proto) {
+                // ArrayIterator and ArrayObject need special care because their "flags"
+                // option changes the behavior of the (array) casting operator.
+                [$arrayValue, $properties] = self::getArrayObjectProperties($value, $proto);
+
+                // populates Registry::$prototypes[$class] with a new instance
+                Registry::getClassReflector($class, Registry::$instantiableWithoutConstructor[$class], Registry::$cloneable[$class]);
+            } elseif ($value instanceof \SplObjectStorage && Registry::$cloneable[$class] && null !== $proto) {
+                // By implementing Serializable, SplObjectStorage breaks
+                // internal references; let's deal with it on our own.
+                foreach (clone $value as $v) {
+                    $properties[] = $v;
+                    $properties[] = $value[$v];
+                }
+                $properties = ['SplObjectStorage' => ["\0" => $properties]];
+                $arrayValue = (array) $value;
+            } elseif ($value instanceof \Serializable
+                || $value instanceof \__PHP_Incomplete_Class
+                || \PHP_VERSION_ID < 80200 && $value instanceof \DatePeriod
+            ) {
+                ++$objectsCount;
+                $objectsPool[$value] = [$id = \count($objectsPool), serialize($value), [], 0];
+                $value = new Reference($id);
+                goto handle_value;
+            } else {
+                if (method_exists($class, '__sleep')) {
+                    if (!\is_array($sleep = $value->__sleep())) {
+                        trigger_error('serialize(): __sleep should return an array only containing the names of instance-variables to serialize', \E_USER_NOTICE);
+                        $value = null;
+                        goto handle_value;
+                    }
+                    $sleep = array_flip($sleep);
+                }
+
+                $arrayValue = (array) $value;
+            }
+
+            $proto = (array) $proto;
+
+            foreach ($arrayValue as $name => $v) {
+                $i = 0;
+                $n = (string) $name;
+                if ('' === $n || "\0" !== $n[0]) {
+                    $c = \PHP_VERSION_ID >= 80100 && $reflector->hasProperty($n) && ($p = $reflector->getProperty($n))->isReadOnly() ? $p->class : 'stdClass';
+                } elseif ('*' === $n[1]) {
+                    $n = substr($n, 3);
+                    $c = $reflector->getProperty($n)->class;
+                    if ('Error' === $c) {
+                        $c = 'TypeError';
+                    } elseif ('Exception' === $c) {
+                        $c = 'ErrorException';
+                    }
+                } else {
+                    $i = strpos($n, "\0", 2);
+                    $c = substr($n, 1, $i - 1);
+                    $n = substr($n, 1 + $i);
+                }
+                if (null !== $sleep) {
+                    if (!isset($sleep[$name]) && (!isset($sleep[$n]) || ($i && $c !== $class))) {
+                        unset($arrayValue[$name]);
+                        continue;
+                    }
+                    unset($sleep[$name], $sleep[$n]);
+                }
+                if (!\array_key_exists($name, $proto) || $proto[$name] !== $v || "\x00Error\x00trace" === $name || "\x00Exception\x00trace" === $name) {
+                    $properties[$c][$n] = $v;
+                }
+            }
+            if ($sleep) {
+                foreach ($sleep as $n => $v) {
+                    trigger_error(sprintf('serialize(): "%s" returned as member variable from __sleep() but does not exist', $n), \E_USER_NOTICE);
+                }
+            }
+            if (method_exists($class, '__unserialize')) {
+                $properties = $arrayValue;
+            }
+
+            prepare_value:
+            $objectsPool[$value] = [$id = \count($objectsPool)];
+            $properties = self::prepare($properties, $objectsPool, $refsPool, $objectsCount, $valueIsStatic);
+            ++$objectsCount;
+            $objectsPool[$value] = [$id, $class, $properties, method_exists($class, '__unserialize') ? -$objectsCount : (method_exists($class, '__wakeup') ? $objectsCount : 0)];
+
+            $value = new Reference($id);
+
+            handle_value:
+            if ($isRef) {
+                unset($value); // Break the hard reference created above
+            } elseif (!$valueIsStatic) {
+                $values[$k] = $value;
+            }
+            $valuesAreStatic = $valueIsStatic && $valuesAreStatic;
+        }
+
+        return $values;
+    }
+
+    public static function export($value, string $indent = '')
+    {
+        switch (true) {
+            case \is_int($value) || \is_float($value): return var_export($value, true);
+            case [] === $value: return '[]';
+            case false === $value: return 'false';
+            case true === $value: return 'true';
+            case null === $value: return 'null';
+            case '' === $value: return "''";
+            case $value instanceof \UnitEnum: return '\\'.ltrim(var_export($value, true), '\\');
+        }
+
+        if ($value instanceof Reference) {
+            if (0 <= $value->id) {
+                return '$o['.$value->id.']';
+            }
+            if (!$value->count) {
+                return self::export($value->value, $indent);
+            }
+            $value = -$value->id;
+
+            return '&$r['.$value.']';
+        }
+        $subIndent = $indent.'    ';
+
+        if (\is_string($value)) {
+            $code = sprintf("'%s'", addcslashes($value, "'\\"));
+
+            $code = preg_replace_callback("/((?:[\\0\\r\\n]|\u{202A}|\u{202B}|\u{202D}|\u{202E}|\u{2066}|\u{2067}|\u{2068}|\u{202C}|\u{2069})++)(.)/", function ($m) use ($subIndent) {
+                $m[1] = sprintf('\'."%s".\'', str_replace(
+                    ["\0", "\r", "\n", "\u{202A}", "\u{202B}", "\u{202D}", "\u{202E}", "\u{2066}", "\u{2067}", "\u{2068}", "\u{202C}", "\u{2069}", '\n\\'],
+                    ['\0', '\r', '\n', '\u{202A}', '\u{202B}', '\u{202D}', '\u{202E}', '\u{2066}', '\u{2067}', '\u{2068}', '\u{202C}', '\u{2069}', '\n"'."\n".$subIndent.'."\\'],
+                    $m[1]
+                ));
+
+                if ("'" === $m[2]) {
+                    return substr($m[1], 0, -2);
+                }
+
+                if ('n".\'' === substr($m[1], -4)) {
+                    return substr_replace($m[1], "\n".$subIndent.".'".$m[2], -2);
+                }
+
+                return $m[1].$m[2];
+            }, $code, -1, $count);
+
+            if ($count && str_starts_with($code, "''.")) {
+                $code = substr($code, 3);
+            }
+
+            return $code;
+        }
+
+        if (\is_array($value)) {
+            $j = -1;
+            $code = '';
+            foreach ($value as $k => $v) {
+                $code .= $subIndent;
+                if (!\is_int($k) || 1 !== $k - $j) {
+                    $code .= self::export($k, $subIndent).' => ';
+                }
+                if (\is_int($k) && $k > $j) {
+                    $j = $k;
+                }
+                $code .= self::export($v, $subIndent).",\n";
+            }
+
+            return "[\n".$code.$indent.']';
+        }
+
+        if ($value instanceof Values) {
+            $code = $subIndent."\$r = [],\n";
+            foreach ($value->values as $k => $v) {
+                $code .= $subIndent.'$r['.$k.'] = '.self::export($v, $subIndent).",\n";
+            }
+
+            return "[\n".$code.$indent.']';
+        }
+
+        if ($value instanceof Registry) {
+            return self::exportRegistry($value, $indent, $subIndent);
+        }
+
+        if ($value instanceof Hydrator) {
+            return self::exportHydrator($value, $indent, $subIndent);
+        }
+
+        throw new \UnexpectedValueException(sprintf('Cannot export value of type "%s".', get_debug_type($value)));
+    }
+
+    private static function exportRegistry(Registry $value, string $indent, string $subIndent): string
+    {
+        $code = '';
+        $serializables = [];
+        $seen = [];
+        $prototypesAccess = 0;
+        $factoriesAccess = 0;
+        $r = '\\'.Registry::class;
+        $j = -1;
+
+        foreach ($value->classes as $k => $class) {
+            if (':' === ($class[1] ?? null)) {
+                $serializables[$k] = $class;
+                continue;
+            }
+            if (!Registry::$instantiableWithoutConstructor[$class]) {
+                if (is_subclass_of($class, 'Serializable') && !method_exists($class, '__unserialize')) {
+                    $serializables[$k] = 'C:'.\strlen($class).':"'.$class.'":0:{}';
+                } else {
+                    $serializables[$k] = 'O:'.\strlen($class).':"'.$class.'":0:{}';
+                }
+                if (is_subclass_of($class, 'Throwable')) {
+                    $eol = is_subclass_of($class, 'Error') ? "\0Error\0" : "\0Exception\0";
+                    $serializables[$k] = substr_replace($serializables[$k], '1:{s:'.(5 + \strlen($eol)).':"'.$eol.'trace";a:0:{}}', -4);
+                }
+                continue;
+            }
+            $code .= $subIndent.(1 !== $k - $j ? $k.' => ' : '');
+            $j = $k;
+            $eol = ",\n";
+            $c = '['.self::export($class).']';
+
+            if ($seen[$class] ?? false) {
+                if (Registry::$cloneable[$class]) {
+                    ++$prototypesAccess;
+                    $code .= 'clone $p'.$c;
+                } else {
+                    ++$factoriesAccess;
+                    $code .= '$f'.$c.'()';
+                }
+            } else {
+                $seen[$class] = true;
+                if (Registry::$cloneable[$class]) {
+                    $code .= 'clone ('.($prototypesAccess++ ? '$p' : '($p = &'.$r.'::$prototypes)').$c.' ?? '.$r.'::p';
+                } else {
+                    $code .= '('.($factoriesAccess++ ? '$f' : '($f = &'.$r.'::$factories)').$c.' ?? '.$r.'::f';
+                    $eol = '()'.$eol;
+                }
+                $code .= '('.substr($c, 1, -1).'))';
+            }
+            $code .= $eol;
+        }
+
+        if (1 === $prototypesAccess) {
+            $code = str_replace('($p = &'.$r.'::$prototypes)', $r.'::$prototypes', $code);
+        }
+        if (1 === $factoriesAccess) {
+            $code = str_replace('($f = &'.$r.'::$factories)', $r.'::$factories', $code);
+        }
+        if ('' !== $code) {
+            $code = "\n".$code.$indent;
+        }
+
+        if ($serializables) {
+            $code = $r.'::unserialize(['.$code.'], '.self::export($serializables, $indent).')';
+        } else {
+            $code = '['.$code.']';
+        }
+
+        return '$o = '.$code;
+    }
+
+    private static function exportHydrator(Hydrator $value, string $indent, string $subIndent): string
+    {
+        $code = '';
+        foreach ($value->properties as $class => $properties) {
+            $code .= $subIndent.'    '.self::export($class).' => '.self::export($properties, $subIndent.'    ').",\n";
+        }
+
+        $code = [
+            self::export($value->registry, $subIndent),
+            self::export($value->values, $subIndent),
+            '' !== $code ? "[\n".$code.$subIndent.']' : '[]',
+            self::export($value->value, $subIndent),
+            self::export($value->wakeups, $subIndent),
+        ];
+
+        return '\\'.\get_class($value)."::hydrate(\n".$subIndent.implode(",\n".$subIndent, $code)."\n".$indent.')';
+    }
+
+    /**
+     * @param \ArrayIterator|\ArrayObject $value
+     * @param \ArrayIterator|\ArrayObject $proto
+     */
+    private static function getArrayObjectProperties($value, $proto): array
+    {
+        $reflector = $value instanceof \ArrayIterator ? 'ArrayIterator' : 'ArrayObject';
+        $reflector = Registry::$reflectors[$reflector] ?? Registry::getClassReflector($reflector);
+
+        $properties = [
+            $arrayValue = (array) $value,
+            $reflector->getMethod('getFlags')->invoke($value),
+            $value instanceof \ArrayObject ? $reflector->getMethod('getIteratorClass')->invoke($value) : 'ArrayIterator',
+        ];
+
+        $reflector = $reflector->getMethod('setFlags');
+        $reflector->invoke($proto, \ArrayObject::STD_PROP_LIST);
+
+        if ($properties[1] & \ArrayObject::STD_PROP_LIST) {
+            $reflector->invoke($value, 0);
+            $properties[0] = (array) $value;
+        } else {
+            $reflector->invoke($value, \ArrayObject::STD_PROP_LIST);
+            $arrayValue = (array) $value;
+        }
+        $reflector->invoke($value, $properties[1]);
+
+        if ([[], 0, 'ArrayIterator'] === $properties) {
+            $properties = [];
+        } else {
+            if ('ArrayIterator' === $properties[2]) {
+                unset($properties[2]);
+            }
+            $properties = [$reflector->class => ["\0" => $properties]];
+        }
+
+        return [$arrayValue, $properties];
+    }
+}
diff --git a/advancedcontentfilter/vendor/symfony/var-exporter/Internal/Hydrator.php b/advancedcontentfilter/vendor/symfony/var-exporter/Internal/Hydrator.php
new file mode 100644 (file)
index 0000000..5ed6bdc
--- /dev/null
@@ -0,0 +1,152 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien@symfony.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\VarExporter\Internal;
+
+use Symfony\Component\VarExporter\Exception\ClassNotFoundException;
+
+/**
+ * @author Nicolas Grekas <p@tchwork.com>
+ *
+ * @internal
+ */
+class Hydrator
+{
+    public static $hydrators = [];
+
+    public $registry;
+    public $values;
+    public $properties;
+    public $value;
+    public $wakeups;
+
+    public function __construct(?Registry $registry, ?Values $values, array $properties, $value, array $wakeups)
+    {
+        $this->registry = $registry;
+        $this->values = $values;
+        $this->properties = $properties;
+        $this->value = $value;
+        $this->wakeups = $wakeups;
+    }
+
+    public static function hydrate($objects, $values, $properties, $value, $wakeups)
+    {
+        foreach ($properties as $class => $vars) {
+            (self::$hydrators[$class] ?? self::getHydrator($class))($vars, $objects);
+        }
+        foreach ($wakeups as $k => $v) {
+            if (\is_array($v)) {
+                $objects[-$k]->__unserialize($v);
+            } else {
+                $objects[$v]->__wakeup();
+            }
+        }
+
+        return $value;
+    }
+
+    public static function getHydrator($class)
+    {
+        switch ($class) {
+            case 'stdClass':
+                return self::$hydrators[$class] = static function ($properties, $objects) {
+                    foreach ($properties as $name => $values) {
+                        foreach ($values as $i => $v) {
+                            $objects[$i]->$name = $v;
+                        }
+                    }
+                };
+
+            case 'ErrorException':
+                return self::$hydrators[$class] = (self::$hydrators['stdClass'] ?? self::getHydrator('stdClass'))->bindTo(null, new class() extends \ErrorException {
+                });
+
+            case 'TypeError':
+                return self::$hydrators[$class] = (self::$hydrators['stdClass'] ?? self::getHydrator('stdClass'))->bindTo(null, new class() extends \Error {
+                });
+
+            case 'SplObjectStorage':
+                return self::$hydrators[$class] = static function ($properties, $objects) {
+                    foreach ($properties as $name => $values) {
+                        if ("\0" === $name) {
+                            foreach ($values as $i => $v) {
+                                for ($j = 0; $j < \count($v); ++$j) {
+                                    $objects[$i]->attach($v[$j], $v[++$j]);
+                                }
+                            }
+                            continue;
+                        }
+                        foreach ($values as $i => $v) {
+                            $objects[$i]->$name = $v;
+                        }
+                    }
+                };
+        }
+
+        if (!class_exists($class) && !interface_exists($class, false) && !trait_exists($class, false)) {
+            throw new ClassNotFoundException($class);
+        }
+        $classReflector = new \ReflectionClass($class);
+
+        switch ($class) {
+            case 'ArrayIterator':
+            case 'ArrayObject':
+                $constructor = \Closure::fromCallable([$classReflector->getConstructor(), 'invokeArgs']);
+
+                return self::$hydrators[$class] = static function ($properties, $objects) use ($constructor) {
+                    foreach ($properties as $name => $values) {
+                        if ("\0" !== $name) {
+                            foreach ($values as $i => $v) {
+                                $objects[$i]->$name = $v;
+                            }
+                        }
+                    }
+                    foreach ($properties["\0"] ?? [] as $i => $v) {
+                        $constructor($objects[$i], $v);
+                    }
+                };
+        }
+
+        if (!$classReflector->isInternal()) {
+            return self::$hydrators[$class] = (self::$hydrators['stdClass'] ?? self::getHydrator('stdClass'))->bindTo(null, $class);
+        }
+
+        if ($classReflector->name !== $class) {
+            return self::$hydrators[$classReflector->name] ?? self::getHydrator($classReflector->name);
+        }
+
+        $propertySetters = [];
+        foreach ($classReflector->getProperties() as $propertyReflector) {
+            if (!$propertyReflector->isStatic()) {
+                $propertyReflector->setAccessible(true);
+                $propertySetters[$propertyReflector->name] = \Closure::fromCallable([$propertyReflector, 'setValue']);
+            }
+        }
+
+        if (!$propertySetters) {
+            return self::$hydrators[$class] = self::$hydrators['stdClass'] ?? self::getHydrator('stdClass');
+        }
+
+        return self::$hydrators[$class] = static function ($properties, $objects) use ($propertySetters) {
+            foreach ($properties as $name => $values) {
+                if ($setValue = $propertySetters[$name] ?? null) {
+                    foreach ($values as $i => $v) {
+                        $setValue($objects[$i], $v);
+                    }
+                    continue;
+                }
+                foreach ($values as $i => $v) {
+                    $objects[$i]->$name = $v;
+                }
+            }
+        };
+    }
+}
diff --git a/advancedcontentfilter/vendor/symfony/var-exporter/Internal/Reference.php b/advancedcontentfilter/vendor/symfony/var-exporter/Internal/Reference.php
new file mode 100644 (file)
index 0000000..e371c07
--- /dev/null
@@ -0,0 +1,30 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien@symfony.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\VarExporter\Internal;
+
+/**
+ * @author Nicolas Grekas <p@tchwork.com>
+ *
+ * @internal
+ */
+class Reference
+{
+    public $id;
+    public $value;
+    public $count = 0;
+
+    public function __construct(int $id, $value = null)
+    {
+        $this->id = $id;
+        $this->value = $value;
+    }
+}
diff --git a/advancedcontentfilter/vendor/symfony/var-exporter/Internal/Registry.php b/advancedcontentfilter/vendor/symfony/var-exporter/Internal/Registry.php
new file mode 100644 (file)
index 0000000..24b77b9
--- /dev/null
@@ -0,0 +1,146 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien@symfony.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\VarExporter\Internal;
+
+use Symfony\Component\VarExporter\Exception\ClassNotFoundException;
+use Symfony\Component\VarExporter\Exception\NotInstantiableTypeException;
+
+/**
+ * @author Nicolas Grekas <p@tchwork.com>
+ *
+ * @internal
+ */
+class Registry
+{
+    public static $reflectors = [];
+    public static $prototypes = [];
+    public static $factories = [];
+    public static $cloneable = [];
+    public static $instantiableWithoutConstructor = [];
+
+    public $classes = [];
+
+    public function __construct(array $classes)
+    {
+        $this->classes = $classes;
+    }
+
+    public static function unserialize($objects, $serializables)
+    {
+        $unserializeCallback = ini_set('unserialize_callback_func', __CLASS__.'::getClassReflector');
+
+        try {
+            foreach ($serializables as $k => $v) {
+                $objects[$k] = unserialize($v);
+            }
+        } finally {
+            ini_set('unserialize_callback_func', $unserializeCallback);
+        }
+
+        return $objects;
+    }
+
+    public static function p($class)
+    {
+        self::getClassReflector($class, true, true);
+
+        return self::$prototypes[$class];
+    }
+
+    public static function f($class)
+    {
+        $reflector = self::$reflectors[$class] ?? self::getClassReflector($class, true, false);
+
+        return self::$factories[$class] = \Closure::fromCallable([$reflector, 'newInstanceWithoutConstructor']);
+    }
+
+    public static function getClassReflector($class, $instantiableWithoutConstructor = false, $cloneable = null)
+    {
+        if (!($isClass = class_exists($class)) && !interface_exists($class, false) && !trait_exists($class, false)) {
+            throw new ClassNotFoundException($class);
+        }
+        $reflector = new \ReflectionClass($class);
+
+        if ($instantiableWithoutConstructor) {
+            $proto = $reflector->newInstanceWithoutConstructor();
+        } elseif (!$isClass || $reflector->isAbstract()) {
+            throw new NotInstantiableTypeException($class);
+        } elseif ($reflector->name !== $class) {
+            $reflector = self::$reflectors[$name = $reflector->name] ?? self::getClassReflector($name, false, $cloneable);
+            self::$cloneable[$class] = self::$cloneable[$name];
+            self::$instantiableWithoutConstructor[$class] = self::$instantiableWithoutConstructor[$name];
+            self::$prototypes[$class] = self::$prototypes[$name];
+
+            return self::$reflectors[$class] = $reflector;
+        } else {
+            try {
+                $proto = $reflector->newInstanceWithoutConstructor();
+                $instantiableWithoutConstructor = true;
+            } catch (\ReflectionException $e) {
+                $proto = $reflector->implementsInterface('Serializable') && !method_exists($class, '__unserialize') ? 'C:' : 'O:';
+                if ('C:' === $proto && !$reflector->getMethod('unserialize')->isInternal()) {
+                    $proto = null;
+                } else {
+                    try {
+                        $proto = @unserialize($proto.\strlen($class).':"'.$class.'":0:{}');
+                    } catch (\Exception $e) {
+                        if (__FILE__ !== $e->getFile()) {
+                            throw $e;
+                        }
+                        throw new NotInstantiableTypeException($class, $e);
+                    }
+                    if (false === $proto) {
+                        throw new NotInstantiableTypeException($class);
+                    }
+                }
+            }
+            if (null !== $proto && !$proto instanceof \Throwable && !$proto instanceof \Serializable && !method_exists($class, '__sleep') && (\PHP_VERSION_ID < 70400 || !method_exists($class, '__serialize'))) {
+                try {
+                    serialize($proto);
+                } catch (\Exception $e) {
+                    throw new NotInstantiableTypeException($class, $e);
+                }
+            }
+        }
+
+        if (null === $cloneable) {
+            if (($proto instanceof \Reflector || $proto instanceof \ReflectionGenerator || $proto instanceof \ReflectionType || $proto instanceof \IteratorIterator || $proto instanceof \RecursiveIteratorIterator) && (!$proto instanceof \Serializable && !method_exists($proto, '__wakeup') && (\PHP_VERSION_ID < 70400 || !method_exists($class, '__unserialize')))) {
+                throw new NotInstantiableTypeException($class);
+            }
+
+            $cloneable = $reflector->isCloneable() && !$reflector->hasMethod('__clone');
+        }
+
+        self::$cloneable[$class] = $cloneable;
+        self::$instantiableWithoutConstructor[$class] = $instantiableWithoutConstructor;
+        self::$prototypes[$class] = $proto;
+
+        if ($proto instanceof \Throwable) {
+            static $setTrace;
+
+            if (null === $setTrace) {
+                $setTrace = [
+                    new \ReflectionProperty(\Error::class, 'trace'),
+                    new \ReflectionProperty(\Exception::class, 'trace'),
+                ];
+                $setTrace[0]->setAccessible(true);
+                $setTrace[1]->setAccessible(true);
+                $setTrace[0] = \Closure::fromCallable([$setTrace[0], 'setValue']);
+                $setTrace[1] = \Closure::fromCallable([$setTrace[1], 'setValue']);
+            }
+
+            $setTrace[$proto instanceof \Exception]($proto, []);
+        }
+
+        return self::$reflectors[$class] = $reflector;
+    }
+}
diff --git a/advancedcontentfilter/vendor/symfony/var-exporter/Internal/Values.php b/advancedcontentfilter/vendor/symfony/var-exporter/Internal/Values.php
new file mode 100644 (file)
index 0000000..21ae04e
--- /dev/null
@@ -0,0 +1,27 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien@symfony.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\VarExporter\Internal;
+
+/**
+ * @author Nicolas Grekas <p@tchwork.com>
+ *
+ * @internal
+ */
+class Values
+{
+    public $values;
+
+    public function __construct(array $values)
+    {
+        $this->values = $values;
+    }
+}
diff --git a/advancedcontentfilter/vendor/symfony/var-exporter/LICENSE b/advancedcontentfilter/vendor/symfony/var-exporter/LICENSE
new file mode 100644 (file)
index 0000000..7536cae
--- /dev/null
@@ -0,0 +1,19 @@
+Copyright (c) 2018-present Fabien Potencier
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is furnished
+to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
diff --git a/advancedcontentfilter/vendor/symfony/var-exporter/README.md b/advancedcontentfilter/vendor/symfony/var-exporter/README.md
new file mode 100644 (file)
index 0000000..a34e4c2
--- /dev/null
@@ -0,0 +1,38 @@
+VarExporter Component
+=====================
+
+The VarExporter component allows exporting any serializable PHP data structure to
+plain PHP code. While doing so, it preserves all the semantics associated with
+the serialization mechanism of PHP (`__wakeup`, `__sleep`, `Serializable`,
+`__serialize`, `__unserialize`).
+
+It also provides an instantiator that allows creating and populating objects
+without calling their constructor nor any other methods.
+
+The reason to use this component *vs* `serialize()` or
+[igbinary](https://github.com/igbinary/igbinary) is performance: thanks to
+OPcache, the resulting code is significantly faster and more memory efficient
+than using `unserialize()` or `igbinary_unserialize()`.
+
+Unlike `var_export()`, this works on any serializable PHP value.
+
+It also provides a few improvements over `var_export()`/`serialize()`:
+
+ * the output is PSR-2 compatible;
+ * the output can be re-indented without messing up with `\r` or `\n` in the data
+ * missing classes throw a `ClassNotFoundException` instead of being unserialized to
+   `PHP_Incomplete_Class` objects;
+ * references involving `SplObjectStorage`, `ArrayObject` or `ArrayIterator`
+   instances are preserved;
+ * `Reflection*`, `IteratorIterator` and `RecursiveIteratorIterator` classes
+   throw an exception when being serialized (their unserialized version is broken
+   anyway, see https://bugs.php.net/76737).
+
+Resources
+---------
+
+ * [Documentation](https://symfony.com/doc/current/components/var_exporter.html)
+ * [Contributing](https://symfony.com/doc/current/contributing/index.html)
+ * [Report issues](https://github.com/symfony/symfony/issues) and
+   [send Pull Requests](https://github.com/symfony/symfony/pulls)
+   in the [main Symfony repository](https://github.com/symfony/symfony)
diff --git a/advancedcontentfilter/vendor/symfony/var-exporter/VarExporter.php b/advancedcontentfilter/vendor/symfony/var-exporter/VarExporter.php
new file mode 100644 (file)
index 0000000..d4c0809
--- /dev/null
@@ -0,0 +1,115 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien@symfony.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\VarExporter;
+
+use Symfony\Component\VarExporter\Exception\ExceptionInterface;
+use Symfony\Component\VarExporter\Internal\Exporter;
+use Symfony\Component\VarExporter\Internal\Hydrator;
+use Symfony\Component\VarExporter\Internal\Registry;
+use Symfony\Component\VarExporter\Internal\Values;
+
+/**
+ * Exports serializable PHP values to PHP code.
+ *
+ * VarExporter allows serializing PHP data structures to plain PHP code (like var_export())
+ * while preserving all the semantics associated with serialize() (unlike var_export()).
+ *
+ * By leveraging OPcache, the generated PHP code is faster than doing the same with unserialize().
+ *
+ * @author Nicolas Grekas <p@tchwork.com>
+ */
+final class VarExporter
+{
+    /**
+     * Exports a serializable PHP value to PHP code.
+     *
+     * @param mixed $value          The value to export
+     * @param bool  &$isStaticValue Set to true after execution if the provided value is static, false otherwise
+     * @param array &$foundClasses  Classes found in the value are added to this list as both keys and values
+     *
+     * @throws ExceptionInterface When the provided value cannot be serialized
+     */
+    public static function export($value, ?bool &$isStaticValue = null, array &$foundClasses = []): string
+    {
+        $isStaticValue = true;
+
+        if (!\is_object($value) && !(\is_array($value) && $value) && !\is_resource($value) || $value instanceof \UnitEnum) {
+            return Exporter::export($value);
+        }
+
+        $objectsPool = new \SplObjectStorage();
+        $refsPool = [];
+        $objectsCount = 0;
+
+        try {
+            $value = Exporter::prepare([$value], $objectsPool, $refsPool, $objectsCount, $isStaticValue)[0];
+        } finally {
+            $references = [];
+            foreach ($refsPool as $i => $v) {
+                if ($v[0]->count) {
+                    $references[1 + $i] = $v[2];
+                }
+                $v[0] = $v[1];
+            }
+        }
+
+        if ($isStaticValue) {
+            return Exporter::export($value);
+        }
+
+        $classes = [];
+        $values = [];
+        $states = [];
+        foreach ($objectsPool as $i => $v) {
+            [, $class, $values[], $wakeup] = $objectsPool[$v];
+            $foundClasses[$class] = $classes[] = $class;
+
+            if (0 < $wakeup) {
+                $states[$wakeup] = $i;
+            } elseif (0 > $wakeup) {
+                $states[-$wakeup] = [$i, array_pop($values)];
+                $values[] = [];
+            }
+        }
+        ksort($states);
+
+        $wakeups = [null];
+        foreach ($states as $v) {
+            if (\is_array($v)) {
+                $wakeups[-$v[0]] = $v[1];
+            } else {
+                $wakeups[] = $v;
+            }
+        }
+
+        if (null === $wakeups[0]) {
+            unset($wakeups[0]);
+        }
+
+        $properties = [];
+        foreach ($values as $i => $vars) {
+            foreach ($vars as $class => $values) {
+                foreach ($values as $name => $v) {
+                    $properties[$class][$name][$i] = $v;
+                }
+            }
+        }
+
+        if ($classes || $references) {
+            $value = new Hydrator(new Registry($classes), $references ? new Values($references) : null, $properties, $value, $wakeups);
+        } else {
+            $isStaticValue = true;
+        }
+
+        return Exporter::export($value);
+    }
+}
diff --git a/advancedcontentfilter/vendor/symfony/var-exporter/composer.json b/advancedcontentfilter/vendor/symfony/var-exporter/composer.json
new file mode 100644 (file)
index 0000000..29d4901
--- /dev/null
@@ -0,0 +1,32 @@
+{
+    "name": "symfony/var-exporter",
+    "type": "library",
+    "description": "Allows exporting any serializable PHP data structure to plain PHP code",
+    "keywords": ["export", "serialize", "instantiate", "hydrate", "construct", "clone"],
+    "homepage": "https://symfony.com",
+    "license": "MIT",
+    "authors": [
+        {
+            "name": "Nicolas Grekas",
+            "email": "p@tchwork.com"
+        },
+        {
+            "name": "Symfony Community",
+            "homepage": "https://symfony.com/contributors"
+        }
+    ],
+    "require": {
+        "php": ">=7.2.5",
+        "symfony/polyfill-php80": "^1.16"
+    },
+    "require-dev": {
+        "symfony/var-dumper": "^4.4.9|^5.0.9|^6.0"
+    },
+    "autoload": {
+        "psr-4": { "Symfony\\Component\\VarExporter\\": "" },
+        "exclude-from-classmap": [
+            "/Tests/"
+        ]
+    },
+    "minimum-stability": "dev"
+}