From 2fbcaa3a681d38c17270a867ecab8b07e6280d1d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maximilian=20B=C3=B6sing?= <2189546+boesing@users.noreply.github.com> Date: Sat, 26 Aug 2023 22:29:21 +0200 Subject: [PATCH 1/3] qa: remove dependency on real storage adapters MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This also removes benchmarks which are so available in each adapter repository and thus were redundant. Even tho, we are now unable to directly see impact on performance when changing `AbstractAdapter`, the adapters themselves keep track on performance due to renovate updating locks permanently. Longterm, the `AbstractAdapter` will most likely be removed in favor of cache backend specific features explicitly implemented. The `StorageInterface` will extend the PSR interfaces and requires the adapters to serve these interfaces in their own way. Therefore, removing benchmarks might be a good thing since the `StorageInterface` is meant to be feature complete. With #130, some methods might be removed from the `StorageInterface` but extending that interface is not planned. Signed-off-by: Maximilian Bösing <2189546+boesing@users.noreply.github.com> --- .gitattributes | 1 + .laminas-ci.json | 7 - .../install-apcu-extension-via-pecl.sh | 14 - .laminas-ci/pre-install.sh | 2 - .../AbstractCommonStorageAdapterBench.php | 353 ------ benchmark/FilesystemStorageAdapterBench.php | 74 -- benchmark/MemoryStorageAdapterBench.php | 23 - composer.json | 19 +- composer.lock | 1090 ++--------------- dev-implementation/README.md | 4 + dev-implementation/VoidAdapter.php | 36 + dev-implementation/composer.json | 12 + phpbench.json | 5 - phpcs.xml | 2 +- psalm-baseline.xml | 103 +- psalm.xml | 1 + src/Storage/Adapter/AbstractAdapter.php | 2 +- .../AbstractCommonStoragePatternTest.php | 6 +- test/Pattern/CallbackCacheTest.php | 100 +- test/Pattern/ObjectCacheTest.php | 75 +- test/Pattern/OutputCacheTest.php | 32 +- test/Pattern/TestAsset/TestCallbackCache.php | 6 +- .../CacheItemPoolIntegrationTest.php | 22 - .../SimpleCacheIntegrationTest.php | 22 - .../AdapterPluginManagerTypes.php | 6 +- test/Storage/CapabilitiesTest.php | 6 +- 26 files changed, 304 insertions(+), 1719 deletions(-) delete mode 100755 .laminas-ci/install-apcu-extension-via-pecl.sh delete mode 100644 benchmark/AbstractCommonStorageAdapterBench.php delete mode 100644 benchmark/FilesystemStorageAdapterBench.php delete mode 100644 benchmark/MemoryStorageAdapterBench.php create mode 100644 dev-implementation/README.md create mode 100644 dev-implementation/VoidAdapter.php create mode 100644 dev-implementation/composer.json delete mode 100644 phpbench.json delete mode 100644 test/Psr/CacheItemPool/CacheItemPoolIntegrationTest.php delete mode 100644 test/Psr/SimpleCache/SimpleCacheIntegrationTest.php diff --git a/.gitattributes b/.gitattributes index fe524d08..568685da 100644 --- a/.gitattributes +++ b/.gitattributes @@ -5,6 +5,7 @@ /.gitignore export-ignore /.travis.yml export-ignore /benchmark/ export-ignore +/dev-implementation/ export-ignore /docs/ export-ignore /mkdocs.yml export-ignore /phpbench.json export-ignore diff --git a/.laminas-ci.json b/.laminas-ci.json index 38b147d9..18707e20 100644 --- a/.laminas-ci.json +++ b/.laminas-ci.json @@ -1,10 +1,3 @@ { - "extensions": [ - "apcu" - ], - "ini": [ - "apc.enabled=1", - "apc.enable_cli=1" - ], "backwardCompatibilityCheck": true } diff --git a/.laminas-ci/install-apcu-extension-via-pecl.sh b/.laminas-ci/install-apcu-extension-via-pecl.sh deleted file mode 100755 index 0f2e221f..00000000 --- a/.laminas-ci/install-apcu-extension-via-pecl.sh +++ /dev/null @@ -1,14 +0,0 @@ -#!/bin/bash - -PHP_VERSION="$1" - -if ! [[ "${PHP_VERSION}" =~ 8\.2 ]]; then - echo "APCu is only installed from pecl for PHP 8.2, ${PHP_VERSION} detected." - exit 0; -fi - -set +e - -pecl install --configureoptions 'enable-apcu-debug="no"' apcu -echo "extension=apcu.so" > /etc/php/${PHP_VERSION}/mods-available/apcu.ini -phpenmod -v ${PHP} -s cli apcu diff --git a/.laminas-ci/pre-install.sh b/.laminas-ci/pre-install.sh index 73c63187..25ed8129 100755 --- a/.laminas-ci/pre-install.sh +++ b/.laminas-ci/pre-install.sh @@ -14,5 +14,3 @@ if [ ! -z "$GITHUB_BASE_REF" ] && [[ "$GITHUB_BASE_REF" =~ ^[0-9]+\.[0-9] ]]; th export COMPOSER_ROOT_VERISON="${MAJOR_OF_TARGET_BRANCH}.${MINOR_OF_TARGET_BRANCH}.99" echo "Exported COMPOSER_ROOT_VERISON as ${COMPOSER_ROOT_VERISON}" fi - -${WORKING_DIRECTORY}/.laminas-ci/install-apcu-extension-via-pecl.sh "${PHP_VERSION}" || exit 1 diff --git a/benchmark/AbstractCommonStorageAdapterBench.php b/benchmark/AbstractCommonStorageAdapterBench.php deleted file mode 100644 index 27f70dc1..00000000 --- a/benchmark/AbstractCommonStorageAdapterBench.php +++ /dev/null @@ -1,353 +0,0 @@ - - */ - protected $warmItems = []; - - /** - * Key-Value-Pairs of missing items - * - * @var array - */ - protected $coldItems = []; - - public function __construct() - { - // generate warm items - for ($i = 0; $i < 10; $i++) { - $this->warmItems['warm' . $i] = $i; - } - - // generate cold items - for ($i = 0; $i < 10; $i++) { - $this->coldItems['cold' . $i] = $i; - } - } - - public function setUp() - { - $this->storage->setItems($this->warmItems); - } - - public function tearDown() - { - $this->storage->removeItems(array_keys($this->coldItems)); - } - - /** - * Has missing items with single operations - */ - public function benchHasMissingItemsSingle() - { - foreach ($this->coldItems as $k => $_) { - $this->storage->hasItem($k); - } - } - - /** - * Has missing items at once - */ - public function benchHasMissingItemsBulk() - { - $this->storage->hasItems(array_keys($this->coldItems)); - } - - /** - * Has existing items with single operations - */ - public function benchHasExistingItemsSingle() - { - foreach ($this->warmItems as $k => $_) { - $this->storage->hasItem($k); - } - } - - /** - * Has existing items at once - */ - public function benchHasExistingItemsBulk() - { - $this->storage->hasItems(array_keys($this->warmItems)); - } - - /** - * Set existing items with single operations - */ - public function benchSetExistingItemsSingle() - { - foreach ($this->warmItems as $k => $v) { - $this->storage->setItem($k, $v); - } - } - - /** - * Set existingn items at once - */ - public function benchSetExistingItemsBulk() - { - $this->storage->setItems($this->warmItems); - } - - /** - * Set missing items with single operations - */ - public function benchSetMissingItemsSingle() - { - foreach ($this->coldItems as $k => $v) { - $this->storage->setItem($k, $k . $v); - } - } - - /** - * Set missing items at once - */ - public function benchSetMissingItemsBulk() - { - $this->storage->setItems($this->coldItems); - } - - /** - * Add items with single operations - */ - public function benchAddItemsSingle() - { - foreach ($this->coldItems as $k => $v) { - $this->storage->addItem($k, $k . $v); - } - } - - /** - * Add items at once - */ - public function benchAddItemsBulk() - { - $this->storage->addItems($this->coldItems); - } - - /** - * Replace items with single operations - */ - public function benchReplaceItemsSingle() - { - foreach ($this->warmItems as $k => $v) { - $this->storage->replaceItem($k, $k . $v); - } - } - - /** - * Replace items at once - */ - public function benchReplaceItemsBulk() - { - $this->storage->replaceItems($this->coldItems); - } - - /** - * Get, check and set items with single operations - */ - public function benchGetCheckAndSetItemsSingle() - { - foreach ($this->warmItems as $k => $v) { - $this->storage->getItem($k, $success, $token); - $this->storage->checkAndSetItem($token, $k, $k . $v); - } - } - - /** - * Touch missing items with single operations - */ - public function benchTouchMissingItemsSingle() - { - foreach ($this->coldItems as $k => $_) { - $this->storage->touchItem($k); - } - } - - /** - * Touch missing items at once - */ - public function benchTouchMissingItemsBulk() - { - $this->storage->touchItems(array_keys($this->coldItems)); - } - - /** - * Touch existing items with single operations - */ - public function benchTouchExistingItemsSingle() - { - foreach ($this->warmItems as $k => $_) { - $this->storage->touchItem($k); - } - } - - /** - * Touch existing items at once - */ - public function benchTouchExistingItemsBulk() - { - $this->storage->touchItems(array_keys($this->warmItems)); - } - - /** - * Get missing items with single operations - */ - public function benchGetMissingItemsSingle() - { - foreach ($this->coldItems as $k => $_) { - $this->storage->getItem($k); - } - } - - /** - * Get missing items at once - */ - public function benchGetMissingItemsBulk() - { - $this->storage->getItems(array_keys($this->coldItems)); - } - - /** - * Get existing items with single operations - */ - public function benchGetExistingItemsSingle() - { - foreach ($this->warmItems as $k => $_) { - $this->storage->getItem($k); - } - } - - /** - * Get existing items at once - */ - public function benchGetExistingItemsBulk() - { - $this->storage->getItems(array_keys($this->warmItems)); - } - - /** - * Remove missing items with single operations - */ - public function benchRemoveMissingItemsSingle() - { - foreach ($this->coldItems as $k => $_) { - $this->storage->removeItem($k); - } - } - - /** - * Remove missing items at once - */ - public function benchRemoveMissingItemsBulk() - { - $this->storage->removeItems(array_keys($this->coldItems)); - } - - /** - * Remove exisint items with single operations - */ - public function benchRemoveExistingItemsSingle() - { - foreach ($this->warmItems as $k => $_) { - $this->storage->removeItem($k); - } - } - - /** - * Remove existing items at once - */ - public function benchRemoveExistingItemsBulk() - { - $this->storage->removeItems(array_keys($this->warmItems)); - } - - /** - * Increment missing items with single operations - */ - public function benchIncrementMissingItemsSingle() - { - foreach ($this->coldItems as $k => $v) { - $this->storage->incrementItem($k, $v); - } - } - - /** - * Increment missing items at once - */ - public function benchIncrementMissingItemsBulk() - { - $this->storage->incrementItems($this->coldItems); - } - - /** - * Increment exisint items with single operations - */ - public function benchIncrementExistingItemsSingle() - { - foreach ($this->warmItems as $k => $v) { - $this->storage->incrementItem($k, $v); - } - } - - /** - * Increment existing items at once - */ - public function benchIncrementExistingItemsBulk() - { - $this->storage->incrementItems($this->warmItems); - } - - /** - * Decrement missing items with single operations - */ - public function benchDecrementMissingItemsSingle() - { - foreach ($this->coldItems as $k => $v) { - $this->storage->decrementItem($k, $v); - } - } - - /** - * Decrement missing items at once - */ - public function benchDecrementMissingItemsBulk() - { - $this->storage->decrementItems($this->coldItems); - } - - /** - * Decrement exisint items with single operations - */ - public function benchDecrementExistingItemsSingle() - { - foreach ($this->warmItems as $k => $v) { - $this->storage->decrementItem($k, $v); - } - } - - /** - * Decrement existing items at once - */ - public function benchDecrementExistingItemsBulk() - { - $this->storage->decrementItems($this->warmItems); - } -} diff --git a/benchmark/FilesystemStorageAdapterBench.php b/benchmark/FilesystemStorageAdapterBench.php deleted file mode 100644 index 937b82dc..00000000 --- a/benchmark/FilesystemStorageAdapterBench.php +++ /dev/null @@ -1,74 +0,0 @@ -tmpCacheDir = (string) @tempnam(sys_get_temp_dir(), 'laminas_cache_test_'); - if (! $this->tmpCacheDir) { - $err = error_get_last(); - $this->fail("Can't create temporary cache directory-file: {$err['message']}"); - } elseif (! @unlink($this->tmpCacheDir)) { - $err = error_get_last(); - $this->fail("Can't remove temporary cache directory-file: {$err['message']}"); - } elseif (! @mkdir($this->tmpCacheDir, 0777)) { - $err = error_get_last(); - $this->fail("Can't create temporary cache directory: {$err['message']}"); - } - - $this->storage = new Filesystem([ - 'cache_dir' => $this->tmpCacheDir, - ]); - - parent::__construct(); - } - - public function __destruct() - { - $this->removeRecursive($this->tmpCacheDir); - } - - private function removeRecursive(string $dir): void - { - if (file_exists($dir)) { - $dirIt = new DirectoryIterator($dir); - foreach ($dirIt as $entry) { - $fname = $entry->getFilename(); - if ($fname === '.' || $fname === '..') { - continue; - } - - if ($entry->isFile()) { - unlink($entry->getPathname()); - } else { - $this->removeRecursive($entry->getPathname()); - } - } - - rmdir($dir); - } - } -} diff --git a/benchmark/MemoryStorageAdapterBench.php b/benchmark/MemoryStorageAdapterBench.php deleted file mode 100644 index 8ae937a7..00000000 --- a/benchmark/MemoryStorageAdapterBench.php +++ /dev/null @@ -1,23 +0,0 @@ -storage = new Memory(); - - parent::__construct(); - } -} diff --git a/composer.json b/composer.json index 5eb0e22d..a2a86ef0 100644 --- a/composer.json +++ b/composer.json @@ -35,7 +35,7 @@ }, "require": { "php": "~8.1.0 || ~8.2.0", - "laminas/laminas-cache-storage-implementation": "1.0", + "laminas/laminas-cache-storage-implementation": "2.0", "laminas/laminas-eventmanager": "^3.4", "laminas/laminas-servicemanager": "^3.21", "laminas/laminas-stdlib": "^3.6", @@ -45,17 +45,12 @@ "webmozart/assert": "^1.9" }, "require-dev": { - "laminas/laminas-cache-storage-adapter-apcu": "^2.4", - "laminas/laminas-cache-storage-adapter-blackhole": "^2.3", - "laminas/laminas-cache-storage-adapter-filesystem": "^2.3", - "laminas/laminas-cache-storage-adapter-memory": "^2.2", - "laminas/laminas-cache-storage-adapter-test": "^2.4", + "laminas/laminas-cache-storage-adapter-dev": "@dev", "laminas/laminas-cli": "^1.7", "laminas/laminas-coding-standard": "~2.5.0", "laminas/laminas-config-aggregator": "^1.13", "laminas/laminas-feed": "^2.20", "laminas/laminas-serializer": "^2.14", - "phpbench/phpbench": "^1.2.7", "phpunit/phpunit": "^9.5.27", "psalm/plugin-phpunit": "^0.18.4", "vimeo/psalm": "^5.4" @@ -87,12 +82,16 @@ }, "autoload-dev": { "psr-4": { - "LaminasTest\\Cache\\": "test/", - "LaminasBench\\Cache\\": "benchmark/" + "LaminasTest\\Cache\\": "test/" } }, + "repositories": [ + { + "type": "path", + "url": "./dev-implementation" + } + ], "scripts": { - "benchmark": "phpbench run --revs=2 --iterations=2 --report=aggregate", "check": [ "@cs-check", "@static-analysis", diff --git a/composer.lock b/composer.lock index f33367e2..6fe387e2 100644 --- a/composer.lock +++ b/composer.lock @@ -4,74 +4,28 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "295bfbb0011bdabd9ee9e7ab205903e7", + "content-hash": "9d8cf830e8f7a3851a59b082359a99e0", "packages": [ { - "name": "laminas/laminas-cache-storage-adapter-memory", - "version": "2.2.0", - "source": { - "type": "git", - "url": "https://github.com/laminas/laminas-cache-storage-adapter-memory.git", - "reference": "e002c7d3fa0d4723589b550d7ab4586befa72366" - }, + "name": "laminas/laminas-cache-storage-adapter-dev", + "version": "4.0.x-dev", "dist": { - "type": "zip", - "url": "https://api.github.com/repos/laminas/laminas-cache-storage-adapter-memory/zipball/e002c7d3fa0d4723589b550d7ab4586befa72366", - "reference": "e002c7d3fa0d4723589b550d7ab4586befa72366", - "shasum": "" - }, - "require": { - "laminas/laminas-cache": "^3.0", - "php": "~8.0.0 || ~8.1.0 || ~8.2.0" - }, - "conflict": { - "laminas/laminas-servicemanager": "<3.11" + "type": "path", + "url": "./dev-implementation", + "reference": "8b617656868665bd6cb5e9a99918126bdb015a89" }, "provide": { - "laminas/laminas-cache-storage-implementation": "1.0" - }, - "require-dev": { - "laminas/laminas-cache-storage-adapter-benchmark": "^1.0", - "laminas/laminas-cache-storage-adapter-test": "^2.0", - "laminas/laminas-coding-standard": "~2.4.0", - "psalm/plugin-phpunit": "^0.17.0", - "vimeo/psalm": "^4.9" + "laminas/laminas-cache-storage-implementation": "2.0" }, "type": "library", - "extra": { - "laminas": { - "config-provider": "Laminas\\Cache\\Storage\\Adapter\\Memory\\ConfigProvider", - "module": "Laminas\\Cache\\Storage\\Adapter\\Memory" - } - }, "autoload": { "psr-4": { - "Laminas\\Cache\\Storage\\Adapter\\": "src/" + "Laminas\\Cache\\Storage\\Adapter\\Dev\\": "." } }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "description": "Laminas cache adapter for memory", - "keywords": [ - "cache", - "laminas" - ], - "support": { - "docs": "https://docs.laminas.dev/laminas-cache-storage-adapter-memory/", - "forum": "https://discourse.laminas.dev/", - "issues": "https://github.com/laminas/laminas-cache-storage-adapter-memory/issues", - "rss": "https://github.com/laminas/laminas-cache-storage-adapter-memory/releases.atom", - "source": "https://github.com/laminas/laminas-cache-storage-adapter-memory" - }, - "funding": [ - { - "url": "https://funding.communitybridge.org/projects/laminas-project", - "type": "community_bridge" - } - ], - "time": "2022-10-22T14:38:52+00:00" + "transport-options": { + "relative": true + } }, { "name": "laminas/laminas-eventmanager", @@ -1165,82 +1119,6 @@ }, "time": "2019-12-04T15:06:13+00:00" }, - { - "name": "doctrine/annotations", - "version": "2.0.1", - "source": { - "type": "git", - "url": "https://github.com/doctrine/annotations.git", - "reference": "e157ef3f3124bbf6fe7ce0ffd109e8a8ef284e7f" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/doctrine/annotations/zipball/e157ef3f3124bbf6fe7ce0ffd109e8a8ef284e7f", - "reference": "e157ef3f3124bbf6fe7ce0ffd109e8a8ef284e7f", - "shasum": "" - }, - "require": { - "doctrine/lexer": "^2 || ^3", - "ext-tokenizer": "*", - "php": "^7.2 || ^8.0", - "psr/cache": "^1 || ^2 || ^3" - }, - "require-dev": { - "doctrine/cache": "^2.0", - "doctrine/coding-standard": "^10", - "phpstan/phpstan": "^1.8.0", - "phpunit/phpunit": "^7.5 || ^8.5 || ^9.5", - "symfony/cache": "^5.4 || ^6", - "vimeo/psalm": "^4.10" - }, - "suggest": { - "php": "PHP 8.0 or higher comes with attributes, a native replacement for annotations" - }, - "type": "library", - "autoload": { - "psr-4": { - "Doctrine\\Common\\Annotations\\": "lib/Doctrine/Common/Annotations" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Guilherme Blanco", - "email": "guilhermeblanco@gmail.com" - }, - { - "name": "Roman Borschel", - "email": "roman@code-factory.org" - }, - { - "name": "Benjamin Eberlei", - "email": "kontakt@beberlei.de" - }, - { - "name": "Jonathan Wage", - "email": "jonwage@gmail.com" - }, - { - "name": "Johannes Schmitt", - "email": "schmittjoh@gmail.com" - } - ], - "description": "Docblock Annotations Parser", - "homepage": "https://www.doctrine-project.org/projects/annotations.html", - "keywords": [ - "annotations", - "docblock", - "parser" - ], - "support": { - "issues": "https://github.com/doctrine/annotations/issues", - "source": "https://github.com/doctrine/annotations/tree/2.0.1" - }, - "time": "2023-02-02T22:02:53+00:00" - }, { "name": "doctrine/instantiator", "version": "2.0.0", @@ -1311,83 +1189,6 @@ ], "time": "2022-12-30T00:23:10+00:00" }, - { - "name": "doctrine/lexer", - "version": "3.0.0", - "source": { - "type": "git", - "url": "https://github.com/doctrine/lexer.git", - "reference": "84a527db05647743d50373e0ec53a152f2cde568" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/doctrine/lexer/zipball/84a527db05647743d50373e0ec53a152f2cde568", - "reference": "84a527db05647743d50373e0ec53a152f2cde568", - "shasum": "" - }, - "require": { - "php": "^8.1" - }, - "require-dev": { - "doctrine/coding-standard": "^10", - "phpstan/phpstan": "^1.9", - "phpunit/phpunit": "^9.5", - "psalm/plugin-phpunit": "^0.18.3", - "vimeo/psalm": "^5.0" - }, - "type": "library", - "autoload": { - "psr-4": { - "Doctrine\\Common\\Lexer\\": "src" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Guilherme Blanco", - "email": "guilhermeblanco@gmail.com" - }, - { - "name": "Roman Borschel", - "email": "roman@code-factory.org" - }, - { - "name": "Johannes Schmitt", - "email": "schmittjoh@gmail.com" - } - ], - "description": "PHP Doctrine Lexer parser library that can be used in Top-Down, Recursive Descent Parsers.", - "homepage": "https://www.doctrine-project.org/projects/lexer.html", - "keywords": [ - "annotations", - "docblock", - "lexer", - "parser", - "php" - ], - "support": { - "issues": "https://github.com/doctrine/lexer/issues", - "source": "https://github.com/doctrine/lexer/tree/3.0.0" - }, - "funding": [ - { - "url": "https://www.doctrine-project.org/sponsorship.html", - "type": "custom" - }, - { - "url": "https://www.patreon.com/phpdoctrine", - "type": "patreon" - }, - { - "url": "https://tidelift.com/funding/github/packagist/doctrine%2Flexer", - "type": "tidelift" - } - ], - "time": "2022-12-15T16:57:16+00:00" - }, { "name": "felixfbecker/advanced-json-rpc", "version": "v3.2.1", @@ -1550,263 +1351,6 @@ ], "time": "2022-12-24T12:35:10+00:00" }, - { - "name": "laminas/laminas-cache-storage-adapter-apcu", - "version": "2.4.0", - "source": { - "type": "git", - "url": "https://github.com/laminas/laminas-cache-storage-adapter-apcu.git", - "reference": "89561dee942fbdb76647ec939f0dfa6a1db6f9f4" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/laminas/laminas-cache-storage-adapter-apcu/zipball/89561dee942fbdb76647ec939f0dfa6a1db6f9f4", - "reference": "89561dee942fbdb76647ec939f0dfa6a1db6f9f4", - "shasum": "" - }, - "require": { - "ext-apcu": "^5.1.10", - "laminas/laminas-cache": "^3.0", - "php": "~8.0.0 || ~8.1.0 || ~8.2.0" - }, - "provide": { - "laminas/laminas-cache-storage-implementation": "1.0" - }, - "require-dev": { - "laminas/laminas-cache-storage-adapter-test": "^2.0", - "laminas/laminas-coding-standard": "~2.4.0", - "psalm/plugin-phpunit": "^0.18.0", - "vimeo/psalm": "^5.0.0" - }, - "type": "library", - "extra": { - "laminas": { - "config-provider": "Laminas\\Cache\\Storage\\Adapter\\Apcu\\ConfigProvider", - "module": "Laminas\\Cache\\Storage\\Adapter\\Apcu" - } - }, - "autoload": { - "psr-4": { - "Laminas\\Cache\\Storage\\Adapter\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "description": "Laminas cache adapter for apcu", - "keywords": [ - "cache", - "laminas" - ], - "support": { - "docs": "https://docs.laminas.dev/laminas-cache-storage-adapter-apcu/", - "forum": "https://discourse.laminas.dev/", - "issues": "https://github.com/laminas/laminas-cache-storage-adapter-apcu/issues", - "rss": "https://github.com/laminas/laminas-cache-storage-adapter-apcu/releases.atom", - "source": "https://github.com/laminas/laminas-cache-storage-adapter-apcu" - }, - "funding": [ - { - "url": "https://funding.communitybridge.org/projects/laminas-project", - "type": "community_bridge" - } - ], - "time": "2022-12-05T11:22:35+00:00" - }, - { - "name": "laminas/laminas-cache-storage-adapter-blackhole", - "version": "2.3.0", - "source": { - "type": "git", - "url": "https://github.com/laminas/laminas-cache-storage-adapter-blackhole.git", - "reference": "8730402201904784e6b28a1014908c6123c12d02" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/laminas/laminas-cache-storage-adapter-blackhole/zipball/8730402201904784e6b28a1014908c6123c12d02", - "reference": "8730402201904784e6b28a1014908c6123c12d02", - "shasum": "" - }, - "require": { - "laminas/laminas-cache": "^3.0", - "php": "~8.0.0 || ~8.1.0 || ~8.2.0" - }, - "conflict": { - "laminas/laminas-servicemanager": "<3.11" - }, - "provide": { - "laminas/laminas-cache-storage-implementation": "1.0" - }, - "require-dev": { - "laminas/laminas-cache-storage-adapter-test": "^2.4", - "laminas/laminas-coding-standard": "~2.4.0", - "psalm/plugin-phpunit": "^0.18.4", - "vimeo/psalm": "^5.2" - }, - "type": "library", - "extra": { - "laminas": { - "config-provider": "Laminas\\Cache\\Storage\\Adapter\\BlackHole\\ConfigProvider", - "module": "Laminas\\Cache\\Storage\\Adapter\\BlackHole" - } - }, - "autoload": { - "psr-4": { - "Laminas\\Cache\\Storage\\Adapter\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "description": "Laminas cache adapter for blackhole", - "keywords": [ - "cache", - "laminas" - ], - "support": { - "docs": "https://docs.laminas.dev/laminas-cache-storage-adapter-blackhole/", - "forum": "https://discourse.laminas.dev/", - "issues": "https://github.com/laminas/laminas-cache-storage-adapter-blackhole/issues", - "rss": "https://github.com/laminas/laminas-cache-storage-adapter-blackhole/releases.atom", - "source": "https://github.com/laminas/laminas-cache-storage-adapter-blackhole" - }, - "funding": [ - { - "url": "https://funding.communitybridge.org/projects/laminas-project", - "type": "community_bridge" - } - ], - "time": "2022-12-31T16:03:12+00:00" - }, - { - "name": "laminas/laminas-cache-storage-adapter-filesystem", - "version": "2.3.0", - "source": { - "type": "git", - "url": "https://github.com/laminas/laminas-cache-storage-adapter-filesystem.git", - "reference": "9881529cacc26823dc1530e8b850fd9e467ccd05" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/laminas/laminas-cache-storage-adapter-filesystem/zipball/9881529cacc26823dc1530e8b850fd9e467ccd05", - "reference": "9881529cacc26823dc1530e8b850fd9e467ccd05", - "shasum": "" - }, - "require": { - "laminas/laminas-cache": "^3.0", - "php": "~8.0.0 || ~8.1.0 || ~8.2.0" - }, - "provide": { - "laminas/laminas-cache-storage-implementation": "1.0" - }, - "require-dev": { - "ext-pcntl": "*", - "ext-posix": "*", - "laminas/laminas-cache-storage-adapter-benchmark": "^1.0", - "laminas/laminas-cache-storage-adapter-test": "^2.0 || 2.0.x-dev", - "laminas/laminas-coding-standard": "~2.4", - "laminas/laminas-serializer": "^2.14.0", - "phpunit/phpunit": "^9.5.25", - "psalm/plugin-phpunit": "^0.17.0", - "vimeo/psalm": "^4.29.0" - }, - "type": "library", - "extra": { - "laminas": { - "config-provider": "Laminas\\Cache\\Storage\\Adapter\\Filesystem\\ConfigProvider", - "module": "Laminas\\Cache\\Storage\\Adapter\\Filesystem" - } - }, - "autoload": { - "psr-4": { - "Laminas\\Cache\\Storage\\Adapter\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "description": "Laminas cache adapter for filesystem", - "keywords": [ - "cache", - "laminas" - ], - "support": { - "docs": "https://docs.laminas.dev/laminas-cache-storage-adapter-filesystem/", - "forum": "https://discourse.laminas.dev/", - "issues": "https://github.com/laminas/laminas-cache-storage-adapter-filesystem/issues", - "rss": "https://github.com/laminas/laminas-cache-storage-adapter-filesystem/releases.atom", - "source": "https://github.com/laminas/laminas-cache-storage-adapter-filesystem" - }, - "funding": [ - { - "url": "https://funding.communitybridge.org/projects/laminas-project", - "type": "community_bridge" - } - ], - "time": "2022-10-22T15:00:05+00:00" - }, - { - "name": "laminas/laminas-cache-storage-adapter-test", - "version": "2.4.0", - "source": { - "type": "git", - "url": "https://github.com/laminas/laminas-cache-storage-adapter-test.git", - "reference": "cf8dbad341f93fa1bee326cdaca488182fc68e96" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/laminas/laminas-cache-storage-adapter-test/zipball/cf8dbad341f93fa1bee326cdaca488182fc68e96", - "reference": "cf8dbad341f93fa1bee326cdaca488182fc68e96", - "shasum": "" - }, - "require": { - "container-interop/container-interop": "^1.2", - "laminas/laminas-cache": "^3.1", - "php": "^7.4 || ~8.0.0 || ~8.1.0 || ~8.2.0", - "phpunit/phpunit": "^9.5.20", - "psr/cache": "^1.0 || ^2.0 || ^3.0", - "psr/simple-cache": "^1.0 || ^2.0 || ^3.0" - }, - "require-dev": { - "laminas/laminas-cache-storage-adapter-apcu": "^2.0", - "laminas/laminas-cache-storage-adapter-memory": "^2.0", - "laminas/laminas-coding-standard": "~2.4.0", - "psalm/plugin-phpunit": "^0.18.0", - "vimeo/psalm": "^5.0.0" - }, - "type": "library", - "autoload": { - "psr-4": { - "LaminasTest\\Cache\\Storage\\Adapter\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "description": "Laminas cache storage adapter shared test dependency", - "keywords": [ - "cache", - "laminas", - "test" - ], - "support": { - "forum": "https://discourse.laminas.dev/", - "issues": "https://github.com/laminas/laminas-cache-storage-adapter-test/issues", - "rss": "https://github.com/laminas/laminas-cache-storage-adapter-test/releases.atom", - "source": "https://github.com/laminas/laminas-cache-storage-adapter-test" - }, - "funding": [ - { - "url": "https://funding.communitybridge.org/projects/laminas-project", - "type": "community_bridge" - } - ], - "time": "2022-12-09T09:20:01+00:00" - }, { "name": "laminas/laminas-cli", "version": "1.8.0", @@ -2385,16 +1929,16 @@ }, { "name": "nikic/php-parser", - "version": "v4.16.0", + "version": "v4.17.1", "source": { "type": "git", "url": "https://github.com/nikic/PHP-Parser.git", - "reference": "19526a33fb561ef417e822e85f08a00db4059c17" + "reference": "a6303e50c90c355c7eeee2c4a8b27fe8dc8fef1d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/19526a33fb561ef417e822e85f08a00db4059c17", - "reference": "19526a33fb561ef417e822e85f08a00db4059c17", + "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/a6303e50c90c355c7eeee2c4a8b27fe8dc8fef1d", + "reference": "a6303e50c90c355c7eeee2c4a8b27fe8dc8fef1d", "shasum": "" }, "require": { @@ -2435,9 +1979,9 @@ ], "support": { "issues": "https://github.com/nikic/PHP-Parser/issues", - "source": "https://github.com/nikic/PHP-Parser/tree/v4.16.0" + "source": "https://github.com/nikic/PHP-Parser/tree/v4.17.1" }, - "time": "2023-06-25T14:52:30+00:00" + "time": "2023-08-13T19:53:39+00:00" }, { "name": "phar-io/manifest", @@ -2534,213 +2078,21 @@ }, { "name": "Sebastian Heuer", - "email": "sebastian@phpeople.de", - "role": "Developer" - }, - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "Developer" - } - ], - "description": "Library for handling version information and constraints", - "support": { - "issues": "https://github.com/phar-io/version/issues", - "source": "https://github.com/phar-io/version/tree/3.2.1" - }, - "time": "2022-02-21T01:04:05+00:00" - }, - { - "name": "phpbench/container", - "version": "2.2.1", - "source": { - "type": "git", - "url": "https://github.com/phpbench/container.git", - "reference": "6d555ff7174fca13f9b1ec0b4a089ed41d0ab392" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/phpbench/container/zipball/6d555ff7174fca13f9b1ec0b4a089ed41d0ab392", - "reference": "6d555ff7174fca13f9b1ec0b4a089ed41d0ab392", - "shasum": "" - }, - "require": { - "psr/container": "^1.0|^2.0", - "symfony/options-resolver": "^4.2 || ^5.0 || ^6.0" - }, - "require-dev": { - "friendsofphp/php-cs-fixer": "^2.16", - "phpstan/phpstan": "^0.12.52", - "phpunit/phpunit": "^8" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.x-dev" - } - }, - "autoload": { - "psr-4": { - "PhpBench\\DependencyInjection\\": "lib/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Daniel Leech", - "email": "daniel@dantleech.com" - } - ], - "description": "Simple, configurable, service container.", - "support": { - "issues": "https://github.com/phpbench/container/issues", - "source": "https://github.com/phpbench/container/tree/2.2.1" - }, - "time": "2022-01-25T10:17:35+00:00" - }, - { - "name": "phpbench/dom", - "version": "0.3.3", - "source": { - "type": "git", - "url": "https://github.com/phpbench/dom.git", - "reference": "786a96db538d0def931f5b19225233ec42ec7a72" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/phpbench/dom/zipball/786a96db538d0def931f5b19225233ec42ec7a72", - "reference": "786a96db538d0def931f5b19225233ec42ec7a72", - "shasum": "" - }, - "require": { - "ext-dom": "*", - "php": "^7.3||^8.0" - }, - "require-dev": { - "friendsofphp/php-cs-fixer": "^3.14", - "phpstan/phpstan": "^1.10", - "phpunit/phpunit": "^8.0||^9.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.0-dev" - } - }, - "autoload": { - "psr-4": { - "PhpBench\\Dom\\": "lib/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Daniel Leech", - "email": "daniel@dantleech.com" - } - ], - "description": "DOM wrapper to simplify working with the PHP DOM implementation", - "support": { - "issues": "https://github.com/phpbench/dom/issues", - "source": "https://github.com/phpbench/dom/tree/0.3.3" - }, - "time": "2023-03-06T23:46:57+00:00" - }, - { - "name": "phpbench/phpbench", - "version": "1.2.14", - "source": { - "type": "git", - "url": "https://github.com/phpbench/phpbench.git", - "reference": "edbd1b7ecf704eb01f7a2bcd1b8aa8c189f9fa4e" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/phpbench/phpbench/zipball/edbd1b7ecf704eb01f7a2bcd1b8aa8c189f9fa4e", - "reference": "edbd1b7ecf704eb01f7a2bcd1b8aa8c189f9fa4e", - "shasum": "" - }, - "require": { - "doctrine/annotations": "^1.13 || ^2.0", - "ext-dom": "*", - "ext-json": "*", - "ext-pcre": "*", - "ext-reflection": "*", - "ext-spl": "*", - "ext-tokenizer": "*", - "php": "^7.4 || ^8.0", - "phpbench/container": "^2.1", - "phpbench/dom": "~0.3.3", - "psr/log": "^1.1 || ^2.0 || ^3.0", - "seld/jsonlint": "^1.1", - "symfony/console": "^4.2 || ^5.0 || ^6.0", - "symfony/filesystem": "^4.2 || ^5.0 || ^6.0", - "symfony/finder": "^4.2 || ^5.0 || ^6.0", - "symfony/options-resolver": "^4.2 || ^5.0 || ^6.0", - "symfony/process": "^4.2 || ^5.0 || ^6.0", - "webmozart/glob": "^4.6" - }, - "require-dev": { - "dantleech/invoke": "^2.0", - "friendsofphp/php-cs-fixer": "^3.0", - "jangregor/phpstan-prophecy": "^1.0", - "phpspec/prophecy": "^1.12", - "phpstan/extension-installer": "^1.1", - "phpstan/phpstan": "^1.0", - "phpstan/phpstan-phpunit": "^1.0", - "phpunit/phpunit": "^9.0", - "symfony/error-handler": "^5.2 || ^6.0", - "symfony/var-dumper": "^4.0 || ^5.0 || ^6.0" - }, - "suggest": { - "ext-xdebug": "For Xdebug profiling extension." - }, - "bin": [ - "bin/phpbench" - ], - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.2-dev" - } - }, - "autoload": { - "files": [ - "lib/Report/Func/functions.php" - ], - "psr-4": { - "PhpBench\\": "lib/", - "PhpBench\\Extensions\\XDebug\\": "extensions/xdebug/lib/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ + "email": "sebastian@phpeople.de", + "role": "Developer" + }, { - "name": "Daniel Leech", - "email": "daniel@dantleech.com" + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "Developer" } ], - "description": "PHP Benchmarking Framework", + "description": "Library for handling version information and constraints", "support": { - "issues": "https://github.com/phpbench/phpbench/issues", - "source": "https://github.com/phpbench/phpbench/tree/1.2.14" + "issues": "https://github.com/phar-io/version/issues", + "source": "https://github.com/phar-io/version/tree/3.2.1" }, - "funding": [ - { - "url": "https://github.com/dantleech", - "type": "github" - } - ], - "time": "2023-07-09T09:16:08+00:00" + "time": "2022-02-21T01:04:05+00:00" }, { "name": "phpdocumentor/reflection-common", @@ -3272,16 +2624,16 @@ }, { "name": "phpunit/phpunit", - "version": "9.6.10", + "version": "9.6.11", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "a6d351645c3fe5a30f5e86be6577d946af65a328" + "reference": "810500e92855eba8a7a5319ae913be2da6f957b0" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/a6d351645c3fe5a30f5e86be6577d946af65a328", - "reference": "a6d351645c3fe5a30f5e86be6577d946af65a328", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/810500e92855eba8a7a5319ae913be2da6f957b0", + "reference": "810500e92855eba8a7a5319ae913be2da6f957b0", "shasum": "" }, "require": { @@ -3355,7 +2707,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/phpunit/issues", "security": "https://github.com/sebastianbergmann/phpunit/security/policy", - "source": "https://github.com/sebastianbergmann/phpunit/tree/9.6.10" + "source": "https://github.com/sebastianbergmann/phpunit/tree/9.6.11" }, "funding": [ { @@ -3371,7 +2723,7 @@ "type": "tidelift" } ], - "time": "2023-07-10T04:04:23+00:00" + "time": "2023-08-19T07:10:56+00:00" }, { "name": "psalm/plugin-phpunit", @@ -4039,16 +3391,16 @@ }, { "name": "sebastian/global-state", - "version": "5.0.5", + "version": "5.0.6", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/global-state.git", - "reference": "0ca8db5a5fc9c8646244e629625ac486fa286bf2" + "reference": "bde739e7565280bda77be70044ac1047bc007e34" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/0ca8db5a5fc9c8646244e629625ac486fa286bf2", - "reference": "0ca8db5a5fc9c8646244e629625ac486fa286bf2", + "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/bde739e7565280bda77be70044ac1047bc007e34", + "reference": "bde739e7565280bda77be70044ac1047bc007e34", "shasum": "" }, "require": { @@ -4091,7 +3443,7 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/global-state/issues", - "source": "https://github.com/sebastianbergmann/global-state/tree/5.0.5" + "source": "https://github.com/sebastianbergmann/global-state/tree/5.0.6" }, "funding": [ { @@ -4099,7 +3451,7 @@ "type": "github" } ], - "time": "2022-02-14T08:28:10+00:00" + "time": "2023-08-02T09:26:13+00:00" }, { "name": "sebastian/lines-of-code", @@ -4497,70 +3849,6 @@ ], "time": "2020-09-28T06:39:44+00:00" }, - { - "name": "seld/jsonlint", - "version": "1.10.0", - "source": { - "type": "git", - "url": "https://github.com/Seldaek/jsonlint.git", - "reference": "594fd6462aad8ecee0b45ca5045acea4776667f1" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/Seldaek/jsonlint/zipball/594fd6462aad8ecee0b45ca5045acea4776667f1", - "reference": "594fd6462aad8ecee0b45ca5045acea4776667f1", - "shasum": "" - }, - "require": { - "php": "^5.3 || ^7.0 || ^8.0" - }, - "require-dev": { - "phpstan/phpstan": "^1.5", - "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.0 || ^8.5.13" - }, - "bin": [ - "bin/jsonlint" - ], - "type": "library", - "autoload": { - "psr-4": { - "Seld\\JsonLint\\": "src/Seld/JsonLint/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Jordi Boggiano", - "email": "j.boggiano@seld.be", - "homepage": "http://seld.be" - } - ], - "description": "JSON Linter", - "keywords": [ - "json", - "linter", - "parser", - "validator" - ], - "support": { - "issues": "https://github.com/Seldaek/jsonlint/issues", - "source": "https://github.com/Seldaek/jsonlint/tree/1.10.0" - }, - "funding": [ - { - "url": "https://github.com/Seldaek", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/seld/jsonlint", - "type": "tidelift" - } - ], - "time": "2023-05-11T13:16:46+00:00" - }, { "name": "slevomat/coding-standard", "version": "7.2.1", @@ -4744,16 +4032,16 @@ }, { "name": "symfony/console", - "version": "v6.3.0", + "version": "v6.3.4", "source": { "type": "git", "url": "https://github.com/symfony/console.git", - "reference": "8788808b07cf0bdd6e4b7fdd23d8ddb1470c83b7" + "reference": "eca495f2ee845130855ddf1cf18460c38966c8b6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/8788808b07cf0bdd6e4b7fdd23d8ddb1470c83b7", - "reference": "8788808b07cf0bdd6e4b7fdd23d8ddb1470c83b7", + "url": "https://api.github.com/repos/symfony/console/zipball/eca495f2ee845130855ddf1cf18460c38966c8b6", + "reference": "eca495f2ee845130855ddf1cf18460c38966c8b6", "shasum": "" }, "require": { @@ -4814,7 +4102,7 @@ "terminal" ], "support": { - "source": "https://github.com/symfony/console/tree/v6.3.0" + "source": "https://github.com/symfony/console/tree/v6.3.4" }, "funding": [ { @@ -4830,7 +4118,7 @@ "type": "tidelift" } ], - "time": "2023-05-29T12:49:39+00:00" + "time": "2023-08-16T10:10:12+00:00" }, { "name": "symfony/deprecation-contracts", @@ -4901,16 +4189,16 @@ }, { "name": "symfony/event-dispatcher", - "version": "v6.3.0", + "version": "v6.3.2", "source": { "type": "git", "url": "https://github.com/symfony/event-dispatcher.git", - "reference": "3af8ac1a3f98f6dbc55e10ae59c9e44bfc38dfaa" + "reference": "adb01fe097a4ee930db9258a3cc906b5beb5cf2e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/3af8ac1a3f98f6dbc55e10ae59c9e44bfc38dfaa", - "reference": "3af8ac1a3f98f6dbc55e10ae59c9e44bfc38dfaa", + "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/adb01fe097a4ee930db9258a3cc906b5beb5cf2e", + "reference": "adb01fe097a4ee930db9258a3cc906b5beb5cf2e", "shasum": "" }, "require": { @@ -4961,7 +4249,7 @@ "description": "Provides tools that allow your application components to communicate with each other by dispatching events and listening to them", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/event-dispatcher/tree/v6.3.0" + "source": "https://github.com/symfony/event-dispatcher/tree/v6.3.2" }, "funding": [ { @@ -4977,7 +4265,7 @@ "type": "tidelift" } ], - "time": "2023-04-21T14:41:17+00:00" + "time": "2023-07-06T06:56:43+00:00" }, { "name": "symfony/event-dispatcher-contracts", @@ -5118,137 +4406,6 @@ ], "time": "2023-06-01T08:30:39+00:00" }, - { - "name": "symfony/finder", - "version": "v6.3.0", - "source": { - "type": "git", - "url": "https://github.com/symfony/finder.git", - "reference": "d9b01ba073c44cef617c7907ce2419f8d00d75e2" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/finder/zipball/d9b01ba073c44cef617c7907ce2419f8d00d75e2", - "reference": "d9b01ba073c44cef617c7907ce2419f8d00d75e2", - "shasum": "" - }, - "require": { - "php": ">=8.1" - }, - "require-dev": { - "symfony/filesystem": "^6.0" - }, - "type": "library", - "autoload": { - "psr-4": { - "Symfony\\Component\\Finder\\": "" - }, - "exclude-from-classmap": [ - "/Tests/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Finds files and directories via an intuitive fluent interface", - "homepage": "https://symfony.com", - "support": { - "source": "https://github.com/symfony/finder/tree/v6.3.0" - }, - "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": "2023-04-02T01:25:41+00:00" - }, - { - "name": "symfony/options-resolver", - "version": "v6.3.0", - "source": { - "type": "git", - "url": "https://github.com/symfony/options-resolver.git", - "reference": "a10f19f5198d589d5c33333cffe98dc9820332dd" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/options-resolver/zipball/a10f19f5198d589d5c33333cffe98dc9820332dd", - "reference": "a10f19f5198d589d5c33333cffe98dc9820332dd", - "shasum": "" - }, - "require": { - "php": ">=8.1", - "symfony/deprecation-contracts": "^2.5|^3" - }, - "type": "library", - "autoload": { - "psr-4": { - "Symfony\\Component\\OptionsResolver\\": "" - }, - "exclude-from-classmap": [ - "/Tests/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Provides an improved replacement for the array_replace PHP function", - "homepage": "https://symfony.com", - "keywords": [ - "config", - "configuration", - "options" - ], - "support": { - "source": "https://github.com/symfony/options-resolver/tree/v6.3.0" - }, - "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": "2023-05-12T14:21:09+00:00" - }, { "name": "symfony/polyfill-ctype", "version": "v1.27.0", @@ -5662,67 +4819,6 @@ ], "time": "2022-11-03T14:55:06+00:00" }, - { - "name": "symfony/process", - "version": "v6.3.0", - "source": { - "type": "git", - "url": "https://github.com/symfony/process.git", - "reference": "8741e3ed7fe2e91ec099e02446fb86667a0f1628" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/process/zipball/8741e3ed7fe2e91ec099e02446fb86667a0f1628", - "reference": "8741e3ed7fe2e91ec099e02446fb86667a0f1628", - "shasum": "" - }, - "require": { - "php": ">=8.1" - }, - "type": "library", - "autoload": { - "psr-4": { - "Symfony\\Component\\Process\\": "" - }, - "exclude-from-classmap": [ - "/Tests/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Executes commands in sub-processes", - "homepage": "https://symfony.com", - "support": { - "source": "https://github.com/symfony/process/tree/v6.3.0" - }, - "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": "2023-05-19T08:06:44+00:00" - }, { "name": "symfony/service-contracts", "version": "v2.5.2", @@ -5808,16 +4904,16 @@ }, { "name": "symfony/string", - "version": "v6.3.0", + "version": "v6.3.2", "source": { "type": "git", "url": "https://github.com/symfony/string.git", - "reference": "f2e190ee75ff0f5eced645ec0be5c66fac81f51f" + "reference": "53d1a83225002635bca3482fcbf963001313fb68" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/string/zipball/f2e190ee75ff0f5eced645ec0be5c66fac81f51f", - "reference": "f2e190ee75ff0f5eced645ec0be5c66fac81f51f", + "url": "https://api.github.com/repos/symfony/string/zipball/53d1a83225002635bca3482fcbf963001313fb68", + "reference": "53d1a83225002635bca3482fcbf963001313fb68", "shasum": "" }, "require": { @@ -5874,7 +4970,7 @@ "utf8" ], "support": { - "source": "https://github.com/symfony/string/tree/v6.3.0" + "source": "https://github.com/symfony/string/tree/v6.3.2" }, "funding": [ { @@ -5890,7 +4986,7 @@ "type": "tidelift" } ], - "time": "2023-03-21T21:06:29+00:00" + "time": "2023-07-05T08:41:27+00:00" }, { "name": "theseer/tokenizer", @@ -5944,16 +5040,16 @@ }, { "name": "vimeo/psalm", - "version": "5.13.1", + "version": "5.15.0", "source": { "type": "git", "url": "https://github.com/vimeo/psalm.git", - "reference": "086b94371304750d1c673315321a55d15fc59015" + "reference": "5c774aca4746caf3d239d9c8cadb9f882ca29352" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/vimeo/psalm/zipball/086b94371304750d1c673315321a55d15fc59015", - "reference": "086b94371304750d1c673315321a55d15fc59015", + "url": "https://api.github.com/repos/vimeo/psalm/zipball/5c774aca4746caf3d239d9c8cadb9f882ca29352", + "reference": "5c774aca4746caf3d239d9c8cadb9f882ca29352", "shasum": "" }, "require": { @@ -5974,13 +5070,16 @@ "felixfbecker/language-server-protocol": "^1.5.2", "fidry/cpu-core-counter": "^0.4.1 || ^0.5.1", "netresearch/jsonmapper": "^1.0 || ^2.0 || ^3.0 || ^4.0", - "nikic/php-parser": "^4.14", - "php": "^7.4 || ~8.0.0 || ~8.1.0 || ~8.2.0", + "nikic/php-parser": "^4.16", + "php": "^7.4 || ~8.0.0 || ~8.1.0 || ~8.2.0 || ~8.3.0", "sebastian/diff": "^4.0 || ^5.0", "spatie/array-to-xml": "^2.17.0 || ^3.0", "symfony/console": "^4.1.6 || ^5.0 || ^6.0", "symfony/filesystem": "^5.4 || ^6.0" }, + "conflict": { + "nikic/php-parser": "4.17.0" + }, "provide": { "psalm/psalm": "self.version" }, @@ -6044,9 +5143,9 @@ ], "support": { "issues": "https://github.com/vimeo/psalm/issues", - "source": "https://github.com/vimeo/psalm/tree/5.13.1" + "source": "https://github.com/vimeo/psalm/tree/5.15.0" }, - "time": "2023-06-27T16:39:49+00:00" + "time": "2023-08-20T23:07:30+00:00" }, { "name": "webimpress/coding-standard", @@ -6161,60 +5260,13 @@ } ], "time": "2021-04-19T16:34:45+00:00" - }, - { - "name": "webmozart/glob", - "version": "4.6.0", - "source": { - "type": "git", - "url": "https://github.com/webmozarts/glob.git", - "reference": "3c17f7dec3d9d0e87b575026011f2e75a56ed655" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/webmozarts/glob/zipball/3c17f7dec3d9d0e87b575026011f2e75a56ed655", - "reference": "3c17f7dec3d9d0e87b575026011f2e75a56ed655", - "shasum": "" - }, - "require": { - "php": "^7.3 || ^8.0.0" - }, - "require-dev": { - "phpunit/phpunit": "^9.5", - "symfony/filesystem": "^5.3" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "4.1-dev" - } - }, - "autoload": { - "psr-4": { - "Webmozart\\Glob\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Bernhard Schussek", - "email": "bschussek@gmail.com" - } - ], - "description": "A PHP implementation of Ant's glob.", - "support": { - "issues": "https://github.com/webmozarts/glob/issues", - "source": "https://github.com/webmozarts/glob/tree/4.6.0" - }, - "time": "2022-05-24T19:45:58+00:00" } ], "aliases": [], "minimum-stability": "stable", - "stability-flags": [], + "stability-flags": { + "laminas/laminas-cache-storage-adapter-dev": 20 + }, "prefer-stable": false, "prefer-lowest": false, "platform": { diff --git a/dev-implementation/README.md b/dev-implementation/README.md new file mode 100644 index 00000000..9a3a596e --- /dev/null +++ b/dev-implementation/README.md @@ -0,0 +1,4 @@ +# README + +This package is meant to provide a cache implementation for development. +By adding this as a dev-dependency, we get rid of the circular dependencies. diff --git a/dev-implementation/VoidAdapter.php b/dev-implementation/VoidAdapter.php new file mode 100644 index 00000000..4a907c9f --- /dev/null +++ b/dev-implementation/VoidAdapter.php @@ -0,0 +1,36 @@ + src test - benchmark + dev-implementation diff --git a/psalm-baseline.xml b/psalm-baseline.xml index 0ee001c6..4552f87e 100644 --- a/psalm-baseline.xml +++ b/psalm-baseline.xml @@ -1,5 +1,5 @@ - + $cacheConfiguration @@ -158,10 +158,6 @@ $object $object - - __get - __set - @@ -172,10 +168,6 @@ $data $key - - end - start - (string) $key @@ -464,9 +456,6 @@ getCaching setCaching - - $pluginRegistry - (bool) $flag (int) $value @@ -478,6 +467,12 @@ is_array($options) + + $array + + + array + $letters @@ -814,41 +809,13 @@ - - $event - - - $key - - - - - $generatedKey - $key - $params $return $return - $usedKey - - attach - getParams - getCommonPatternNamesProvider - - call - call - call - call - call - call - generateKey - generateKey - getEventManager - @@ -874,31 +841,10 @@ - - $event - - - - - $generatedKey - $params $return $return - $usedKey - - attach - getParams - - - pattern->property]]> - pattern->property]]> - pattern->property]]> - pattern->property]]> - pattern->property]]> - pattern->unknownProperty]]> - options->getObject()->property]]> options->getObject()->property]]> @@ -906,40 +852,17 @@ getCommonPatternNamesProvider - - call - generateKey - getEventManager - - - getItem - setItem - getCommonPatternNamesProvider - - end - start - start - start - TestCachePattern - - - emptyMethod - - - emptyMethod - - emptyMethod @@ -1030,9 +953,6 @@ setCapabilities - - TtlStorage - @@ -1301,9 +1221,6 @@ clearExpired - - ClearExpiredMockAdapter - @@ -1311,9 +1228,6 @@ internalRemoveItem internalSetItem - - MockAdapter - @@ -1335,8 +1249,5 @@ optimize - - OptimizableMockAdapter - diff --git a/psalm.xml b/psalm.xml index f3f9362e..27c0ce71 100644 --- a/psalm.xml +++ b/psalm.xml @@ -13,6 +13,7 @@ + diff --git a/src/Storage/Adapter/AbstractAdapter.php b/src/Storage/Adapter/AbstractAdapter.php index 951feb17..e9d83a87 100644 --- a/src/Storage/Adapter/AbstractAdapter.php +++ b/src/Storage/Adapter/AbstractAdapter.php @@ -45,7 +45,7 @@ abstract class AbstractAdapter implements StorageInterface, PluginAwareInterface /** * The plugin registry * - * @var SplObjectStorage Registered plugins + * @var SplObjectStorage|null Registered plugins */ protected $pluginRegistry; diff --git a/test/Pattern/AbstractCommonStoragePatternTest.php b/test/Pattern/AbstractCommonStoragePatternTest.php index 7c55455b..586330b0 100644 --- a/test/Pattern/AbstractCommonStoragePatternTest.php +++ b/test/Pattern/AbstractCommonStoragePatternTest.php @@ -7,18 +7,20 @@ use Laminas\Cache\Pattern\PatternInterface; use Laminas\Cache\Pattern\StorageCapableInterface; use Laminas\Cache\Storage\StorageInterface; +use PHPUnit\Framework\MockObject\MockObject; use function sprintf; /** * @psalm-suppress MissingConstructor + * @template TPattern of PatternInterface&StorageCapableInterface */ abstract class AbstractCommonStoragePatternTest extends AbstractCommonPatternTest { - /** @var StorageInterface */ + /** @var StorageInterface&MockObject */ protected $storage; - /** @var PatternInterface&StorageCapableInterface */ + /** @var TPattern */ protected $pattern; protected function setUp(): void diff --git a/test/Pattern/CallbackCacheTest.php b/test/Pattern/CallbackCacheTest.php index 95e53f90..a6c8fd93 100644 --- a/test/Pattern/CallbackCacheTest.php +++ b/test/Pattern/CallbackCacheTest.php @@ -4,8 +4,8 @@ namespace LaminasTest\Cache\Pattern; -use Laminas\Cache; -use Laminas\Cache\Exception\InvalidArgumentException; +use Laminas\Cache\Pattern\CallbackCache; +use Laminas\Cache\Storage\StorageInterface; use LaminasTest\Cache\Pattern\TestAsset\FailableCallback; use LaminasTest\Cache\Pattern\TestAsset\TestCallbackCache; @@ -26,16 +26,15 @@ function bar(): string /** * @group Laminas_Cache + * @template-extends AbstractCommonStoragePatternTest */ class CallbackCacheTest extends AbstractCommonStoragePatternTest { protected function setUp(): void { - $this->storage = new Cache\Storage\Adapter\Memory([ - 'memory_limit' => 0, - ]); + $this->storage = $this->createMock(StorageInterface::class); - $this->pattern = new Cache\Pattern\CallbackCache($this->storage); + $this->pattern = new CallbackCache($this->storage); parent::setUp(); } @@ -80,40 +79,36 @@ public function testGenerateKey(): void $args = ['arg1', 2, 3.33, null]; $generatedKey = $this->pattern->generateKey($callback, $args); - $usedKey = null; - $this->storage->getEventManager()->attach('setItem.pre', static function ($event) use (&$usedKey): void { - $params = $event->getParams(); - $usedKey = $params['key']; - }); - $this->pattern->call($callback, $args); - self::assertEquals($generatedKey, $usedKey); - } + $this->storage + ->expects(self::once()) + ->method('getItem') + ->with($generatedKey, null) + ->willReturn(null); - public function testCallInvalidCallbackException(): void - { - $this->expectException(InvalidArgumentException::class); - $this->pattern->call(1); - } + $this->storage + ->expects(self::once()) + ->method('setItem') + ->with($generatedKey, self::anything()) + ->willReturn(true); - public function testCallUnknownCallbackException(): void - { - $this->expectException(InvalidArgumentException::class); - $this->pattern->call('notExiststingFunction'); + $this->pattern->call($callback, $args); } /** * Running tests calling {@see \LaminasTest\Cache\Pattern\TestCallbackCache::bar} * using different callbacks resulting in this method call * - * @param callable $callback + * @param callable():string $callback + * @param array $args */ - protected function executeCallbackAndMakeAssertions($callback, array $args): void + protected function executeCallbackAndMakeAssertions(callable $callback, array $args): void { - /** @psalm-suppress MixedArgumentTypeCoercion */ - $imploded = implode(', ', $args); - $returnSpec = 'foobar_return(' . $imploded . ') : '; - $outputSpec = 'foobar_output(' . $imploded . ') : '; + $options = $this->pattern->getOptions(); + $cacheOutput = $options->getCacheOutput(); + $imploded = implode(', ', $args); + $returnSpec = 'foobar_return(' . $imploded . ') : '; + $outputSpec = 'foobar_output(' . $imploded . ') : '; // first call - not cached $firstCounter = TestCallbackCache::$fooCounter + 1; @@ -121,13 +116,45 @@ protected function executeCallbackAndMakeAssertions($callback, array $args): voi ob_start(); ob_implicit_flush(false); + $expectedKey = $this->pattern->generateKey($callback, $args); + $this->storage + ->expects(self::exactly(2)) + ->method('getItem') + ->with($expectedKey, null) + ->willReturnCallback( + function ( + string $key, + bool|null &$success = null + ) use ( + $returnSpec, + $outputSpec, + $firstCounter, + $cacheOutput, + ): ?array { + static $called = false; + if ($called === true) { + $success = true; + + $cached = [$returnSpec . $firstCounter]; + if ($cacheOutput) { + $cached[] = $outputSpec . $firstCounter; + } + + return $cached; + } + + $called = true; + return null; + } + ); + $return = $this->pattern->call($callback, $args); $data = ob_get_clean(); self::assertEquals($returnSpec . $firstCounter, $return); self::assertEquals($outputSpec . $firstCounter, $data); - // second call - cached + // second call - "cached" ob_start(); ob_implicit_flush(false); @@ -135,8 +162,7 @@ protected function executeCallbackAndMakeAssertions($callback, array $args): voi $data = ob_get_clean(); self::assertEquals($returnSpec . $firstCounter, $return); - $options = $this->pattern->getOptions(); - if ($options->getCacheOutput()) { + if ($cacheOutput) { self::assertEquals($outputSpec . $firstCounter, $data); } else { self::assertEquals('', $data); @@ -150,7 +176,15 @@ public function testCallCanReturnCachedNullValues(): void { $callback = new FailableCallback(); $key = $this->pattern->generateKey($callback, []); - $this->storage->setItem($key, [null]); + $this->storage + ->expects(self::once()) + ->method('getItem') + ->with($key, null) + ->willReturnCallback(function (string $key, ?bool &$success = null): array { + $success = true; + return [null]; + }); + $value = $this->pattern->call($callback); self::assertNull($value); } diff --git a/test/Pattern/ObjectCacheTest.php b/test/Pattern/ObjectCacheTest.php index 809c5a41..c1e0772c 100644 --- a/test/Pattern/ObjectCacheTest.php +++ b/test/Pattern/ObjectCacheTest.php @@ -5,7 +5,9 @@ namespace LaminasTest\Cache\Pattern; use Laminas\Cache; +use Laminas\Cache\Pattern\ObjectCache; use Laminas\Cache\Pattern\PatternOptions; +use Laminas\Cache\Storage\StorageInterface; use LaminasTest\Cache\Pattern\TestAsset\TestObjectCache; use function implode; @@ -16,6 +18,7 @@ /** * @group Laminas_Cache + * @template-extends AbstractCommonStoragePatternTest */ class ObjectCacheTest extends AbstractCommonStoragePatternTest { @@ -24,13 +27,11 @@ class ObjectCacheTest extends AbstractCommonStoragePatternTest protected function setUp(): void { - $this->storage = new Cache\Storage\Adapter\Memory([ - 'memory_limit' => 0, - ]); + $this->storage = $this->createMock(StorageInterface::class); $this->options = new Cache\Pattern\PatternOptions([ 'object' => new TestObjectCache(), ]); - $this->pattern = new Cache\Pattern\ObjectCache($this->storage, $this->options); + $this->pattern = new ObjectCache($this->storage, $this->options); parent::setUp(); } @@ -71,14 +72,20 @@ public function testGenerateKey(): void $args = ['arg1', 2, 3.33, null]; $generatedKey = $this->pattern->generateKey('emptyMethod', $args); - $usedKey = null; - $this->storage->getEventManager()->attach('setItem.pre', static function ($event) use (&$usedKey): void { - $params = $event->getParams(); - $usedKey = $params['key']; - }); + + $this->storage + ->expects(self::once()) + ->method('getItem') + ->with($generatedKey, null) + ->willReturn(null); + + $this->storage + ->expects(self::once()) + ->method('setItem') + ->with($generatedKey, self::anything()) + ->willReturn(true); $this->pattern->call('emptyMethod', $args); - self::assertEquals($generatedKey, $usedKey); } public function testSetProperty(): void @@ -119,17 +126,53 @@ public function testEmptyObjectKeys(): void self::assertSame($this->options->getObject()::class, $this->options->getObjectKey()); } + /** + * @param array $args + */ protected function executeMethodAndMakeAssertions(string $method, array $args): void { - /** @psalm-suppress MixedArgumentTypeCoercion */ - $imploded = implode(', ', $args); - $returnSpec = 'foobar_return(' . $imploded . ') : '; - $outputSpec = 'foobar_output(' . $imploded . ') : '; - $callback = [$this->pattern, $method]; + $options = $this->pattern->getOptions(); + $cacheOutput = $options->getCacheOutput(); + $imploded = implode(', ', $args); + $returnSpec = 'foobar_return(' . $imploded . ') : '; + $outputSpec = 'foobar_output(' . $imploded . ') : '; + $callback = [$this->pattern, $method]; // first call - not cached $firstCounter = TestObjectCache::$fooCounter + 1; + $expectedKey = $this->pattern->generateKey($method, $args); + $this->storage + ->expects(self::exactly(2)) + ->method('getItem') + ->with($expectedKey, null) + ->willReturnCallback( + function ( + string $key, + bool|null &$success = null + ) use ( + $returnSpec, + $outputSpec, + $firstCounter, + $cacheOutput, + ): ?array { + static $called = false; + if ($called === true) { + $success = true; + + $cached = [$returnSpec . $firstCounter]; + if ($cacheOutput) { + $cached[] = $outputSpec . $firstCounter; + } + + return $cached; + } + + $called = true; + return null; + } + ); + ob_start(); ob_implicit_flush(false); @@ -149,7 +192,7 @@ protected function executeMethodAndMakeAssertions(string $method, array $args): ob_end_clean(); self::assertEquals($returnSpec . $firstCounter, $return); - if ($this->options->getCacheOutput()) { + if ($cacheOutput) { self::assertEquals($outputSpec . $firstCounter, $data); } else { self::assertEquals('', $data); diff --git a/test/Pattern/OutputCacheTest.php b/test/Pattern/OutputCacheTest.php index a2724fa3..0c468f91 100644 --- a/test/Pattern/OutputCacheTest.php +++ b/test/Pattern/OutputCacheTest.php @@ -4,8 +4,9 @@ namespace LaminasTest\Cache\Pattern; -use Laminas\Cache; use Laminas\Cache\Exception\MissingKeyException; +use Laminas\Cache\Pattern\OutputCache; +use Laminas\Cache\Storage\StorageInterface; use function ob_end_clean; use function ob_get_clean; @@ -15,6 +16,7 @@ /** * @group Laminas_Cache * @covers \Laminas\Cache\Pattern\OutputCache + * @template-extends AbstractCommonStoragePatternTest */ class OutputCacheTest extends AbstractCommonStoragePatternTest { @@ -27,11 +29,9 @@ class OutputCacheTest extends AbstractCommonStoragePatternTest public function setUp(): void { - $this->storage = new Cache\Storage\Adapter\Memory([ - 'memory_limit' => 0, - ]); + $this->storage = $this->createMock(StorageInterface::class); - $this->pattern = new Cache\Pattern\OutputCache($this->storage); + $this->pattern = new OutputCache($this->storage); // used to reset the level on tearDown $this->obLevel = ob_get_level(); @@ -69,6 +69,12 @@ public function testStartEndCacheMiss(): void $output = 'foobar'; $key = 'testStartEndCacheMiss'; + $this->storage + ->expects(self::once()) + ->method('setItem') + ->with($key, $output) + ->willReturn(true); + ob_start(); self::assertFalse($this->pattern->start($key)); echo $output; @@ -76,7 +82,6 @@ public function testStartEndCacheMiss(): void $data = ob_get_clean(); self::assertEquals($output, $data); - self::assertEquals($output, $this->pattern->getStorage()->getItem($key)); } public function testStartEndCacheHit(): void @@ -84,9 +89,18 @@ public function testStartEndCacheHit(): void $output = 'foobar'; $key = 'testStartEndCacheHit'; - // fill cache - $storage = $this->pattern->getStorage(); - $storage->setItem($key, $output); + $this->storage + ->expects(self::never()) + ->method('setItem'); + + $this->storage + ->expects(self::once()) + ->method('getItem') + ->with($key, null) + ->willReturnCallback(function (string $key, ?bool &$success = null) use ($output): string { + $success = true; + return $output; + }); ob_start(); self::assertTrue($this->pattern->start($key)); diff --git a/test/Pattern/TestAsset/TestCallbackCache.php b/test/Pattern/TestAsset/TestCallbackCache.php index 565b99ee..8e1abbba 100644 --- a/test/Pattern/TestAsset/TestCallbackCache.php +++ b/test/Pattern/TestAsset/TestCallbackCache.php @@ -14,10 +14,8 @@ final class TestCallbackCache { /** * A counter how oftern the method "foo" was called - * - * @var int */ - public static $fooCounter = 0; + public static int $fooCounter = 0; public static function bar(): string { @@ -30,7 +28,7 @@ public static function bar(): string return 'foobar_return(' . $imploded . ') : ' . static::$fooCounter; } - public static function emptyMethod() + public static function emptyMethod(): void { } } diff --git a/test/Psr/CacheItemPool/CacheItemPoolIntegrationTest.php b/test/Psr/CacheItemPool/CacheItemPoolIntegrationTest.php deleted file mode 100644 index 0b3e5510..00000000 --- a/test/Psr/CacheItemPool/CacheItemPoolIntegrationTest.php +++ /dev/null @@ -1,22 +0,0 @@ -addPlugin($serializer); - - return $storage; - } -} diff --git a/test/Psr/SimpleCache/SimpleCacheIntegrationTest.php b/test/Psr/SimpleCache/SimpleCacheIntegrationTest.php deleted file mode 100644 index 2a14c579..00000000 --- a/test/Psr/SimpleCache/SimpleCacheIntegrationTest.php +++ /dev/null @@ -1,22 +0,0 @@ -addPlugin($serializer); - - return $storage; - } -} diff --git a/test/StaticAnalysis/AdapterPluginManagerTypes.php b/test/StaticAnalysis/AdapterPluginManagerTypes.php index 4aa3ec9f..b2e9d150 100644 --- a/test/StaticAnalysis/AdapterPluginManagerTypes.php +++ b/test/StaticAnalysis/AdapterPluginManagerTypes.php @@ -4,7 +4,7 @@ namespace LaminasTest\Cache\StaticAnalysis; -use Laminas\Cache\Storage\Adapter\Memory; +use Laminas\Cache\Storage\Adapter\Dev\VoidAdapter; use Laminas\Cache\Storage\AdapterPluginManager; use Laminas\Cache\Storage\StorageInterface; @@ -12,7 +12,7 @@ final class AdapterPluginManagerTypes { public function willReturnAnAdapterUsingFQCN(AdapterPluginManager $manager): StorageInterface { - return $manager->get(Memory::class); + return $manager->get(VoidAdapter::class); } public function validateWillAssertInstanceType(AdapterPluginManager $manager, object $instance): StorageInterface @@ -24,6 +24,6 @@ public function validateWillAssertInstanceType(AdapterPluginManager $manager, ob public function buildWillReturnAdapterUsingFQCN(AdapterPluginManager $manager): StorageInterface { - return $manager->build(Memory::class); + return $manager->build(VoidAdapter::class); } } diff --git a/test/Storage/CapabilitiesTest.php b/test/Storage/CapabilitiesTest.php index 25c32b84..c3f3c334 100644 --- a/test/Storage/CapabilitiesTest.php +++ b/test/Storage/CapabilitiesTest.php @@ -4,7 +4,7 @@ namespace LaminasTest\Cache\Storage; -use Laminas\Cache\Storage\Adapter\Memory as MemoryAdapter; +use Laminas\Cache\Storage\Adapter\Dev\VoidAdapter; use Laminas\Cache\Storage\Capabilities; use Laminas\EventManager\Event; use PHPUnit\Framework\TestCase; @@ -40,14 +40,14 @@ class CapabilitiesTest extends TestCase /** * The storage adapter * - * @var MemoryAdapter + * @var VoidAdapter */ protected $adapter; public function setUp(): void { $this->marker = new stdClass(); - $this->adapter = new MemoryAdapter(); + $this->adapter = new VoidAdapter(); $this->baseCapabilities = new Capabilities($this->adapter, $this->marker); $this->capabilities = new Capabilities($this->adapter, $this->marker, [], $this->baseCapabilities); From 6a08ab0b78d0c4b7bfc9e441a2fea167b3c1a5d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maximilian=20B=C3=B6sing?= <2189546+boesing@users.noreply.github.com> Date: Sun, 27 Aug 2023 01:23:04 +0200 Subject: [PATCH 2/3] feature: introduce `MetadataCapableInterface` MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This provides a way for storage adapters to provide properly typed metadata objects. Signed-off-by: Maximilian Bösing <2189546+boesing@users.noreply.github.com> --- psalm-baseline.xml | 181 +---------- psalm.xml | 1 + .../CacheItemPool/CacheItemPoolDecorator.php | 3 +- src/Psr/SimpleCache/SimpleCacheDecorator.php | 1 - .../AbstractMetadataCapableAdapter.php | 136 +++++++++ src/Storage/Adapter/AbstractAdapter.php | 104 ------- src/Storage/Adapter/KeyListIterator.php | 4 - src/Storage/Capabilities.php | 37 --- src/Storage/IteratorInterface.php | 7 +- src/Storage/MetadataCapableInterface.php | 30 ++ src/Storage/PluginManager.php | 4 +- src/Storage/StorageInterface.php | 17 -- .../StaticAnalysis/MetadataCapableAdapter.php | 62 ++++ test/Storage/Adapter/AbstractAdapterTest.php | 180 +---------- .../AbstractMetadataCapableAdapterTest.php | 287 ++++++++++++++++++ 15 files changed, 532 insertions(+), 522 deletions(-) create mode 100644 src/Storage/AbstractMetadataCapableAdapter.php create mode 100644 src/Storage/MetadataCapableInterface.php create mode 100644 test/StaticAnalysis/MetadataCapableAdapter.php create mode 100644 test/Storage/Adapter/AbstractMetadataCapableAdapterTest.php diff --git a/psalm-baseline.xml b/psalm-baseline.xml index 4552f87e..ca1f995c 100644 --- a/psalm-baseline.xml +++ b/psalm-baseline.xml @@ -5,13 +5,6 @@ $cacheConfiguration $configuration - - $cache - $cacheConfiguration - $caches - $caches - $configuration - $projectConfiguration @@ -66,11 +59,6 @@ $result[0] $result[1] - - $object - $result - $ret - __call @@ -126,13 +114,6 @@ $property $property - - $property - $property - $property - $property - $value - bool void @@ -164,10 +145,6 @@ $data $key - - $data - $key - (string) $key @@ -212,12 +189,6 @@ validateKeys validateStorage - - $cleared - $key - $value - $value - flush @@ -230,14 +201,6 @@ $key $key - - $key - $key - $result - $result - $results[$key] - $value - $ttl $ttl @@ -311,7 +274,6 @@ $normalizedKey $normalizedKey $normalizedKey - $normalizedKey $value $value @@ -323,50 +285,6 @@ $normalizedKey $normalizedKey - - $handle - $normalizedKey - $normalizedKey - $normalizedKey - $normalizedKey - $normalizedKey - $normalizedKeyValuePairs[$key] - $oldValue - $result - $result - $result - $result - $result - $result - $result - $result - $result - $result - $result - $result - $result - $result - $result - $result - $result - $result - $result - $result - $result - $result - $result - $result - $result - $result[$normalizedKey] - $value - $value - $value - $value - $value - $value - $value - $value - AdapterOptions Capabilities @@ -379,8 +297,6 @@ array array array - array - array|bool bool bool bool @@ -419,10 +335,6 @@ triggerException(__FUNCTION__, $args, $result, $e)]]> triggerException(__FUNCTION__, $args, $result, $e)]]> triggerException(__FUNCTION__, $args, $result, $e)]]> - triggerException(__FUNCTION__, $args, $result, $e)]]> - triggerException(__FUNCTION__, $args, $result, $e)]]> - triggerPost(__FUNCTION__, $args, $result)]]> - triggerPost(__FUNCTION__, $args, $result)]]> triggerPost(__FUNCTION__, $args, $result)]]> triggerPost(__FUNCTION__, $args, $result)]]> triggerPost(__FUNCTION__, $args, $result)]]> @@ -481,12 +393,6 @@ $letter $letters - - $array[$normalizedKey] - $key - $letter - $value - $this @@ -513,18 +419,10 @@ - - is_string($name) - $name - - $toType - $value - - array array bool bool @@ -554,14 +452,12 @@ 'object' => false, 'resource' => false, ])]]> - getCapability('supportedMetadata', [])]]> getCapability('ttlPrecision', 1)]]> getCapability('useRequestTime', false)]]> getNamespaceIsPrefix getNamespaceSeparator - getSupportedMetadata getTtlPrecision setLockOnExpire setMaxKeyLength @@ -570,7 +466,6 @@ setNamespaceSeparator setStaticTtl setSupportedDatatypes - setSupportedMetadata setTtlPrecision setUseRequestTime @@ -583,7 +478,6 @@ $namespaceSeparator $staticTtl $supportedDatatypes - $supportedMetadata $ttlPrecision $useRequestTime @@ -641,6 +535,11 @@ setMode + + + getMetadata + + bool @@ -670,9 +569,6 @@ SerializerAdapter - - serializerOptions]]> - setExitOnAbort setOptimizingFactor @@ -711,29 +607,6 @@ $keyValuePairs[$key] $keyValuePairs[$key] - - $baseCapabilities - $failedKey - $failedKey - $key - $key - $keyValuePairs[$key] - $keyValuePairs[$key] - $keyValuePairs[$key] - $keyValuePairs[$key] - $newValue - $newValue - $oldValue - $oldValue - $result - $result - $result - $value - $value - $value - $value - $value - getAdapter @@ -809,10 +682,6 @@ - - $return - $return - getCommonPatternNamesProvider @@ -841,10 +710,6 @@ - - $return - $return - options->getObject()->property]]> options->getObject()->property]]> @@ -891,11 +756,6 @@ $key $key - - $item - $item - $item - get get @@ -988,32 +848,11 @@ - - $event - - - static function ($event) use ($retVal) { - $success - - $eventList[] - $eventList[] - $eventList[] - - - $result - $result - $rs - $v - - - array - getResult - stopPropagation null @@ -1033,6 +872,9 @@ $success + + simpleEventHandlingMethodDefinitions + @@ -1079,10 +921,6 @@ $eventArg - - $em - $event - attach @@ -1202,9 +1040,6 @@ - - $values - onDecrementItemPre onReadItemPost diff --git a/psalm.xml b/psalm.xml index 27c0ce71..3b13db86 100644 --- a/psalm.xml +++ b/psalm.xml @@ -19,6 +19,7 @@ + diff --git a/src/Psr/CacheItemPool/CacheItemPoolDecorator.php b/src/Psr/CacheItemPool/CacheItemPoolDecorator.php index 12cdddaf..e3b32f31 100644 --- a/src/Psr/CacheItemPool/CacheItemPoolDecorator.php +++ b/src/Psr/CacheItemPool/CacheItemPoolDecorator.php @@ -417,8 +417,7 @@ private function saveMultipleItems(array $items, ?int $itemTtl): array $keyValuePair = []; foreach ($items as $item) { - $key = $item->getKey(); - /** @psalm-suppress MixedAssignment */ + $key = $item->getKey(); $keyValuePair[$key] = $item->get(); } diff --git a/src/Psr/SimpleCache/SimpleCacheDecorator.php b/src/Psr/SimpleCache/SimpleCacheDecorator.php index 20d0eb48..7d945363 100644 --- a/src/Psr/SimpleCache/SimpleCacheDecorator.php +++ b/src/Psr/SimpleCache/SimpleCacheDecorator.php @@ -442,7 +442,6 @@ private function convertIterableToKeyValueMap(iterable $values): array $this->validateKey($key); - /** @psalm-suppress MixedAssignment */ $keyValueMap[$key] = $value; } diff --git a/src/Storage/AbstractMetadataCapableAdapter.php b/src/Storage/AbstractMetadataCapableAdapter.php new file mode 100644 index 00000000..6971dd7e --- /dev/null +++ b/src/Storage/AbstractMetadataCapableAdapter.php @@ -0,0 +1,136 @@ + + */ +abstract class AbstractMetadataCapableAdapter extends AbstractAdapter implements MetadataCapableInterface +{ + public function getMetadata(string $key): ?object + { + if (! $this->getOptions()->getReadable()) { + return null; + } + + $this->normalizeKey($key); + $args = new ArrayObject([ + 'key' => &$key, + ]); + + try { + $eventRs = $this->triggerPre(__FUNCTION__, $args); + Assert::string($args['key']); + + $result = $eventRs->stopped() + ? $eventRs->last() + : $this->internalGetMetadata($args['key']); + + $result = $this->triggerPost(__FUNCTION__, $args, $result); + if ($result !== null && ! is_object($result)) { + return null; + } + + /** + * NOTE: We do trust the event handling here and assume that it will return an instance of Metadata + * and thus does not modify the type. + * + * @var TMetadata|null $result + */ + return $result; + } catch (Exception $exception) { + $result = null; + $result = $this->triggerException(__FUNCTION__, $args, $result, $exception); + Assert::null($result); + + return $result; + } + } + + /** + * Internal method to get metadata of an item. + * + * @return TMetadata|null Metadata on success, null on failure or in case metadata is not accessible. + * @throws ExceptionInterface + */ + abstract protected function internalGetMetadata(string $normalizedKey): ?object; + + public function getMetadatas(array $keys): array + { + if (! $this->getOptions()->getReadable()) { + return []; + } + + $this->normalizeKeys($keys); + $args = new ArrayObject([ + 'keys' => &$keys, + ]); + + try { + $eventRs = $this->triggerPre(__FUNCTION__, $args); + Assert::isArray($args['keys']); + Assert::allString($args['keys']); + + $result = $eventRs->stopped() + ? $eventRs->last() + : $this->internalGetMetadatas($args['keys']); + + if (! is_array($result)) { + return []; + } + + $result = $this->triggerPost(__FUNCTION__, $args, $result); + Assert::isMap($result); + Assert::allObject($result); + + /** + * NOTE: We do trust the event handling here and assume that it will return a map of instances of Metadata + * and thus does not modify the type. + * + * @var array $result + */ + return $result; + } catch (Exception $exception) { + $result = []; + $result = $this->triggerException(__FUNCTION__, $args, $result, $exception); + Assert::isArray($result); + Assert::isEmpty($result); + + return $result; + } + } + + /** + * Internal method to get multiple metadata + * + * @param array $normalizedKeys + * @return array Associative array of keys and metadata + * @throws ExceptionInterface + */ + protected function internalGetMetadatas(array $normalizedKeys): array + { + $result = []; + foreach ($normalizedKeys as $normalizedKey) { + $metadata = $this->internalGetMetadata($normalizedKey); + if ($metadata === null) { + continue; + } + + $result[$normalizedKey] = $metadata; + } + + return $result; + } +} diff --git a/src/Storage/Adapter/AbstractAdapter.php b/src/Storage/Adapter/AbstractAdapter.php index e9d83a87..1c632a33 100644 --- a/src/Storage/Adapter/AbstractAdapter.php +++ b/src/Storage/Adapter/AbstractAdapter.php @@ -527,110 +527,6 @@ protected function internalHasItems(array &$normalizedKeys) return $result; } - /** - * Get metadata of an item. - * - * @param string $key - * @return array|bool Metadata on success, false on failure - * @throws Exception\ExceptionInterface - * @triggers getMetadata.pre(PreEvent) - * @triggers getMetadata.post(PostEvent) - * @triggers getMetadata.exception(ExceptionEvent) - */ - public function getMetadata($key) - { - if (! $this->getOptions()->getReadable()) { - return false; - } - - $this->normalizeKey($key); - $args = new ArrayObject([ - 'key' => &$key, - ]); - - try { - $eventRs = $this->triggerPre(__FUNCTION__, $args); - - $result = $eventRs->stopped() - ? $eventRs->last() - : $this->internalGetMetadata($args['key']); - - return $this->triggerPost(__FUNCTION__, $args, $result); - } catch (\Exception $e) { - $result = false; - return $this->triggerException(__FUNCTION__, $args, $result, $e); - } - } - - /** - * Internal method to get metadata of an item. - * - * @param string $normalizedKey - * @return array|bool Metadata on success, false on failure - * @throws Exception\ExceptionInterface - */ - protected function internalGetMetadata(&$normalizedKey) - { - if (! $this->internalHasItem($normalizedKey)) { - return false; - } - - return []; - } - - /** - * Get multiple metadata - * - * @param array $keys - * @return array Associative array of keys and metadata - * @throws Exception\ExceptionInterface - * @triggers getMetadatas.pre(PreEvent) - * @triggers getMetadatas.post(PostEvent) - * @triggers getMetadatas.exception(ExceptionEvent) - */ - public function getMetadatas(array $keys) - { - if (! $this->getOptions()->getReadable()) { - return []; - } - - $this->normalizeKeys($keys); - $args = new ArrayObject([ - 'keys' => &$keys, - ]); - - try { - $eventRs = $this->triggerPre(__FUNCTION__, $args); - - $result = $eventRs->stopped() - ? $eventRs->last() - : $this->internalGetMetadatas($args['keys']); - - return $this->triggerPost(__FUNCTION__, $args, $result); - } catch (\Exception $e) { - $result = []; - return $this->triggerException(__FUNCTION__, $args, $result, $e); - } - } - - /** - * Internal method to get multiple metadata - * - * @return array Associative array of keys and metadata - * @throws Exception\ExceptionInterface - */ - protected function internalGetMetadatas(array &$normalizedKeys) - { - $result = []; - foreach ($normalizedKeys as $normalizedKey) { - $metadata = $this->internalGetMetadata($normalizedKey); - if ($metadata !== false) { - $result[$normalizedKey] = $metadata; - } - } - return $result; - } - /* writing */ /** diff --git a/src/Storage/Adapter/KeyListIterator.php b/src/Storage/Adapter/KeyListIterator.php index c62cf1df..41b35774 100644 --- a/src/Storage/Adapter/KeyListIterator.php +++ b/src/Storage/Adapter/KeyListIterator.php @@ -96,10 +96,6 @@ public function current() $key = $this->key(); - if ($this->mode === IteratorInterface::CURRENT_AS_METADATA) { - return $this->storage->getMetadata($key); - } - if ($this->mode === IteratorInterface::CURRENT_AS_VALUE) { return $this->storage->getItem($key); } diff --git a/src/Storage/Capabilities.php b/src/Storage/Capabilities.php index 5682062b..82844dd6 100644 --- a/src/Storage/Capabilities.php +++ b/src/Storage/Capabilities.php @@ -102,16 +102,6 @@ class Capabilities */ protected $supportedDatatypes; - /** - * Supported metadata - * - * If it's NULL the capability isn't set and the getter - * returns the base capability or the default value. - * - * @var null|array - */ - protected $supportedMetadata; - /** * TTL precision * @@ -222,33 +212,6 @@ public function setSupportedDatatypes(stdClass $marker, array $datatypes) return $this->setCapability($marker, 'supportedDatatypes', $datatypes); } - /** - * Get supported metadata - * - * @return array - */ - public function getSupportedMetadata() - { - return $this->getCapability('supportedMetadata', []); - } - - /** - * Set supported metadata - * - * @param string[] $metadata - * @throws Exception\InvalidArgumentException - * @return Capabilities Fluent interface - */ - public function setSupportedMetadata(stdClass $marker, array $metadata) - { - foreach ($metadata as $name) { - if (! is_string($name)) { - throw new Exception\InvalidArgumentException('$metadata must be an array of strings'); - } - } - return $this->setCapability($marker, 'supportedMetadata', $metadata); - } - /** * Get minimum supported time-to-live * diff --git a/src/Storage/IteratorInterface.php b/src/Storage/IteratorInterface.php index 386e865e..69d11796 100644 --- a/src/Storage/IteratorInterface.php +++ b/src/Storage/IteratorInterface.php @@ -11,10 +11,9 @@ */ interface IteratorInterface extends Iterator { - public const CURRENT_AS_SELF = 0; - public const CURRENT_AS_KEY = 1; - public const CURRENT_AS_VALUE = 2; - public const CURRENT_AS_METADATA = 3; + public const CURRENT_AS_SELF = 0; + public const CURRENT_AS_KEY = 1; + public const CURRENT_AS_VALUE = 2; /** * Get storage instance diff --git a/src/Storage/MetadataCapableInterface.php b/src/Storage/MetadataCapableInterface.php new file mode 100644 index 00000000..664e1590 --- /dev/null +++ b/src/Storage/MetadataCapableInterface.php @@ -0,0 +1,30 @@ + $keys + * @return array Associative array of keys and metadata + * @throws ExceptionInterface + */ + public function getMetadatas(array $keys): array; +} diff --git a/src/Storage/PluginManager.php b/src/Storage/PluginManager.php index 4cb033e9..916773e8 100644 --- a/src/Storage/PluginManager.php +++ b/src/Storage/PluginManager.php @@ -15,7 +15,6 @@ * plugins available. * * @extends AbstractPluginManager - * @final */ final class PluginManager extends AbstractPluginManager { @@ -64,8 +63,7 @@ final class PluginManager extends AbstractPluginManager public function build($name, ?array $options = null) { $options ??= []; - /** @psalm-suppress MixedAssignment */ - $plugin = parent::build($name); + $plugin = parent::build($name); if ($options !== [] && $plugin instanceof PluginInterface) { $plugin->setOptions(new PluginOptions($options)); } diff --git a/src/Storage/StorageInterface.php b/src/Storage/StorageInterface.php index a22a8bfa..518ed855 100644 --- a/src/Storage/StorageInterface.php +++ b/src/Storage/StorageInterface.php @@ -58,23 +58,6 @@ public function hasItem($key); */ public function hasItems(array $keys); - /** - * Get metadata of an item. - * - * @param string $key - * @return array|bool Metadata on success, false on failure - * @throws ExceptionInterface - */ - public function getMetadata($key); - - /** - * Get multiple metadata - * - * @return array Associative array of keys and metadata - * @throws ExceptionInterface - */ - public function getMetadatas(array $keys); - /* writing */ /** * Store an item. diff --git a/test/StaticAnalysis/MetadataCapableAdapter.php b/test/StaticAnalysis/MetadataCapableAdapter.php new file mode 100644 index 00000000..2b2e0c27 --- /dev/null +++ b/test/StaticAnalysis/MetadataCapableAdapter.php @@ -0,0 +1,62 @@ + + */ +final class MetadataCapableAdapter extends AbstractMetadataCapableAdapter +{ + /** + * {@inheritDoc} + */ + protected function internalHasItem(&$normalizedKey) + { + return true; + } + + /** + * {@inheritDoc} + */ + protected function internalGetItem(&$normalizedKey, &$success = null, mixed &$casToken = null) + { + return null; + } + + /** + * {@inheritDoc} + */ + protected function internalSetItem(&$normalizedKey, mixed &$value) + { + return false; + } + + /** + * {@inheritDoc} + */ + protected function internalRemoveItem(&$normalizedKey) + { + return false; + } + + /** + * {@inheritDoc} + */ + protected function internalGetMetadata(string $normalizedKey): ?object + { + return null; + } +} + +$adapter = new MetadataCapableAdapter(); +$metadata = $adapter->getMetadata('foo'); + +if ($metadata === null) { + return; +} + +echo $metadata->meta; diff --git a/test/Storage/Adapter/AbstractAdapterTest.php b/test/Storage/Adapter/AbstractAdapterTest.php index 30ba7dbc..8b5c0fd4 100644 --- a/test/Storage/Adapter/AbstractAdapterTest.php +++ b/test/Storage/Adapter/AbstractAdapterTest.php @@ -24,7 +24,6 @@ use stdClass; use function array_keys; -use function array_map; use function array_merge; use function array_unique; use function assert; @@ -377,8 +376,6 @@ public function simpleEventHandlingMethodDefinitions(): array ['hasItems', 'internalHasItems', [['k1', 'k2']], ['v1', 'v2']], ['getItem', 'internalGetItem', ['k'], 'v'], ['getItems', 'internalGetItems', [['k1', 'k2']], ['k1' => 'v1', 'k2' => 'v2']], - ['getMetadata', 'internalGetMetadata', ['k'], []], - ['getMetadatas', 'internalGetMetadatas', [['k1', 'k2']], ['k1' => [], 'k2' => []]], ['setItem', 'internalSetItem', ['k', 'v'], true], ['setItems', 'internalSetItems', [['k1' => 'v1', 'k2' => 'v2']], []], ['replaceItem', 'internalReplaceItem', ['k', 'v'], true], @@ -398,161 +395,6 @@ public function simpleEventHandlingMethodDefinitions(): array ]; } - /** - * @psalm-param non-empty-string $methodName - * @psalm-param non-empty-string $internalMethodName - * @dataProvider simpleEventHandlingMethodDefinitions - */ - public function testEventHandlingSimple( - string $methodName, - string $internalMethodName, - array $methodArgs, - mixed $retVal - ): void { - $storage = $this->getMockForAbstractAdapter([$internalMethodName]); - - $eventList = []; - $eventHandler = static function (Event $event) use (&$eventList): void { - $eventList[] = $event->getName(); - }; - $eventManager = $storage->getEventManager(); - $eventManager->attach($methodName . '.pre', $eventHandler); - $eventManager->attach($methodName . '.post', $eventHandler); - $eventManager->attach($methodName . '.exception', $eventHandler); - - $storage - ->expects($this->once()) - ->method($internalMethodName) - ->with(...array_map([$this, 'equalTo'], $methodArgs)) - ->willReturn($retVal); - - call_user_func_array([$storage, $methodName], $methodArgs); - - $expectedEventList = [ - $methodName . '.pre', - $methodName . '.post', - ]; - - self::assertSame($expectedEventList, $eventList); - } - - /** - * @psalm-param non-empty-string $methodName - * @psalm-param non-empty-string $internalMethodName - * @dataProvider simpleEventHandlingMethodDefinitions - */ - public function testEventHandlingCatchException( - string $methodName, - string $internalMethodName, - array $methodArgs - ): void { - $storage = $this->getMockForAbstractAdapter([$internalMethodName]); - - $eventList = []; - $eventHandler = static function (Event $event) use (&$eventList): void { - $eventList[] = $event->getName(); - if ($event instanceof Cache\Storage\ExceptionEvent) { - $event->setThrowException(false); - } - }; - $eventManager = $storage->getEventManager(); - $eventManager->attach($methodName . '.pre', $eventHandler); - $eventManager->attach($methodName . '.post', $eventHandler); - $eventManager->attach($methodName . '.exception', $eventHandler); - - $storage - ->expects($this->once()) - ->method($internalMethodName) - ->with(...array_map([$this, 'equalTo'], $methodArgs)) - ->willThrowException(new \Exception('test')); - - call_user_func_array([$storage, $methodName], $methodArgs); - - $expectedEventList = [ - $methodName . '.pre', - $methodName . '.exception', - ]; - self::assertSame($expectedEventList, $eventList); - } - - /** - * @psalm-param non-empty-string $methodName - * @psalm-param non-empty-string $internalMethodName - * @dataProvider simpleEventHandlingMethodDefinitions - */ - public function testEventHandlingStopInPre( - string $methodName, - string $internalMethodName, - array $methodArgs, - mixed $retVal - ): void { - $storage = $this->getMockForAbstractAdapter([$internalMethodName]); - - $eventList = []; - $eventHandler = static function (Event $event) use (&$eventList): void { - $eventList[] = $event->getName(); - }; - $eventManager = $storage->getEventManager(); - $eventManager->attach($methodName . '.pre', $eventHandler); - $eventManager->attach($methodName . '.post', $eventHandler); - $eventManager->attach($methodName . '.exception', $eventHandler); - - $eventManager->attach($methodName . '.pre', static function ($event) use ($retVal) { - $event->stopPropagation(); - return $retVal; - }); - - // the internal method should never be called - $storage->expects($this->never())->method($internalMethodName); - - // the return vaue should be available by pre-event - $result = call_user_func_array([$storage, $methodName], $methodArgs); - self::assertSame($retVal, $result); - - // after the triggered pre-event the post-event should be triggered as well - $expectedEventList = [ - $methodName . '.pre', - $methodName . '.post', - ]; - self::assertSame($expectedEventList, $eventList); - } - - public function testGetMetadatas(): void - { - $storage = $this->getMockForAbstractAdapter(['getMetadata', 'internalGetMetadata']); - - $meta = ['meta' => 'data']; - $items = [ - 'key1' => $meta, - 'key2' => $meta, - ]; - - // foreach item call 'internalGetMetadata' instead of 'getMetadata' - $storage->expects($this->never())->method('getMetadata'); - $storage->expects($this->exactly(count($items))) - ->method('internalGetMetadata') - ->with($this->stringContains('key')) - ->willReturn($meta); - - self::assertSame($items, $storage->getMetadatas(array_keys($items))); - } - - public function testGetMetadatasFail(): void - { - $storage = $this->getMockForAbstractAdapter(['internalGetMetadata']); - - $items = ['key1', 'key2']; - - // return false to indicate that the operation failed - $storage - ->expects($this->exactly(count($items))) - ->method('internalGetMetadata') - ->with($this->stringContains('key')) - ->willReturn(false); - - self::assertSame([], $storage->getMetadatas($items)); - } - public function testSetItems(): void { $storage = $this->getMockForAbstractAdapter(['setItem', 'internalSetItem']); @@ -954,19 +796,6 @@ public function testPreEventsCanChangeArguments(): void 'keys' => ['changedKey'], ]); - // getMetadata(s) - $this->checkPreEventCanChangeArguments('getMetadata', [ - 'key' => 'key', - ], [ - 'key' => 'changedKey', - ]); - - $this->checkPreEventCanChangeArguments('getMetadatas', [ - 'keys' => ['key'], - ], [ - 'keys' => ['changedKey'], - ]); - // setItem(s) $this->checkPreEventCanChangeArguments('setItem', [ 'key' => 'key', @@ -1111,14 +940,11 @@ protected function checkPreEventCanChangeArguments(string $method, array $args, * Also sets the adapter options * * @psalm-param list $methods - * @return AbstractAdapter&MockObject */ - protected function getMockForAbstractAdapter(array $methods = []): AbstractAdapter + protected function getMockForAbstractAdapter(array $methods = []): MockObject&AbstractAdapter { - $class = AbstractAdapter::class; - if (! $methods) { - $adapter = $this->getMockForAbstractClass($class); + $adapter = $this->getMockForAbstractClass(AbstractAdapter::class); } else { $reflection = new ReflectionClass(AbstractAdapter::class); foreach ($reflection->getMethods() as $method) { @@ -1126,7 +952,7 @@ protected function getMockForAbstractAdapter(array $methods = []): AbstractAdapt $methods[] = $method->getName(); } } - $adapter = $this->getMockBuilder($class) + $adapter = $this->getMockBuilder(AbstractAdapter::class) ->onlyMethods(array_unique($methods)) ->disableArgumentCloning() ->getMock(); diff --git a/test/Storage/Adapter/AbstractMetadataCapableAdapterTest.php b/test/Storage/Adapter/AbstractMetadataCapableAdapterTest.php new file mode 100644 index 00000000..3af0775f --- /dev/null +++ b/test/Storage/Adapter/AbstractMetadataCapableAdapterTest.php @@ -0,0 +1,287 @@ +options = new AdapterOptions(); + } + + /** + * @return list + */ + public function simpleEventHandlingMethodDefinitions(): array + { + return [ + // name, internalName, args, returnValue + ['getMetadata', 'internalGetMetadata', ['k'], null], + ['getMetadatas', 'internalGetMetadatas', [['k1', 'k2']], []], + ]; + } + + /** + * Generates a mock of the abstract metadata capable storage adapter by mocking all abstract and the given methods + * Also sets the adapter options + * + * @psalm-param list $methods + */ + private function getMockForAbstractMetadataCapableAdapter( + array $methods = [] + ): MockObject&AbstractMetadataCapableAdapter { + if (! $methods) { + $adapter = $this->getMockForAbstractClass(AbstractMetadataCapableAdapter::class); + } else { + $reflection = new ReflectionClass(AbstractMetadataCapableAdapter::class); + foreach ($reflection->getMethods() as $method) { + if ($method->isAbstract()) { + $methods[] = $method->getName(); + } + } + $adapter = $this->getMockBuilder(AbstractMetadataCapableAdapter::class) + ->onlyMethods(array_unique($methods)) + ->disableArgumentCloning() + ->getMock(); + } + + $adapter->setOptions($this->options ?? new AdapterOptions()); + + return $adapter; + } + + /** + * @psalm-param non-empty-string $methodName + * @psalm-param non-empty-string $internalMethodName + * @dataProvider simpleEventHandlingMethodDefinitions + */ + public function testEventHandlingSimple( + string $methodName, + string $internalMethodName, + array $methodArgs, + mixed $retVal + ): void { + $storage = $this->getMockForAbstractMetadataCapableAdapter([$internalMethodName]); + + $eventList = []; + $eventHandler = static function (Event $event) use (&$eventList): void { + assert(is_array($eventList)); + $eventList[] = $event->getName(); + }; + $eventManager = $storage->getEventManager(); + $eventManager->attach($methodName . '.pre', $eventHandler); + $eventManager->attach($methodName . '.post', $eventHandler); + $eventManager->attach($methodName . '.exception', $eventHandler); + + $storage + ->expects($this->once()) + ->method($internalMethodName) + ->with(...array_map([$this, 'equalTo'], $methodArgs)) + ->willReturn($retVal); + + call_user_func_array([$storage, $methodName], $methodArgs); + + $expectedEventList = [ + $methodName . '.pre', + $methodName . '.post', + ]; + + self::assertSame($expectedEventList, $eventList); + } + + /** + * @psalm-param non-empty-string $methodName + * @psalm-param non-empty-string $internalMethodName + * @dataProvider simpleEventHandlingMethodDefinitions + */ + public function testEventHandlingCatchException( + string $methodName, + string $internalMethodName, + array $methodArgs + ): void { + $storage = $this->getMockForAbstractMetadataCapableAdapter([$internalMethodName]); + + $eventList = []; + $eventHandler = static function (Event $event) use (&$eventList): void { + assert(is_array($eventList)); + $eventList[] = $event->getName(); + if ($event instanceof Cache\Storage\ExceptionEvent) { + $event->setThrowException(false); + } + }; + $eventManager = $storage->getEventManager(); + $eventManager->attach($methodName . '.pre', $eventHandler); + $eventManager->attach($methodName . '.post', $eventHandler); + $eventManager->attach($methodName . '.exception', $eventHandler); + + $storage + ->expects($this->once()) + ->method($internalMethodName) + ->with(...array_map([self::class, 'equalTo'], $methodArgs)) + ->willThrowException(new Exception('test')); + + call_user_func_array([$storage, $methodName], $methodArgs); + + $expectedEventList = [ + $methodName . '.pre', + $methodName . '.exception', + ]; + self::assertSame($expectedEventList, $eventList); + } + + /** + * @psalm-param non-empty-string $methodName + * @psalm-param non-empty-string $internalMethodName + * @dataProvider simpleEventHandlingMethodDefinitions + */ + public function testEventHandlingStopInPre( + string $methodName, + string $internalMethodName, + array $methodArgs, + mixed $retVal + ): void { + $storage = $this->getMockForAbstractMetadataCapableAdapter([$internalMethodName]); + + $eventList = []; + $eventHandler = static function (Event $event) use (&$eventList): void { + assert(is_array($eventList)); + $eventList[] = $event->getName(); + }; + $eventManager = $storage->getEventManager(); + $eventManager->attach($methodName . '.pre', $eventHandler); + $eventManager->attach($methodName . '.post', $eventHandler); + $eventManager->attach($methodName . '.exception', $eventHandler); + + $eventManager->attach($methodName . '.pre', static function (EventInterface $event) use ($retVal): mixed { + $event->stopPropagation(); + return $retVal; + }); + + // the internal method should never be called + $storage->expects($this->never())->method($internalMethodName); + + // the return value should be available by pre-event + $result = call_user_func_array([$storage, $methodName], $methodArgs); + self::assertSame($retVal, $result); + + // after the triggered pre-event the post-event should be triggered as well + $expectedEventList = [ + $methodName . '.pre', + $methodName . '.post', + ]; + self::assertSame($expectedEventList, $eventList); + } + + public function testGetMetadatas(): void + { + $storage = $this->getMockForAbstractMetadataCapableAdapter(['getMetadata', 'internalGetMetadata']); + + $meta = new class { + public string $meta = 'data'; + }; + + $items = [ + 'key1' => $meta, + 'key2' => $meta, + ]; + + // foreach item call 'internalGetMetadata' instead of 'getMetadata' + $storage->expects($this->never())->method('getMetadata'); + $storage->expects($this->exactly(count($items))) + ->method('internalGetMetadata') + ->with($this->stringContains('key')) + ->willReturn($meta); + + self::assertSame($items, $storage->getMetadatas(array_keys($items))); + } + + public function testGetMetadatasFail(): void + { + $storage = $this->getMockForAbstractMetadataCapableAdapter(['internalGetMetadata']); + + $items = ['key1', 'key2']; + + // return false to indicate that the operation failed + $storage + ->expects($this->exactly(count($items))) + ->method('internalGetMetadata') + ->with($this->stringContains('key')) + ->willReturn(null); + + self::assertSame([], $storage->getMetadatas($items)); + } + + public function testFoo(): void + { + // getMetadata(s) + $this->checkPreEventCanChangeArguments('getMetadata', [ + 'key' => 'key', + ], [ + 'key' => 'changedKey', + ]); + + $this->checkPreEventCanChangeArguments('getMetadatas', [ + 'keys' => ['key'], + ], [ + 'keys' => ['changedKey'], + ]); + } + + /** + * @param non-empty-string $method + * @param array>|array $args + * @param array>|array $expectedArgs + */ + protected function checkPreEventCanChangeArguments(string $method, array $args, array $expectedArgs): void + { + $internalMethod = 'internal' . ucfirst($method); + $eventName = $method . '.pre'; + + // init mock + $storage = $this->getMockForAbstractMetadataCapableAdapter([$internalMethod]); + $storage->getEventManager()->attach($eventName, static function (Event $event) use ($expectedArgs): void { + $params = $event->getParams(); + $params->exchangeArray(array_merge($params->getArrayCopy(), $expectedArgs)); + }); + + // set expected arguments of internal method call + $tmp = $storage->expects($this->once())->method($internalMethod); + $equals = []; + foreach ($expectedArgs as $v) { + $equals[] = $this->equalTo($v); + } + call_user_func_array([$tmp, 'with'], $equals); + + // run + call_user_func_array([$storage, $method], $args); + } +} From d04ba8a4eb8cc25810e1db4cb9f7e426f473cb05 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maximilian=20B=C3=B6sing?= <2189546+boesing@users.noreply.github.com> Date: Sun, 27 Aug 2023 01:40:29 +0200 Subject: [PATCH 3/3] qa: apply changes to prevent psalm and codesniffer to yell at me MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Maximilian Bösing <2189546+boesing@users.noreply.github.com> --- psalm-baseline.xml | 5 ----- .../AbstractMetadataCapableAdapter.php | 19 ++++++++++++++++-- .../StaticAnalysis/MetadataCapableAdapter.php | 20 ++++++++++++------- 3 files changed, 30 insertions(+), 14 deletions(-) diff --git a/psalm-baseline.xml b/psalm-baseline.xml index ca1f995c..81a453f2 100644 --- a/psalm-baseline.xml +++ b/psalm-baseline.xml @@ -535,11 +535,6 @@ setMode - - - getMetadata - - bool diff --git a/src/Storage/AbstractMetadataCapableAdapter.php b/src/Storage/AbstractMetadataCapableAdapter.php index 6971dd7e..3e68ccca 100644 --- a/src/Storage/AbstractMetadataCapableAdapter.php +++ b/src/Storage/AbstractMetadataCapableAdapter.php @@ -1,5 +1,8 @@ triggerException(__FUNCTION__, $args, $result, $exception); - Assert::null($result); + Assert::nullOrObject($result); + /** + * NOTE: We do trust the event handling here and assume that it will return an instance of Metadata + * and thus does not modify the type. + * + * @var TMetadata|null $result + */ return $result; } } @@ -106,8 +115,14 @@ public function getMetadatas(array $keys): array $result = []; $result = $this->triggerException(__FUNCTION__, $args, $result, $exception); Assert::isArray($result); - Assert::isEmpty($result); + Assert::allObject($result); + /** + * NOTE: We do trust the event handling here and assume that it will return a map of instances of Metadata + * and thus does not modify the type. + * + * @var array $result + */ return $result; } } diff --git a/test/StaticAnalysis/MetadataCapableAdapter.php b/test/StaticAnalysis/MetadataCapableAdapter.php index 2b2e0c27..0f222bbd 100644 --- a/test/StaticAnalysis/MetadataCapableAdapter.php +++ b/test/StaticAnalysis/MetadataCapableAdapter.php @@ -50,13 +50,19 @@ protected function internalGetMetadata(string $normalizedKey): ?object { return null; } -} -$adapter = new MetadataCapableAdapter(); -$metadata = $adapter->getMetadata('foo'); + /** + * @psalm-api Mark method as API method to prevent psalm from detecting this method as unused. + */ + public function whatever(): string + { + $adapter = new MetadataCapableAdapter(); + $metadata = $adapter->getMetadata('foo'); -if ($metadata === null) { - return; -} + if ($metadata === null) { + return ''; + } -echo $metadata->meta; + return $metadata->meta; + } +}