From 1e300cfc691cbcd9486f2ba7e8387bc348a19e82 Mon Sep 17 00:00:00 2001 From: Joshua Estes Date: Mon, 6 Nov 2023 11:38:03 -0500 Subject: [PATCH 01/29] [Cache] New Component --- src/SonsOfPHP/Component/Cache/.gitattributes | 4 ++ src/SonsOfPHP/Component/Cache/.gitignore | 3 + src/SonsOfPHP/Component/Cache/LICENSE | 19 ++++++ src/SonsOfPHP/Component/Cache/README.md | 16 +++++ src/SonsOfPHP/Component/Cache/composer.json | 62 ++++++++++++++++++++ 5 files changed, 104 insertions(+) create mode 100644 src/SonsOfPHP/Component/Cache/.gitattributes create mode 100644 src/SonsOfPHP/Component/Cache/.gitignore create mode 100644 src/SonsOfPHP/Component/Cache/LICENSE create mode 100644 src/SonsOfPHP/Component/Cache/README.md create mode 100644 src/SonsOfPHP/Component/Cache/composer.json diff --git a/src/SonsOfPHP/Component/Cache/.gitattributes b/src/SonsOfPHP/Component/Cache/.gitattributes new file mode 100644 index 00000000..84c7add0 --- /dev/null +++ b/src/SonsOfPHP/Component/Cache/.gitattributes @@ -0,0 +1,4 @@ +/Tests export-ignore +/phpunit.xml.dist export-ignore +/.gitattributes export-ignore +/.gitignore export-ignore diff --git a/src/SonsOfPHP/Component/Cache/.gitignore b/src/SonsOfPHP/Component/Cache/.gitignore new file mode 100644 index 00000000..5414c2c6 --- /dev/null +++ b/src/SonsOfPHP/Component/Cache/.gitignore @@ -0,0 +1,3 @@ +composer.lock +phpunit.xml +vendor/ diff --git a/src/SonsOfPHP/Component/Cache/LICENSE b/src/SonsOfPHP/Component/Cache/LICENSE new file mode 100644 index 00000000..39238382 --- /dev/null +++ b/src/SonsOfPHP/Component/Cache/LICENSE @@ -0,0 +1,19 @@ +Copyright 2022 to Present Joshua Estes + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/src/SonsOfPHP/Component/Cache/README.md b/src/SonsOfPHP/Component/Cache/README.md new file mode 100644 index 00000000..c47c2c53 --- /dev/null +++ b/src/SonsOfPHP/Component/Cache/README.md @@ -0,0 +1,16 @@ +Sons of PHP - Cache +=================== + +## Learn More + +* [Documentation][docs] +* [Contributing][contributing] +* [Report Issues][issues] and [Submit Pull Requests][pull-requests] in the [Mother Repository][mother-repo] +* Get Help & Support using [Discussions][discussions] + +[discussions]: https://github.com/orgs/SonsOfPHP/discussions +[mother-repo]: https://github.com/SonsOfPHP/sonsofphp +[contributing]: https://docs.sonsofphp.com/contributing/ +[docs]: https://docs.sonsofphp.com/components/http-factory/ +[issues]: https://github.com/SonsOfPHP/sonsofphp/issues?q=is%3Aopen+is%3Aissue+label%3ACache +[pull-requests]: https://github.com/SonsOfPHP/sonsofphp/pulls?q=is%3Aopen+is%3Apr+label%3ACache diff --git a/src/SonsOfPHP/Component/Cache/composer.json b/src/SonsOfPHP/Component/Cache/composer.json new file mode 100644 index 00000000..2d0e1de7 --- /dev/null +++ b/src/SonsOfPHP/Component/Cache/composer.json @@ -0,0 +1,62 @@ +{ + "name": "sonsofphp/cache", + "type": "library", + "description": "", + "keywords": [ + "psr", + "psr-6", + "psr-16", + "cache" + ], + "homepage": "https://github.com/SonsOfPHP/cache", + "license": "MIT", + "authors": [ + { + "name": "Joshua Estes", + "email": "joshua@sonsofphp.com" + } + ], + "support": { + "issues": "https://github.com/SonsOfPHP/sonsofphp/issues", + "forum": "https://github.com/orgs/SonsOfPHP/discussions", + "docs": "https://docs.sonsofphp.com" + }, + "autoload": { + "psr-4": { + "SonsOfPHP\\Component\\Cache\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "minimum-stability": "dev", + "prefer-stable": true, + "require": { + "php": ">=8.1", + "psr/cache": "^3.0", + "psr/simple-cache": "^3.0" + }, + "suggest": { + "sonsofphp/filesystem": "Stores cache files using virtual filesystem" + }, + "provide": { + "psr/cache-implementation": "^3.0", + "psr/simple-cache-implementation": "^3.0" + }, + "extra": { + "sort-packages": true, + "branch-alias": { + "dev-main": "0.3.x-dev" + } + }, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/JoshuaEstes" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/subscription/pkg/packagist-sonsofphp-sonsofphp" + } + ] +} From 3614eb78d68810e762b2f8c7a15fe62d2c1f3a27 Mon Sep 17 00:00:00 2001 From: Joshua Estes Date: Mon, 6 Nov 2023 11:41:56 -0500 Subject: [PATCH 02/29] updates --- bard.json | 4 ++++ composer.json | 26 ++++++++++++++------- src/SonsOfPHP/Component/Cache/composer.json | 2 +- 3 files changed, 23 insertions(+), 9 deletions(-) diff --git a/bard.json b/bard.json index 393c534d..cddcb915 100644 --- a/bard.json +++ b/bard.json @@ -5,6 +5,10 @@ "path": "src/SonsOfPHP/Bard", "repository": "git@github.com:SonsOfPHP/bard.git" }, + { + "path": "src/SonsOfPHP/Component/Cache", + "repository": "git@github.com:SonsOfPHP/cache.git" + }, { "path": "src/SonsOfPHP/Component/Clock", "repository": "git@github.com:SonsOfPHP/clock.git" diff --git a/composer.json b/composer.json index 4fb66aed..af7ac76a 100644 --- a/composer.json +++ b/composer.json @@ -19,8 +19,7 @@ "support": { "issues": "https://github.com/SonsOfPHP/sonsofphp/issues", "forum": "https://github.com/orgs/SonsOfPHP/discussions", - "docs": "https://docs.sonsofphp.com", - "chat": "https://discord.gg/sdVxNhFqND" + "docs": "https://docs.sonsofphp.com" }, "funding": [ { @@ -36,7 +35,9 @@ "psr/event-dispatcher-implementation": "1.0", "psr/clock-implementation": "1.0", "psr/http-message-implementation": "^1.0", - "psr/http-factory-implementation": "^1.0" + "psr/http-factory-implementation": "^1.0", + "psr/cache-implementation": "^3.0", + "psr/simple-cache-implementation": "^3.0" }, "require": { "php": ">=8.1", @@ -55,7 +56,9 @@ "symfony/messenger": "^5|^6", "psr/clock": "^1.0", "psr/http-message": "^1.0", - "psr/http-factory": "^1.0" + "psr/http-factory": "^1.0", + "psr/cache": "^3.0", + "psr/simple-cache": "^3.0" }, "replace": { "sonsofphp/bard": "self.version", @@ -73,11 +76,14 @@ "sonsofphp/cqrs-bundle": "self.version", "sonsofphp/filesystem": "self.version", "sonsofphp/http-message": "self.version", - "sonsofphp/http-factory": "self.version" + "sonsofphp/http-factory": "self.version", + "sonsofphp/core-contract": "self.version", + "sonsofphp/cache": "self.version" }, "autoload": { "psr-4": { "SonsOfPHP\\Bard\\": "src/SonsOfPHP/Bard/src", + "SonsOfPHP\\Component\\Cache\\": "src/SonsOfPHP/Component/Cache", "SonsOfPHP\\Component\\Clock\\": "src/SonsOfPHP/Component/Clock", "SonsOfPHP\\Component\\Cqrs\\": "src/SonsOfPHP/Component/Cqrs", "SonsOfPHP\\Bundle\\Cqrs\\": "src/SonsOfPHP/Bundle/Cqrs", @@ -92,10 +98,12 @@ "SonsOfPHP\\Component\\HttpMessage\\": "src/SonsOfPHP/Component/HttpMessage", "SonsOfPHP\\Component\\Json\\": "src/SonsOfPHP/Component/Json", "SonsOfPHP\\Component\\Money\\": "src/SonsOfPHP/Component/Money", - "SonsOfPHP\\Component\\Version\\": "src/SonsOfPHP/Component/Version" + "SonsOfPHP\\Component\\Version\\": "src/SonsOfPHP/Component/Version", + "SonsOfPHP\\Contract\\Core\\": "src/SonsOfPHP/Contract/Core" }, "exclude-from-classmap": [ "src/SonsOfPHP/Bard/Tests", + "src/SonsOfPHP/Component/Cache/Tests", "src/SonsOfPHP/Component/Clock/Tests", "src/SonsOfPHP/Component/Cqrs/Tests", "src/SonsOfPHP/Bundle/Cqrs/Tests", @@ -110,7 +118,8 @@ "src/SonsOfPHP/Component/HttpMessage/Tests", "src/SonsOfPHP/Component/Json/Tests", "src/SonsOfPHP/Component/Money/Tests", - "src/SonsOfPHP/Component/Version/Tests" + "src/SonsOfPHP/Component/Version/Tests", + "src/SonsOfPHP/Contract/Core/Tests" ] }, "extra": { @@ -124,7 +133,8 @@ "symfony/serializer": "^5|^6", "symfony/phpunit-bridge": "^6", "symfony/error-handler": "^6", - "symfony/messenger": "^5|^6" + "symfony/messenger": "^5|^6", + "phpunit/phpunit": "^10.4" }, "autoload-dev": { "psr-4": { diff --git a/src/SonsOfPHP/Component/Cache/composer.json b/src/SonsOfPHP/Component/Cache/composer.json index 2d0e1de7..4a38c045 100644 --- a/src/SonsOfPHP/Component/Cache/composer.json +++ b/src/SonsOfPHP/Component/Cache/composer.json @@ -59,4 +59,4 @@ "url": "https://tidelift.com/subscription/pkg/packagist-sonsofphp-sonsofphp" } ] -} +} \ No newline at end of file From 1e3fa95845349c8594c09b03901455faf9559dde Mon Sep 17 00:00:00 2001 From: Joshua Estes Date: Mon, 6 Nov 2023 11:44:07 -0500 Subject: [PATCH 03/29] labeler --- .github/labeler.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/labeler.yml b/.github/labeler.yml index d4062aca..19f9df10 100644 --- a/.github/labeler.yml +++ b/.github/labeler.yml @@ -2,6 +2,10 @@ Bard: - docs/bard/* - src/SonsOfPHP/Bard/* +Cache: + - docs/components/cache/* + - src/SonsOfPHP/**/Cache/* + Clock: - docs/components/clock/* - src/SonsOfPHP/Component/Clock/* From 01a53d4cfd06e57e455a84f81e28fc05dc946088 Mon Sep 17 00:00:00 2001 From: Joshua Estes Date: Mon, 6 Nov 2023 11:45:27 -0500 Subject: [PATCH 04/29] docs --- docs/components/cache/index.md | 11 +++++++++++ mkdocs.yml | 1 + 2 files changed, 12 insertions(+) create mode 100644 docs/components/cache/index.md diff --git a/docs/components/cache/index.md b/docs/components/cache/index.md new file mode 100644 index 00000000..ebb4b4f4 --- /dev/null +++ b/docs/components/cache/index.md @@ -0,0 +1,11 @@ +--- +title: Cache - Overview +--- + +Used for cache stuff + +## Installation + +```shell +composer require sonsofphp/cache +``` diff --git a/mkdocs.yml b/mkdocs.yml index 01d84f2f..482f1774 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -59,6 +59,7 @@ nav: - bard/index.md - Components: - components/index.md + - Cache: components/clock/index.md - Clock: components/clock/index.md - CQRS: - components/cqrs/index.md From de79de085965d34230241388e337f26ad38d0046 Mon Sep 17 00:00:00 2001 From: Joshua Estes Date: Mon, 6 Nov 2023 11:56:07 -0500 Subject: [PATCH 05/29] meh --- src/SonsOfPHP/Component/Cache/Cache.php | 14 ++++++++++++++ src/SonsOfPHP/Component/Cache/CacheItem.php | 14 ++++++++++++++ src/SonsOfPHP/Component/Cache/CacheItemPool.php | 14 ++++++++++++++ .../Component/Cache/Exception/CacheException.php | 14 ++++++++++++++ .../Cache/Exception/InvalidArgumentException.php | 14 ++++++++++++++ 5 files changed, 70 insertions(+) create mode 100644 src/SonsOfPHP/Component/Cache/Cache.php create mode 100644 src/SonsOfPHP/Component/Cache/CacheItem.php create mode 100644 src/SonsOfPHP/Component/Cache/CacheItemPool.php create mode 100644 src/SonsOfPHP/Component/Cache/Exception/CacheException.php create mode 100644 src/SonsOfPHP/Component/Cache/Exception/InvalidArgumentException.php diff --git a/src/SonsOfPHP/Component/Cache/Cache.php b/src/SonsOfPHP/Component/Cache/Cache.php new file mode 100644 index 00000000..aafe8ce0 --- /dev/null +++ b/src/SonsOfPHP/Component/Cache/Cache.php @@ -0,0 +1,14 @@ + + */ +final class Cache implements CacheInterface +{ +} diff --git a/src/SonsOfPHP/Component/Cache/CacheItem.php b/src/SonsOfPHP/Component/Cache/CacheItem.php new file mode 100644 index 00000000..1fac7f07 --- /dev/null +++ b/src/SonsOfPHP/Component/Cache/CacheItem.php @@ -0,0 +1,14 @@ + + */ +final class CacheItem implements CacheItemInterface +{ +} diff --git a/src/SonsOfPHP/Component/Cache/CacheItemPool.php b/src/SonsOfPHP/Component/Cache/CacheItemPool.php new file mode 100644 index 00000000..14819bb3 --- /dev/null +++ b/src/SonsOfPHP/Component/Cache/CacheItemPool.php @@ -0,0 +1,14 @@ + + */ +class CacheItemPool implements CacheItemPoolInterface +{ +} diff --git a/src/SonsOfPHP/Component/Cache/Exception/CacheException.php b/src/SonsOfPHP/Component/Cache/Exception/CacheException.php new file mode 100644 index 00000000..c9b84748 --- /dev/null +++ b/src/SonsOfPHP/Component/Cache/Exception/CacheException.php @@ -0,0 +1,14 @@ + + */ +class CacheException extends \Exception implements CacheExceptionInterface +{ +} diff --git a/src/SonsOfPHP/Component/Cache/Exception/InvalidArgumentException.php b/src/SonsOfPHP/Component/Cache/Exception/InvalidArgumentException.php new file mode 100644 index 00000000..cf9e3a04 --- /dev/null +++ b/src/SonsOfPHP/Component/Cache/Exception/InvalidArgumentException.php @@ -0,0 +1,14 @@ + + */ +class InvalidArgumentException extends \InvalidArgumentException implements InvalidArgumentExceptionInterface +{ +} From 46b4ffa2afd6e713de2093601af3c9d728ba5e4f Mon Sep 17 00:00:00 2001 From: Joshua Estes Date: Mon, 6 Nov 2023 12:47:07 -0500 Subject: [PATCH 06/29] outline --- .../AdapterInterface.php} | 6 ++---- .../Component/Cache/Adapter/ArrayAdapter.php | 10 ++++++++++ .../Component/Cache/Adapter/ChainAdapter.php | 12 ++++++++++++ .../Component/Cache/Adapter/FilesystemAdapter.php | 12 ++++++++++++ .../Cache/Adapter/NativeFilesystemAdapter.php | 12 ++++++++++++ .../Component/Cache/Adapter/NullAdapter.php | 10 ++++++++++ .../Cache/Adapter/TaggableAdapterInterface.php | 13 +++++++++++++ src/SonsOfPHP/Component/Cache/Cache.php | 4 ++++ src/SonsOfPHP/Component/Cache/CacheItem.php | 4 +--- .../Component/Cache/Exception/CacheException.php | 4 +--- .../Cache/Exception/InvalidArgumentException.php | 4 +--- .../Cache/TaggableCacheItemInterface.php | 15 +++++++++++++++ 12 files changed, 93 insertions(+), 13 deletions(-) rename src/SonsOfPHP/Component/Cache/{CacheItemPool.php => Adapter/AdapterInterface.php} (54%) create mode 100644 src/SonsOfPHP/Component/Cache/Adapter/ArrayAdapter.php create mode 100644 src/SonsOfPHP/Component/Cache/Adapter/ChainAdapter.php create mode 100644 src/SonsOfPHP/Component/Cache/Adapter/FilesystemAdapter.php create mode 100644 src/SonsOfPHP/Component/Cache/Adapter/NativeFilesystemAdapter.php create mode 100644 src/SonsOfPHP/Component/Cache/Adapter/NullAdapter.php create mode 100644 src/SonsOfPHP/Component/Cache/Adapter/TaggableAdapterInterface.php create mode 100644 src/SonsOfPHP/Component/Cache/TaggableCacheItemInterface.php diff --git a/src/SonsOfPHP/Component/Cache/CacheItemPool.php b/src/SonsOfPHP/Component/Cache/Adapter/AdapterInterface.php similarity index 54% rename from src/SonsOfPHP/Component/Cache/CacheItemPool.php rename to src/SonsOfPHP/Component/Cache/Adapter/AdapterInterface.php index 14819bb3..a3fafe7c 100644 --- a/src/SonsOfPHP/Component/Cache/CacheItemPool.php +++ b/src/SonsOfPHP/Component/Cache/Adapter/AdapterInterface.php @@ -2,13 +2,11 @@ declare(strict_types=1); -namespace SonsOfPHP\Component\Cache; +namespace SonsOfPHP\Component\Cache\Adapter; use Psr\Cache\CacheItemPoolInterface; /** * @author Joshua Estes */ -class CacheItemPool implements CacheItemPoolInterface -{ -} +interface AdapterInterface extends CacheItemPoolInterface {} diff --git a/src/SonsOfPHP/Component/Cache/Adapter/ArrayAdapter.php b/src/SonsOfPHP/Component/Cache/Adapter/ArrayAdapter.php new file mode 100644 index 00000000..fb17c4c9 --- /dev/null +++ b/src/SonsOfPHP/Component/Cache/Adapter/ArrayAdapter.php @@ -0,0 +1,10 @@ + + */ +class ArrayAdapter implements AdapterInterface {} diff --git a/src/SonsOfPHP/Component/Cache/Adapter/ChainAdapter.php b/src/SonsOfPHP/Component/Cache/Adapter/ChainAdapter.php new file mode 100644 index 00000000..10012887 --- /dev/null +++ b/src/SonsOfPHP/Component/Cache/Adapter/ChainAdapter.php @@ -0,0 +1,12 @@ + + */ +class ChainAdapter implements AdapterInterface {} diff --git a/src/SonsOfPHP/Component/Cache/Adapter/FilesystemAdapter.php b/src/SonsOfPHP/Component/Cache/Adapter/FilesystemAdapter.php new file mode 100644 index 00000000..e87a2b2f --- /dev/null +++ b/src/SonsOfPHP/Component/Cache/Adapter/FilesystemAdapter.php @@ -0,0 +1,12 @@ + + */ +class FilesystemAdapter implements AdapterInterface {} diff --git a/src/SonsOfPHP/Component/Cache/Adapter/NativeFilesystemAdapter.php b/src/SonsOfPHP/Component/Cache/Adapter/NativeFilesystemAdapter.php new file mode 100644 index 00000000..01b36160 --- /dev/null +++ b/src/SonsOfPHP/Component/Cache/Adapter/NativeFilesystemAdapter.php @@ -0,0 +1,12 @@ + + */ +class NativeFilesystemAdapter implements AdapterInterface {} diff --git a/src/SonsOfPHP/Component/Cache/Adapter/NullAdapter.php b/src/SonsOfPHP/Component/Cache/Adapter/NullAdapter.php new file mode 100644 index 00000000..4282c703 --- /dev/null +++ b/src/SonsOfPHP/Component/Cache/Adapter/NullAdapter.php @@ -0,0 +1,10 @@ + + */ +class NullAdapter implements AdapterInterface {} diff --git a/src/SonsOfPHP/Component/Cache/Adapter/TaggableAdapterInterface.php b/src/SonsOfPHP/Component/Cache/Adapter/TaggableAdapterInterface.php new file mode 100644 index 00000000..87f6bdfd --- /dev/null +++ b/src/SonsOfPHP/Component/Cache/Adapter/TaggableAdapterInterface.php @@ -0,0 +1,13 @@ + + */ +interface TaggableAdapterInterface extends AdapterInterface +{ + public function clearByTag(string $tag): bool; +} diff --git a/src/SonsOfPHP/Component/Cache/Cache.php b/src/SonsOfPHP/Component/Cache/Cache.php index aafe8ce0..1bd623cd 100644 --- a/src/SonsOfPHP/Component/Cache/Cache.php +++ b/src/SonsOfPHP/Component/Cache/Cache.php @@ -5,10 +5,14 @@ namespace SonsOfPHP\Component\Cache; use Psr\SimpleCache\CacheInterface; +use SonsOfPHP\Component\Cache\Adapter\AdapterInterface; /** * @author Joshua Estes */ final class Cache implements CacheInterface { + public function __construct( + private AdapterInterface $adapter, + ) {} } diff --git a/src/SonsOfPHP/Component/Cache/CacheItem.php b/src/SonsOfPHP/Component/Cache/CacheItem.php index 1fac7f07..0dfdee28 100644 --- a/src/SonsOfPHP/Component/Cache/CacheItem.php +++ b/src/SonsOfPHP/Component/Cache/CacheItem.php @@ -9,6 +9,4 @@ /** * @author Joshua Estes */ -final class CacheItem implements CacheItemInterface -{ -} +class CacheItem implements CacheItemInterface {} diff --git a/src/SonsOfPHP/Component/Cache/Exception/CacheException.php b/src/SonsOfPHP/Component/Cache/Exception/CacheException.php index c9b84748..509657ab 100644 --- a/src/SonsOfPHP/Component/Cache/Exception/CacheException.php +++ b/src/SonsOfPHP/Component/Cache/Exception/CacheException.php @@ -9,6 +9,4 @@ /** * @author Joshua Estes */ -class CacheException extends \Exception implements CacheExceptionInterface -{ -} +class CacheException extends \Exception implements CacheExceptionInterface {} diff --git a/src/SonsOfPHP/Component/Cache/Exception/InvalidArgumentException.php b/src/SonsOfPHP/Component/Cache/Exception/InvalidArgumentException.php index cf9e3a04..a8a525fb 100644 --- a/src/SonsOfPHP/Component/Cache/Exception/InvalidArgumentException.php +++ b/src/SonsOfPHP/Component/Cache/Exception/InvalidArgumentException.php @@ -9,6 +9,4 @@ /** * @author Joshua Estes */ -class InvalidArgumentException extends \InvalidArgumentException implements InvalidArgumentExceptionInterface -{ -} +class InvalidArgumentException extends \InvalidArgumentException implements InvalidArgumentExceptionInterface {} diff --git a/src/SonsOfPHP/Component/Cache/TaggableCacheItemInterface.php b/src/SonsOfPHP/Component/Cache/TaggableCacheItemInterface.php new file mode 100644 index 00000000..31e85797 --- /dev/null +++ b/src/SonsOfPHP/Component/Cache/TaggableCacheItemInterface.php @@ -0,0 +1,15 @@ + + */ +interface TaggableCacheItem extends CacheItemInterface +{ + public function setTags(array $tags); +} From 4c3a8bc72f6afeb5be750df7d58807db674d777a Mon Sep 17 00:00:00 2001 From: Joshua Estes Date: Mon, 6 Nov 2023 14:44:35 -0500 Subject: [PATCH 07/29] updates --- Makefile | 3 + phpunit.xml.dist | 4 + .../Cache/Adapter/AdapterInterface.php | 2 + .../Component/Cache/Adapter/ArrayAdapter.php | 96 ++++++++++++++++++- .../Component/Cache/Adapter/ChainAdapter.php | 4 +- .../Component/Cache/Adapter/NullAdapter.php | 77 ++++++++++++++- ...rface.php => TagAwareAdapterInterface.php} | 2 +- src/SonsOfPHP/Component/Cache/Cache.php | 74 ++++++++++++++ src/SonsOfPHP/Component/Cache/CacheItem.php | 73 +++++++++++++- .../Component/Cache/Tests/CacheItemTest.php | 57 +++++++++++ src/SonsOfPHP/Component/Cache/composer.json | 10 +- 11 files changed, 392 insertions(+), 10 deletions(-) rename src/SonsOfPHP/Component/Cache/Adapter/{TaggableAdapterInterface.php => TagAwareAdapterInterface.php} (75%) create mode 100644 src/SonsOfPHP/Component/Cache/Tests/CacheItemTest.php diff --git a/Makefile b/Makefile index f6fd71ba..de0c12b8 100644 --- a/Makefile +++ b/Makefile @@ -57,6 +57,9 @@ lint-php: # lint php files coverage: ## Build Code Coverage Report XDEBUG_MODE=coverage $(PHP) -dxdebug.mode=coverage $(PHPUNIT) --coverage-html $(COVERAGE_DIR) +coverage-cache: + XDEBUG_MODE=coverage $(PHP) -dxdebug.mode=coverage $(PHPUNIT) --testsuite cache --coverage-html $(COVERAGE_DIR) + coverage-clock: XDEBUG_MODE=coverage $(PHP) -dxdebug.mode=coverage $(PHPUNIT) --testsuite clock --coverage-html $(COVERAGE_DIR) diff --git a/phpunit.xml.dist b/phpunit.xml.dist index 265e1bda..9e431ee3 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -21,6 +21,10 @@ + + src/SonsOfPHP/Component/Clock/Tests + + src/SonsOfPHP/Component/Clock/Tests diff --git a/src/SonsOfPHP/Component/Cache/Adapter/AdapterInterface.php b/src/SonsOfPHP/Component/Cache/Adapter/AdapterInterface.php index a3fafe7c..4e2f8701 100644 --- a/src/SonsOfPHP/Component/Cache/Adapter/AdapterInterface.php +++ b/src/SonsOfPHP/Component/Cache/Adapter/AdapterInterface.php @@ -7,6 +7,8 @@ use Psr\Cache\CacheItemPoolInterface; /** + * All Adapters MUST implement this interface + * * @author Joshua Estes */ interface AdapterInterface extends CacheItemPoolInterface {} diff --git a/src/SonsOfPHP/Component/Cache/Adapter/ArrayAdapter.php b/src/SonsOfPHP/Component/Cache/Adapter/ArrayAdapter.php index fb17c4c9..08c52df9 100644 --- a/src/SonsOfPHP/Component/Cache/Adapter/ArrayAdapter.php +++ b/src/SonsOfPHP/Component/Cache/Adapter/ArrayAdapter.php @@ -4,7 +4,101 @@ namespace SonsOfPHP\Component\Cache\Adapter; +use Psr\Cache\CacheItemInterface; +use SonsOfPHP\Component\Cache\Exception\InvalidArgumentException; + /** * @author Joshua Estes */ -class ArrayAdapter implements AdapterInterface {} +class ArrayAdapter implements AdapterInterface +{ + private array $values = []; + + /** + * {@inheritdoc} + */ + public function getItem(string $key): CacheItemInterface + { + if ($this->hasItem($key)) { + return (new CacheItem($key, true))->set($this->values[$key]); + } + + return new CacheItem($key, false); + } + + /** + * {@inheritdoc} + */ + public function getItems(array $keys = []): iterable + { + foreach ($keys as $key) { + yield $this->getItem($key); + } + } + + /** + * {@inheritdoc} + */ + public function hasItem(string $key): bool + { + return array_key_exists($key, $this->values); + } + + /** + * {@inheritdoc} + */ + public function clear(): bool + { + $this->values = []; + + return true; + } + + /** + * {@inheritdoc} + */ + public function deleteItem(string $key): bool + { + unset($this->values[$key]); + + return true; + } + + /** + * {@inheritdoc} + */ + public function deleteItems(array $keys): bool + { + foreach ($keys as $key) { + $this->deleteItem($key); + } + + return true; + } + + /** + * {@inheritdoc} + */ + public function save(CacheItemInterface $item): bool + { + $this->values[$item->getKey()] = $item->get(); + + return true; + } + + /** + * {@inheritdoc} + */ + public function saveDeferred(CacheItemInterface $item): bool + { + return $this->save($item); + } + + /** + * {@inheritdoc} + */ + public function commit(): bool + { + return true; + } +} diff --git a/src/SonsOfPHP/Component/Cache/Adapter/ChainAdapter.php b/src/SonsOfPHP/Component/Cache/Adapter/ChainAdapter.php index 10012887..ac350e78 100644 --- a/src/SonsOfPHP/Component/Cache/Adapter/ChainAdapter.php +++ b/src/SonsOfPHP/Component/Cache/Adapter/ChainAdapter.php @@ -9,4 +9,6 @@ * * @author Joshua Estes */ -class ChainAdapter implements AdapterInterface {} +class ChainAdapter implements AdapterInterface +{ +} diff --git a/src/SonsOfPHP/Component/Cache/Adapter/NullAdapter.php b/src/SonsOfPHP/Component/Cache/Adapter/NullAdapter.php index 4282c703..b4bc10f2 100644 --- a/src/SonsOfPHP/Component/Cache/Adapter/NullAdapter.php +++ b/src/SonsOfPHP/Component/Cache/Adapter/NullAdapter.php @@ -7,4 +7,79 @@ /** * @author Joshua Estes */ -class NullAdapter implements AdapterInterface {} +final class NullAdapter implements AdapterInterface +{ + /** + * {@inheritdoc} + */ + public function getItem(string $key): CacheItemInterface + { + return new CacheItem($key, false); + } + + /** + * {@inheritdoc} + */ + public function getItems(array $keys = []): iterable + { + foreach ($keys as $key) { + yield $this->getItem($key); + } + } + + /** + * {@inheritdoc} + */ + public function hasItem(string $key): bool + { + return false; + } + + /** + * {@inheritdoc} + */ + public function clear(): bool + { + return true; + } + + /** + * {@inheritdoc} + */ + public function deleteItem(string $key): bool + { + return true; + } + + /** + * {@inheritdoc} + */ + public function deleteItems(array $keys): bool + { + return true; + } + + /** + * {@inheritdoc} + */ + public function save(CacheItemInterface $item): bool + { + return true; + } + + /** + * {@inheritdoc} + */ + public function saveDeferred(CacheItemInterface $item): bool + { + return true; + } + + /** + * {@inheritdoc} + */ + public function commit(): bool + { + return true; + } +} diff --git a/src/SonsOfPHP/Component/Cache/Adapter/TaggableAdapterInterface.php b/src/SonsOfPHP/Component/Cache/Adapter/TagAwareAdapterInterface.php similarity index 75% rename from src/SonsOfPHP/Component/Cache/Adapter/TaggableAdapterInterface.php rename to src/SonsOfPHP/Component/Cache/Adapter/TagAwareAdapterInterface.php index 87f6bdfd..2e8520b1 100644 --- a/src/SonsOfPHP/Component/Cache/Adapter/TaggableAdapterInterface.php +++ b/src/SonsOfPHP/Component/Cache/Adapter/TagAwareAdapterInterface.php @@ -7,7 +7,7 @@ /** * @author Joshua Estes */ -interface TaggableAdapterInterface extends AdapterInterface +interface TagAwareAdapterInterface { public function clearByTag(string $tag): bool; } diff --git a/src/SonsOfPHP/Component/Cache/Cache.php b/src/SonsOfPHP/Component/Cache/Cache.php index 1bd623cd..c161ea55 100644 --- a/src/SonsOfPHP/Component/Cache/Cache.php +++ b/src/SonsOfPHP/Component/Cache/Cache.php @@ -15,4 +15,78 @@ final class Cache implements CacheInterface public function __construct( private AdapterInterface $adapter, ) {} + + /** + * {@inheritdoc} + */ + public function get(string $key, mixed $default = null): mixed + { + if (!$this->adapter->hasItem($key)) { + return $default; + } + + return $this->adapter->getItem($key); + } + + /** + * {@inheritdoc} + */ + public function set(string $key, mixed $value, null|int|\DateInterval $ttl = null): bool + { + return $this->adapter->save((new CacheItem($key))->set($value)->expiresAfter($ttl)); + } + + /** + * {@inheritdoc} + */ + public function delete(string $key): bool + { + return $this->adapter->deleteItem($key); + } + + /** + * {@inheritdoc} + */ + public function clear(): bool + { + return $this->adapter->clear(); + } + + /** + * {@inheritdoc} + */ + public function getMultiple(iterable $keys, mixed $default = null): iterable + { + foreach ($keys as $key) { + yield $key => $this->has('key') ? $this->adapter->getItem($key)->get() : $default; + } + } + + /** + * {@inheritdoc} + */ + public function setMultiple(iterable $values, null|int|\DateInterval $ttl = null): bool + { + foreach ($values as $key => $value) { + $this->set($key, $value, $ttl); + } + + return true; + } + + /** + * {@inheritdoc} + */ + public function deleteMultiple(iterable $keys): bool + { + return $this->adapter->deleteItems(iterator_to_array($keys)); + } + + /** + * {@inheritdoc} + */ + public function has(string $key): bool + { + return $this->adapter->hasItem($key); + } } diff --git a/src/SonsOfPHP/Component/Cache/CacheItem.php b/src/SonsOfPHP/Component/Cache/CacheItem.php index 0dfdee28..6794e2ae 100644 --- a/src/SonsOfPHP/Component/Cache/CacheItem.php +++ b/src/SonsOfPHP/Component/Cache/CacheItem.php @@ -9,4 +9,75 @@ /** * @author Joshua Estes */ -class CacheItem implements CacheItemInterface {} +final class CacheItem implements CacheItemInterface +{ + private mixed $value; + private int|float|null $expiry = null; + + public function __construct( + private string $key, + private bool $isHit = false, + ) { + // @todo throw exception for invalid key + } + + /** + * {@inheritdoc} + */ + public function getKey(): string + { + return $this->key; + } + + /** + * {@inheritdoc} + */ + public function get(): mixed + { + return $this->value ?? null; + } + + /** + * {@inheritdoc} + */ + public function isHit(): bool + { + return $this->isHit; + } + + /** + * {@inheritdoc} + */ + public function set(mixed $value): static + { + $this->value = $value; + + return $this; + } + + /** + * {@inheritdoc} + */ + public function expiresAt(?\DateTimeInterface $expiration): static + { + $this->expiry = null !== $expiration ? (float) $expiration->format('U.u') : null; + + return $this; + } + + /** + * {@inheritdoc} + */ + public function expiresAfter(int|\DateInterval|null $time): static + { + if (is_int($time)) { + $this->expiry = $time + microtime(true); + } elseif ($time instanceof \DateInterval) { + $this->expiry = microtime(true) + \DateTimeImmutable::createFromFormat('U', 0)->add($time)->format('U.u'); + } elseif (null === $time) { + $this->expiry = null; + } + + return $this; + } +} diff --git a/src/SonsOfPHP/Component/Cache/Tests/CacheItemTest.php b/src/SonsOfPHP/Component/Cache/Tests/CacheItemTest.php new file mode 100644 index 00000000..164a902d --- /dev/null +++ b/src/SonsOfPHP/Component/Cache/Tests/CacheItemTest.php @@ -0,0 +1,57 @@ +assertInstanceOf(CacheItemInterface::class, $item); + } + + /** + * @covers ::isHit + */ + public function testDefaultValueForIsHit(): void + { + $item = new CacheItem('testing'); + + $this->assertFalse($item->isHit()); + } + + /** + * @covers ::get + */ + public function testDefaultValueForGet(): void + { + $item = new CacheItem('testing'); + + $this->assertNull($item->get()); + } + + /** + * @covers ::set + */ + public function testSetWorksAsExpected(): void + { + $item = new CacheItem('testing'); + $this->assertSame($item, $item->set('value')); + $this->assertSame('value', $item->get()); + } +} diff --git a/src/SonsOfPHP/Component/Cache/composer.json b/src/SonsOfPHP/Component/Cache/composer.json index 4a38c045..02d84cba 100644 --- a/src/SonsOfPHP/Component/Cache/composer.json +++ b/src/SonsOfPHP/Component/Cache/composer.json @@ -33,15 +33,15 @@ "prefer-stable": true, "require": { "php": ">=8.1", - "psr/cache": "^3.0", - "psr/simple-cache": "^3.0" + "psr/cache": "^1.0|^2.0|^3.0", + "psr/simple-cache": "^1.0|^2.0|^3.0" }, "suggest": { "sonsofphp/filesystem": "Stores cache files using virtual filesystem" }, "provide": { - "psr/cache-implementation": "^3.0", - "psr/simple-cache-implementation": "^3.0" + "psr/cache-implementation": "^1.0|^2.0|^3.0", + "psr/simple-cache-implementation": "^1.0|^2.0|^3.0" }, "extra": { "sort-packages": true, @@ -59,4 +59,4 @@ "url": "https://tidelift.com/subscription/pkg/packagist-sonsofphp-sonsofphp" } ] -} \ No newline at end of file +} From 8e7fca0e308daca9fa173f814bb41ad477b2fc4a Mon Sep 17 00:00:00 2001 From: Joshua Estes Date: Mon, 6 Nov 2023 14:49:45 -0500 Subject: [PATCH 08/29] testing --- .../Component/Cache/Tests/CacheItemTest.php | 2 +- .../Component/Cache/Tests/CacheTest.php | 35 +++++++++++++++++++ 2 files changed, 36 insertions(+), 1 deletion(-) create mode 100644 src/SonsOfPHP/Component/Cache/Tests/CacheTest.php diff --git a/src/SonsOfPHP/Component/Cache/Tests/CacheItemTest.php b/src/SonsOfPHP/Component/Cache/Tests/CacheItemTest.php index 164a902d..9855159d 100644 --- a/src/SonsOfPHP/Component/Cache/Tests/CacheItemTest.php +++ b/src/SonsOfPHP/Component/Cache/Tests/CacheItemTest.php @@ -11,7 +11,7 @@ /** * @coversDefaultClass \SonsOfPHP\Component\Cache\CacheItem * - * @internal + * @uses \SonsOfPHP\Component\Cache\CacheItem */ final class CacheItemTest extends TestCase { diff --git a/src/SonsOfPHP/Component/Cache/Tests/CacheTest.php b/src/SonsOfPHP/Component/Cache/Tests/CacheTest.php new file mode 100644 index 00000000..70147a84 --- /dev/null +++ b/src/SonsOfPHP/Component/Cache/Tests/CacheTest.php @@ -0,0 +1,35 @@ +adapter = $this->createMock(AdapterInterface::class); + } + + /** + * @coversNothing + */ + public function testItHasTheCorrectInterface(): void + { + $cache = new Cache($this->adapter); + + $this->assertInstanceOf(CacheInterface::class, $cache); + } +} From 8f45691efd2dfaa0363dac135bdded81c1f6feb0 Mon Sep 17 00:00:00 2001 From: Joshua Estes Date: Mon, 6 Nov 2023 15:09:48 -0500 Subject: [PATCH 09/29] updates --- src/SonsOfPHP/Component/Cache/Cache.php | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/src/SonsOfPHP/Component/Cache/Cache.php b/src/SonsOfPHP/Component/Cache/Cache.php index c161ea55..3e76e87c 100644 --- a/src/SonsOfPHP/Component/Cache/Cache.php +++ b/src/SonsOfPHP/Component/Cache/Cache.php @@ -21,11 +21,9 @@ public function __construct( */ public function get(string $key, mixed $default = null): mixed { - if (!$this->adapter->hasItem($key)) { - return $default; - } + $item = $this->adapter->getItem($key); - return $this->adapter->getItem($key); + return $item->isHit() ? $item->get() : $default; } /** @@ -33,7 +31,14 @@ public function get(string $key, mixed $default = null): mixed */ public function set(string $key, mixed $value, null|int|\DateInterval $ttl = null): bool { - return $this->adapter->save((new CacheItem($key))->set($value)->expiresAfter($ttl)); + $item = $this->adapter->getItem($key); + $item->set($value); + + if (null !== $ttl) { + $item->expiresAfter($ttl); + } + + return $this->adapter->save($item); } /** @@ -57,8 +62,9 @@ public function clear(): bool */ public function getMultiple(iterable $keys, mixed $default = null): iterable { - foreach ($keys as $key) { - yield $key => $this->has('key') ? $this->adapter->getItem($key)->get() : $default; + $items = $this->adapter->getItems($keys); + foreach ($items as $item) { + yield $key => $item->isHit() ? $item->get() : $default; } } From 66ca87ceed161f17533a381d22117086c2caae85 Mon Sep 17 00:00:00 2001 From: Joshua Estes Date: Mon, 6 Nov 2023 15:48:24 -0500 Subject: [PATCH 10/29] meh --- src/SonsOfPHP/Component/Cache/Cache.php | 22 ++++++++-------- src/SonsOfPHP/Component/Cache/CacheItem.php | 8 +++--- .../Component/Cache/CacheItemFactory.php | 21 ++++++++++++++++ .../Cache/CacheItemFactoryInterface.php | 17 +++++++++++++ .../Component/Cache/Tests/CacheItemTest.php | 25 +++++++++++++++++++ 5 files changed, 79 insertions(+), 14 deletions(-) create mode 100644 src/SonsOfPHP/Component/Cache/CacheItemFactory.php create mode 100644 src/SonsOfPHP/Component/Cache/CacheItemFactoryInterface.php diff --git a/src/SonsOfPHP/Component/Cache/Cache.php b/src/SonsOfPHP/Component/Cache/Cache.php index 3e76e87c..1f685f86 100644 --- a/src/SonsOfPHP/Component/Cache/Cache.php +++ b/src/SonsOfPHP/Component/Cache/Cache.php @@ -5,15 +5,17 @@ namespace SonsOfPHP\Component\Cache; use Psr\SimpleCache\CacheInterface; -use SonsOfPHP\Component\Cache\Adapter\AdapterInterface; +use Psr\Cache\CacheItemPoolInterface; /** + * Simple Cache + * * @author Joshua Estes */ final class Cache implements CacheInterface { public function __construct( - private AdapterInterface $adapter, + private CacheItemPoolInterface $pool, ) {} /** @@ -21,7 +23,7 @@ public function __construct( */ public function get(string $key, mixed $default = null): mixed { - $item = $this->adapter->getItem($key); + $item = $this->pool->getItem($key); return $item->isHit() ? $item->get() : $default; } @@ -31,14 +33,14 @@ public function get(string $key, mixed $default = null): mixed */ public function set(string $key, mixed $value, null|int|\DateInterval $ttl = null): bool { - $item = $this->adapter->getItem($key); + $item = $this->pool->getItem($key); $item->set($value); if (null !== $ttl) { $item->expiresAfter($ttl); } - return $this->adapter->save($item); + return $this->pool->save($item); } /** @@ -46,7 +48,7 @@ public function set(string $key, mixed $value, null|int|\DateInterval $ttl = nul */ public function delete(string $key): bool { - return $this->adapter->deleteItem($key); + return $this->pool->deleteItem($key); } /** @@ -54,7 +56,7 @@ public function delete(string $key): bool */ public function clear(): bool { - return $this->adapter->clear(); + return $this->pool->clear(); } /** @@ -62,7 +64,7 @@ public function clear(): bool */ public function getMultiple(iterable $keys, mixed $default = null): iterable { - $items = $this->adapter->getItems($keys); + $items = $this->pool->getItems($keys); foreach ($items as $item) { yield $key => $item->isHit() ? $item->get() : $default; } @@ -85,7 +87,7 @@ public function setMultiple(iterable $values, null|int|\DateInterval $ttl = null */ public function deleteMultiple(iterable $keys): bool { - return $this->adapter->deleteItems(iterator_to_array($keys)); + return $this->pool->deleteItems(iterator_to_array($keys)); } /** @@ -93,6 +95,6 @@ public function deleteMultiple(iterable $keys): bool */ public function has(string $key): bool { - return $this->adapter->hasItem($key); + return $this->pool->hasItem($key); } } diff --git a/src/SonsOfPHP/Component/Cache/CacheItem.php b/src/SonsOfPHP/Component/Cache/CacheItem.php index 6794e2ae..db2bf8e1 100644 --- a/src/SonsOfPHP/Component/Cache/CacheItem.php +++ b/src/SonsOfPHP/Component/Cache/CacheItem.php @@ -11,12 +11,12 @@ */ final class CacheItem implements CacheItemInterface { - private mixed $value; - private int|float|null $expiry = null; + protected mixed $value; + protected int|float|null $expiry; public function __construct( - private string $key, - private bool $isHit = false, + protected string $key, + protected bool $isHit = false, ) { // @todo throw exception for invalid key } diff --git a/src/SonsOfPHP/Component/Cache/CacheItemFactory.php b/src/SonsOfPHP/Component/Cache/CacheItemFactory.php new file mode 100644 index 00000000..5d397667 --- /dev/null +++ b/src/SonsOfPHP/Component/Cache/CacheItemFactory.php @@ -0,0 +1,21 @@ + + */ +final class CacheItemFactroy implements CacheItemFactroyInterface +{ + public function createCacheItem(string $key, mixed $value, bool $isHit = false): CacheItemInterface + { + $item = new CacheItem($key, $isHit); + $item->set($value); + + return $item; + } +} diff --git a/src/SonsOfPHP/Component/Cache/CacheItemFactoryInterface.php b/src/SonsOfPHP/Component/Cache/CacheItemFactoryInterface.php new file mode 100644 index 00000000..3579d4f3 --- /dev/null +++ b/src/SonsOfPHP/Component/Cache/CacheItemFactoryInterface.php @@ -0,0 +1,17 @@ + + */ +interface CacheItemFactroyInterface +{ + /** + */ + public function createCacheItem(string $key, mixed $value, bool $isHit = false): CacheItemInterface; +} diff --git a/src/SonsOfPHP/Component/Cache/Tests/CacheItemTest.php b/src/SonsOfPHP/Component/Cache/Tests/CacheItemTest.php index 9855159d..53d7b5ef 100644 --- a/src/SonsOfPHP/Component/Cache/Tests/CacheItemTest.php +++ b/src/SonsOfPHP/Component/Cache/Tests/CacheItemTest.php @@ -25,6 +25,17 @@ public function testItHasTheCorrectInterface(): void $this->assertInstanceOf(CacheItemInterface::class, $item); } + /** + * @covers ::__construct + * @covers ::getKey + */ + public function testGetKeyWorksAsExpected(): void + { + $item = new CacheItem('testing'); + + $this->assertSame('testing', $item->getKey()); + } + /** * @covers ::isHit */ @@ -54,4 +65,18 @@ public function testSetWorksAsExpected(): void $this->assertSame($item, $item->set('value')); $this->assertSame('value', $item->get()); } + + /** + * @covers ::expiresAfter + */ + public function testExpiresAfterWorksAsExpectedWithIntegers(): void + { + $item = new CacheItem('testing'); + $itemAsArray = (array) $item; + $this->assertFalse(isset($itemAsArray["\0*\0expiry"])); + + $item->expiresAfter(3600); + $itemAsArray = (array) $item; + $this->assertNotNull($itemAsArray["\0*\0expiry"]); + } } From cf827feb4e5c71949734754c22a0d1f084d27f1e Mon Sep 17 00:00:00 2001 From: Joshua Estes Date: Tue, 7 Nov 2023 10:08:59 -0500 Subject: [PATCH 11/29] testing --- .../Component/Cache/Adapter/ArrayAdapter.php | 3 +- .../Component/Cache/Adapter/NullAdapter.php | 5 +- src/SonsOfPHP/Component/Cache/Cache.php | 11 +- src/SonsOfPHP/Component/Cache/CacheItem.php | 2 +- .../Cache/Tests/Adapter/ArrayAdapterTest.php | 125 +++++++++++++++ .../Cache/Tests/Adapter/NullAdapterTest.php | 125 +++++++++++++++ .../Component/Cache/Tests/CacheItemTest.php | 58 +++++++ .../Component/Cache/Tests/CacheTest.php | 143 +++++++++++++++++- 8 files changed, 466 insertions(+), 6 deletions(-) create mode 100644 src/SonsOfPHP/Component/Cache/Tests/Adapter/ArrayAdapterTest.php create mode 100644 src/SonsOfPHP/Component/Cache/Tests/Adapter/NullAdapterTest.php diff --git a/src/SonsOfPHP/Component/Cache/Adapter/ArrayAdapter.php b/src/SonsOfPHP/Component/Cache/Adapter/ArrayAdapter.php index 08c52df9..6ecc3f3a 100644 --- a/src/SonsOfPHP/Component/Cache/Adapter/ArrayAdapter.php +++ b/src/SonsOfPHP/Component/Cache/Adapter/ArrayAdapter.php @@ -6,6 +6,7 @@ use Psr\Cache\CacheItemInterface; use SonsOfPHP\Component\Cache\Exception\InvalidArgumentException; +use SonsOfPHP\Component\Cache\CacheItem; /** * @author Joshua Estes @@ -32,7 +33,7 @@ public function getItem(string $key): CacheItemInterface public function getItems(array $keys = []): iterable { foreach ($keys as $key) { - yield $this->getItem($key); + yield $key => $this->getItem($key); } } diff --git a/src/SonsOfPHP/Component/Cache/Adapter/NullAdapter.php b/src/SonsOfPHP/Component/Cache/Adapter/NullAdapter.php index b4bc10f2..106a7a85 100644 --- a/src/SonsOfPHP/Component/Cache/Adapter/NullAdapter.php +++ b/src/SonsOfPHP/Component/Cache/Adapter/NullAdapter.php @@ -4,6 +4,9 @@ namespace SonsOfPHP\Component\Cache\Adapter; +use SonsOfPHP\Component\Cache\CacheItem; +use Psr\Cache\CacheItemInterface; + /** * @author Joshua Estes */ @@ -23,7 +26,7 @@ public function getItem(string $key): CacheItemInterface public function getItems(array $keys = []): iterable { foreach ($keys as $key) { - yield $this->getItem($key); + yield $key => $this->getItem($key); } } diff --git a/src/SonsOfPHP/Component/Cache/Cache.php b/src/SonsOfPHP/Component/Cache/Cache.php index 1f685f86..532e8661 100644 --- a/src/SonsOfPHP/Component/Cache/Cache.php +++ b/src/SonsOfPHP/Component/Cache/Cache.php @@ -14,6 +14,9 @@ */ final class Cache implements CacheInterface { + /** + * @codeCoverageIgnore + */ public function __construct( private CacheItemPoolInterface $pool, ) {} @@ -65,7 +68,7 @@ public function clear(): bool public function getMultiple(iterable $keys, mixed $default = null): iterable { $items = $this->pool->getItems($keys); - foreach ($items as $item) { + foreach ($items as $key => $item) { yield $key => $item->isHit() ? $item->get() : $default; } } @@ -87,7 +90,11 @@ public function setMultiple(iterable $values, null|int|\DateInterval $ttl = null */ public function deleteMultiple(iterable $keys): bool { - return $this->pool->deleteItems(iterator_to_array($keys)); + if ($keys instanceof \Traversable) { + $keys = iterator_to_array($keys); + } + + return $this->pool->deleteItems($keys); } /** diff --git a/src/SonsOfPHP/Component/Cache/CacheItem.php b/src/SonsOfPHP/Component/Cache/CacheItem.php index db2bf8e1..a396815d 100644 --- a/src/SonsOfPHP/Component/Cache/CacheItem.php +++ b/src/SonsOfPHP/Component/Cache/CacheItem.php @@ -73,7 +73,7 @@ public function expiresAfter(int|\DateInterval|null $time): static if (is_int($time)) { $this->expiry = $time + microtime(true); } elseif ($time instanceof \DateInterval) { - $this->expiry = microtime(true) + \DateTimeImmutable::createFromFormat('U', 0)->add($time)->format('U.u'); + $this->expiry = microtime(true) + \DateTimeImmutable::createFromFormat('U', '0')->add($time)->format('U.u'); } elseif (null === $time) { $this->expiry = null; } diff --git a/src/SonsOfPHP/Component/Cache/Tests/Adapter/ArrayAdapterTest.php b/src/SonsOfPHP/Component/Cache/Tests/Adapter/ArrayAdapterTest.php new file mode 100644 index 00000000..6e811c4a --- /dev/null +++ b/src/SonsOfPHP/Component/Cache/Tests/Adapter/ArrayAdapterTest.php @@ -0,0 +1,125 @@ +assertInstanceOf(AdapterInterface::class, $adapter); + $this->assertInstanceOf(CacheItemPoolInterface::class, $adapter); + } + + /** + * @covers ::getItem + */ + public function testGetItem(): void + { + $adapter = new ArrayAdapter(); + $item = $adapter->getItem('unit.test'); + + $this->assertInstanceOf(CacheItemInterface::class, $item); + } + + /** + * @covers ::getItems + */ + public function testGetItems(): void + { + $adapter = new ArrayAdapter(); + $items = $adapter->getItems(['unit.test']); + foreach ($items as $key => $item) { + $this->assertSame('unit.test', $key); + } + } + + /** + * @covers ::hasItem + */ + public function testHasItem(): void + { + $adapter = new ArrayAdapter(); + + $this->assertFalse($adapter->hasItem('item.key')); + } + + /** + * @covers ::clear + */ + public function testClear(): void + { + $adapter = new ArrayAdapter(); + + $this->assertTrue($adapter->clear()); + } + + /** + * @covers ::deleteItem + */ + public function testDeleteHasItem(): void + { + $adapter = new ArrayAdapter(); + + $this->assertTrue($adapter->deleteItem('item.key')); + } + + /** + * @covers ::deleteItems + */ + public function testDeleteHasItems(): void + { + $adapter = new ArrayAdapter(); + + $this->assertTrue($adapter->deleteItems(['item.key'])); + } + + /** + * @covers ::commit + */ + public function testCommit(): void + { + $adapter = new ArrayAdapter(); + + $this->assertTrue($adapter->commit()); + } + + /** + * @covers ::save + */ + public function testSave(): void + { + $adapter = new ArrayAdapter(); + + $this->assertTrue($adapter->save($this->createMock(CacheItemInterface::class))); + } + + /** + * @covers ::saveDeferred + */ + public function testSaveDeferred(): void + { + $adapter = new ArrayAdapter(); + + $this->assertTrue($adapter->saveDeferred($this->createMock(CacheItemInterface::class))); + } +} diff --git a/src/SonsOfPHP/Component/Cache/Tests/Adapter/NullAdapterTest.php b/src/SonsOfPHP/Component/Cache/Tests/Adapter/NullAdapterTest.php new file mode 100644 index 00000000..bd83ec84 --- /dev/null +++ b/src/SonsOfPHP/Component/Cache/Tests/Adapter/NullAdapterTest.php @@ -0,0 +1,125 @@ +assertInstanceOf(AdapterInterface::class, $adapter); + $this->assertInstanceOf(CacheItemPoolInterface::class, $adapter); + } + + /** + * @covers ::getItem + */ + public function testGetItem(): void + { + $adapter = new NullAdapter(); + $item = $adapter->getItem('unit.test'); + + $this->assertInstanceOf(CacheItemInterface::class, $item); + } + + /** + * @covers ::getItems + */ + public function testGetItems(): void + { + $adapter = new NullAdapter(); + $items = $adapter->getItems(['unit.test']); + foreach ($items as $key => $item) { + $this->assertSame('unit.test', $key); + } + } + + /** + * @covers ::hasItem + */ + public function testHasItem(): void + { + $adapter = new NullAdapter(); + + $this->assertFalse($adapter->hasItem('item.key')); + } + + /** + * @covers ::clear + */ + public function testClear(): void + { + $adapter = new NullAdapter(); + + $this->assertTrue($adapter->clear()); + } + + /** + * @covers ::deleteItem + */ + public function testDeleteHasItem(): void + { + $adapter = new NullAdapter(); + + $this->assertTrue($adapter->deleteItem('item.key')); + } + + /** + * @covers ::deleteItems + */ + public function testDeleteHasItems(): void + { + $adapter = new NullAdapter(); + + $this->assertTrue($adapter->deleteItems(['item.key'])); + } + + /** + * @covers ::commit + */ + public function testCommit(): void + { + $adapter = new NullAdapter(); + + $this->assertTrue($adapter->commit()); + } + + /** + * @covers ::save + */ + public function testSave(): void + { + $adapter = new NullAdapter(); + + $this->assertTrue($adapter->save($this->createMock(CacheItemInterface::class))); + } + + /** + * @covers ::saveDeferred + */ + public function testSaveDeferred(): void + { + $adapter = new NullAdapter(); + + $this->assertTrue($adapter->saveDeferred($this->createMock(CacheItemInterface::class))); + } +} diff --git a/src/SonsOfPHP/Component/Cache/Tests/CacheItemTest.php b/src/SonsOfPHP/Component/Cache/Tests/CacheItemTest.php index 53d7b5ef..73ccc0d0 100644 --- a/src/SonsOfPHP/Component/Cache/Tests/CacheItemTest.php +++ b/src/SonsOfPHP/Component/Cache/Tests/CacheItemTest.php @@ -66,6 +66,36 @@ public function testSetWorksAsExpected(): void $this->assertSame('value', $item->get()); } + /** + * @covers ::expiresAt + */ + public function testExpiresAtWorksAsExpectedWithNull(): void + { + $item = new CacheItem('testing'); + $item->expiresAfter(3600); + $itemAsArray = (array) $item; + $this->assertNotNull($itemAsArray["\0*\0expiry"]); + + $item->expiresAt(null); + $itemAsArray = (array) $item; + $this->assertNull($itemAsArray["\0*\0expiry"]); + } + + /** + * @covers ::expiresAt + */ + public function testExpiresAtWorksAsExpectedWithDateTimeInterface(): void + { + $item = new CacheItem('testing'); + $itemAsArray = (array) $item; + $this->assertFalse(isset($itemAsArray["\0*\0expiry"])); + + $item->expiresAt(new \DateTimeImmutable('2020-04-20 04:20:00')); + $itemAsArray = (array) $item; + $this->assertNotNull($itemAsArray["\0*\0expiry"]); + $this->assertSame(1587356400.0, $itemAsArray["\0*\0expiry"]); + } + /** * @covers ::expiresAfter */ @@ -79,4 +109,32 @@ public function testExpiresAfterWorksAsExpectedWithIntegers(): void $itemAsArray = (array) $item; $this->assertNotNull($itemAsArray["\0*\0expiry"]); } + + /** + * @covers ::expiresAfter + */ + public function testExpiresAfterWorksAsExpectedWithDateInterval(): void + { + $item = new CacheItem('testing'); + $itemAsArray = (array) $item; + $this->assertFalse(isset($itemAsArray["\0*\0expiry"])); + + $item->expiresAfter(new \DateInterval('PT60S')); + $itemAsArray = (array) $item; + $this->assertNotNull($itemAsArray["\0*\0expiry"]); + } + + /** + * @covers ::expiresAfter + */ + public function testExpiresAfterWorksAsExpectedWithNull(): void + { + $item = new CacheItem('testing'); + $itemAsArray = (array) $item; + $this->assertFalse(isset($itemAsArray["\0*\0expiry"])); + + $item->expiresAfter(null); + $itemAsArray = (array) $item; + $this->assertNull($itemAsArray["\0*\0expiry"]); + } } diff --git a/src/SonsOfPHP/Component/Cache/Tests/CacheTest.php b/src/SonsOfPHP/Component/Cache/Tests/CacheTest.php index 70147a84..3ad26932 100644 --- a/src/SonsOfPHP/Component/Cache/Tests/CacheTest.php +++ b/src/SonsOfPHP/Component/Cache/Tests/CacheTest.php @@ -8,6 +8,7 @@ use SonsOfPHP\Component\Cache\Cache; use Psr\SimpleCache\CacheInterface; use SonsOfPHP\Component\Cache\Adapter\AdapterInterface; +use Psr\Cache\CacheItemInterface; /** * @coversDefaultClass \SonsOfPHP\Component\Cache\Cache @@ -24,7 +25,7 @@ public function setUp(): void } /** - * @coversNothing + * @covers ::__construct */ public function testItHasTheCorrectInterface(): void { @@ -32,4 +33,144 @@ public function testItHasTheCorrectInterface(): void $this->assertInstanceOf(CacheInterface::class, $cache); } + + /** + * @covers ::get + */ + public function testGetWhenHit(): void + { + $item = $this->createMock(CacheItemInterface::class); + $item->method('isHit')->willReturn(true); + $item->method('get')->willReturn('item.value'); + + $this->adapter->method('getItem')->willReturn($item); + + $cache = new Cache($this->adapter); + + $this->assertSame('item.value', $cache->get('item.key')); + } + + /** + * @covers ::get + */ + public function testGetWhenMiss(): void + { + $item = $this->createMock(CacheItemInterface::class); + $item->method('isHit')->willReturn(false); + + $this->adapter->method('getItem')->willReturn($item); + + $cache = new Cache($this->adapter); + + $this->assertSame('default.value', $cache->get('item.key', 'default.value')); + } + + /** + * @covers ::delete + */ + public function testDelete(): void + { + $this->adapter->expects($this->once())->method('deleteItem')->willReturn(true); + + $cache = new Cache($this->adapter); + + $this->assertTrue($cache->delete('item.key')); + } + + /** + * @covers ::clear + */ + public function testClear(): void + { + $this->adapter->expects($this->once())->method('clear')->willReturn(true); + + $cache = new Cache($this->adapter); + + $this->assertTrue($cache->clear()); + } + + /** + * @covers ::has + */ + public function testHas(): void + { + $this->adapter->expects($this->once())->method('hasItem')->willReturn(false); + + $cache = new Cache($this->adapter); + + $this->assertFalse($cache->has('item.key')); + } + + /** + * @covers ::deleteMultiple + */ + public function testDeleteMultiple(): void + { + $this->adapter->expects($this->once())->method('deleteItems')->willReturn(true); + + $cache = new Cache($this->adapter); + + $this->assertTrue($cache->deleteMultiple(['item.key'])); + } + + /** + * @covers ::set + */ + public function testSet(): void + { + $item = $this->createMock(CacheItemInterface::class); + $item->expects($this->once())->method('set'); + + $this->adapter->expects($this->once())->method('getItem')->willReturn($item); + $this->adapter->expects($this->once())->method('save')->willReturn(true); + + $cache = new Cache($this->adapter); + + $this->assertTrue($cache->set('item.key', 'item.value')); + } + + /** + * @covers ::setMultiple + */ + public function testSetMultiple(): void + { + $item = $this->createMock(CacheItemInterface::class); + $item->expects($this->once())->method('set'); + + $this->adapter->expects($this->once())->method('getItem')->willReturn($item); + $this->adapter->expects($this->once())->method('save')->willReturn(true); + + $cache = new Cache($this->adapter); + + $this->assertTrue($cache->setMultiple(['item.key' => 'item.value'])); + } + + /** + * @covers ::getMultiple + */ + public function testGetMultiple(): void + { + $item = $this->createMock(CacheItemInterface::class); + $item->expects($this->never())->method('get'); + $item->expects($this->once())->method('isHit')->willReturn(false); + + $item2 = $this->createMock(CacheItemInterface::class); + $item2->expects($this->once())->method('get')->willReturn('item2.value'); + $item2->expects($this->once())->method('isHit')->willReturn(true); + + $this->adapter->expects($this->once())->method('getItems')->willReturn([ + 'item.key' => $item, + 'item2' => $item2, + ]); + + $cache = new Cache($this->adapter); + + $items = iterator_to_array($cache->getMultiple(['item.key', 'item2'], 'default.value')); + + $this->assertArrayHasKey('item.key', $items); + $this->assertArrayHasKey('item2', $items); + + $this->assertSame('default.value', $items['item.key']); + $this->assertSame('item2.value', $items['item2']); + } } From b7eb6c3cef318eac9666a4ed38fdcf7a40fbc637 Mon Sep 17 00:00:00 2001 From: Joshua Estes Date: Tue, 7 Nov 2023 10:11:40 -0500 Subject: [PATCH 12/29] updates --- src/SonsOfPHP/Component/Cache/CacheItemFactory.php | 5 +++-- src/SonsOfPHP/Component/Cache/CacheItemFactoryInterface.php | 2 +- src/SonsOfPHP/Component/Cache/TaggableCacheItemInterface.php | 2 +- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/SonsOfPHP/Component/Cache/CacheItemFactory.php b/src/SonsOfPHP/Component/Cache/CacheItemFactory.php index 5d397667..2bccd817 100644 --- a/src/SonsOfPHP/Component/Cache/CacheItemFactory.php +++ b/src/SonsOfPHP/Component/Cache/CacheItemFactory.php @@ -11,10 +11,11 @@ */ final class CacheItemFactroy implements CacheItemFactroyInterface { - public function createCacheItem(string $key, mixed $value, bool $isHit = false): CacheItemInterface + public function createCacheItem(string $key, mixed $value, bool $hit = false, int $ttl = 0): CacheItemInterface { - $item = new CacheItem($key, $isHit); + $item = new CacheItem($key, $hit); $item->set($value); + $item->expiresAfter($ttl); return $item; } diff --git a/src/SonsOfPHP/Component/Cache/CacheItemFactoryInterface.php b/src/SonsOfPHP/Component/Cache/CacheItemFactoryInterface.php index 3579d4f3..1f8d0866 100644 --- a/src/SonsOfPHP/Component/Cache/CacheItemFactoryInterface.php +++ b/src/SonsOfPHP/Component/Cache/CacheItemFactoryInterface.php @@ -13,5 +13,5 @@ interface CacheItemFactroyInterface { /** */ - public function createCacheItem(string $key, mixed $value, bool $isHit = false): CacheItemInterface; + public function createCacheItem(string $key, mixed $value, bool $hit = false, int $ttl = 0): CacheItemInterface; } diff --git a/src/SonsOfPHP/Component/Cache/TaggableCacheItemInterface.php b/src/SonsOfPHP/Component/Cache/TaggableCacheItemInterface.php index 31e85797..82621c33 100644 --- a/src/SonsOfPHP/Component/Cache/TaggableCacheItemInterface.php +++ b/src/SonsOfPHP/Component/Cache/TaggableCacheItemInterface.php @@ -11,5 +11,5 @@ */ interface TaggableCacheItem extends CacheItemInterface { - public function setTags(array $tags); + public function getTags(): iterable; } From 008887f83210c02caf18db1b4ef6f6922627976e Mon Sep 17 00:00:00 2001 From: Joshua Estes Date: Tue, 7 Nov 2023 10:26:19 -0500 Subject: [PATCH 13/29] chaning name --- .../Component/Cache/Adapter/ChainAdapter.php | 124 ++++++++++++++++++ .../Cache/{Cache.php => SimpleCache.php} | 4 +- .../Component/Cache/Tests/CacheTest.php | 28 ++-- 3 files changed, 140 insertions(+), 16 deletions(-) rename src/SonsOfPHP/Component/Cache/{Cache.php => SimpleCache.php} (96%) diff --git a/src/SonsOfPHP/Component/Cache/Adapter/ChainAdapter.php b/src/SonsOfPHP/Component/Cache/Adapter/ChainAdapter.php index ac350e78..69cd3b88 100644 --- a/src/SonsOfPHP/Component/Cache/Adapter/ChainAdapter.php +++ b/src/SonsOfPHP/Component/Cache/Adapter/ChainAdapter.php @@ -4,11 +4,135 @@ namespace SonsOfPHP\Component\Cache\Adapter; +use SonsOfPHP\Component\Cache\Exception\CacheException; + /** * Chains multiple adapters together to allow for multi-layer caches * + * This will write to all, but only pull from the first adapter + * + * Usage: + * $adapter = new ChainAdapter([ + * new ArrayAdapter(), + * new NativeFilesystemAdapter(), + * new RedisAdapter(), + * ]); + * * @author Joshua Estes */ class ChainAdapter implements AdapterInterface { + public function __construct( + private array $adapters, + ) { + foreach ($this->adapters as $adapter) { + if (!$adapter instanceof AdapterInterface) { + throw new CacheException('Invalid Adapter, must implement AdapterInterface'); + } + } + } + + /** + * {@inheritdoc} + */ + public function getItem(string $key): CacheItemInterface + { + return $this->adapters[0]->getItem($key); + } + + /** + * {@inheritdoc} + */ + public function getItems(array $keys = []): iterable + { + foreach ($keys as $key) { + yield $key => $this->getItem($key); + } + } + + /** + * {@inheritdoc} + */ + public function hasItem(string $key): bool + { + foreach ($this->adapters as $adapter) { + if ($adapter->hasItem($key)) { + return true; + } + } + + return false; + } + + /** + * {@inheritdoc} + */ + public function clear(): bool + { + foreach ($this->adapters as $adapter) { + $adapter->clear(); + } + + return true; + } + + /** + * {@inheritdoc} + */ + public function deleteItem(string $key): bool + { + foreach ($this->adapters as $adapter) { + $adapter->deleteItem($key); + } + + return true; + } + + /** + * {@inheritdoc} + */ + public function deleteItems(array $keys): bool + { + foreach ($this->adapters as $adapter) { + $adapter->deleteItems($keys); + } + + return true; + } + + /** + * {@inheritdoc} + */ + public function save(CacheItemInterface $item): bool + { + foreach ($this->adapters as $adapter) { + $adapter->save($item); + } + + return true; + } + + /** + * {@inheritdoc} + */ + public function saveDeferred(CacheItemInterface $item): bool + { + foreach ($this->adapters as $adapter) { + $adapter->saveDeferred($item); + } + + return true; + } + + /** + * {@inheritdoc} + */ + public function commit(): bool + { + foreach ($this->adapters as $adapter) { + $adapter->commit(); + } + + return true; + } } diff --git a/src/SonsOfPHP/Component/Cache/Cache.php b/src/SonsOfPHP/Component/Cache/SimpleCache.php similarity index 96% rename from src/SonsOfPHP/Component/Cache/Cache.php rename to src/SonsOfPHP/Component/Cache/SimpleCache.php index 532e8661..c30f3d1d 100644 --- a/src/SonsOfPHP/Component/Cache/Cache.php +++ b/src/SonsOfPHP/Component/Cache/SimpleCache.php @@ -8,11 +8,11 @@ use Psr\Cache\CacheItemPoolInterface; /** - * Simple Cache + * PSR-16 Simple Cache * * @author Joshua Estes */ -final class Cache implements CacheInterface +final class SimpleCache implements CacheInterface { /** * @codeCoverageIgnore diff --git a/src/SonsOfPHP/Component/Cache/Tests/CacheTest.php b/src/SonsOfPHP/Component/Cache/Tests/CacheTest.php index 3ad26932..7d7880ae 100644 --- a/src/SonsOfPHP/Component/Cache/Tests/CacheTest.php +++ b/src/SonsOfPHP/Component/Cache/Tests/CacheTest.php @@ -5,17 +5,17 @@ namespace SonsOfPHP\Component\Cache\Tests; use PHPUnit\Framework\TestCase; -use SonsOfPHP\Component\Cache\Cache; +use SonsOfPHP\Component\Cache\SimpleCache; use Psr\SimpleCache\CacheInterface; use SonsOfPHP\Component\Cache\Adapter\AdapterInterface; use Psr\Cache\CacheItemInterface; /** - * @coversDefaultClass \SonsOfPHP\Component\Cache\Cache + * @coversDefaultClass \SonsOfPHP\Component\Cache\SimpleCache * - * @uses \SonsOfPHP\Component\Cache\Cache + * @uses \SonsOfPHP\Component\Cache\SimpleCache */ -final class CacheTest extends TestCase +final class SimpleCacheTest extends TestCase { private $adapter; @@ -29,7 +29,7 @@ public function setUp(): void */ public function testItHasTheCorrectInterface(): void { - $cache = new Cache($this->adapter); + $cache = new SimpleCache($this->adapter); $this->assertInstanceOf(CacheInterface::class, $cache); } @@ -45,7 +45,7 @@ public function testGetWhenHit(): void $this->adapter->method('getItem')->willReturn($item); - $cache = new Cache($this->adapter); + $cache = new SimpleCache($this->adapter); $this->assertSame('item.value', $cache->get('item.key')); } @@ -60,7 +60,7 @@ public function testGetWhenMiss(): void $this->adapter->method('getItem')->willReturn($item); - $cache = new Cache($this->adapter); + $cache = new SimpleCache($this->adapter); $this->assertSame('default.value', $cache->get('item.key', 'default.value')); } @@ -72,7 +72,7 @@ public function testDelete(): void { $this->adapter->expects($this->once())->method('deleteItem')->willReturn(true); - $cache = new Cache($this->adapter); + $cache = new SimpleCache($this->adapter); $this->assertTrue($cache->delete('item.key')); } @@ -84,7 +84,7 @@ public function testClear(): void { $this->adapter->expects($this->once())->method('clear')->willReturn(true); - $cache = new Cache($this->adapter); + $cache = new SimpleCache($this->adapter); $this->assertTrue($cache->clear()); } @@ -96,7 +96,7 @@ public function testHas(): void { $this->adapter->expects($this->once())->method('hasItem')->willReturn(false); - $cache = new Cache($this->adapter); + $cache = new SimpleCache($this->adapter); $this->assertFalse($cache->has('item.key')); } @@ -108,7 +108,7 @@ public function testDeleteMultiple(): void { $this->adapter->expects($this->once())->method('deleteItems')->willReturn(true); - $cache = new Cache($this->adapter); + $cache = new SimpleCache($this->adapter); $this->assertTrue($cache->deleteMultiple(['item.key'])); } @@ -124,7 +124,7 @@ public function testSet(): void $this->adapter->expects($this->once())->method('getItem')->willReturn($item); $this->adapter->expects($this->once())->method('save')->willReturn(true); - $cache = new Cache($this->adapter); + $cache = new SimpleCache($this->adapter); $this->assertTrue($cache->set('item.key', 'item.value')); } @@ -140,7 +140,7 @@ public function testSetMultiple(): void $this->adapter->expects($this->once())->method('getItem')->willReturn($item); $this->adapter->expects($this->once())->method('save')->willReturn(true); - $cache = new Cache($this->adapter); + $cache = new SimpleCache($this->adapter); $this->assertTrue($cache->setMultiple(['item.key' => 'item.value'])); } @@ -163,7 +163,7 @@ public function testGetMultiple(): void 'item2' => $item2, ]); - $cache = new Cache($this->adapter); + $cache = new SimpleCache($this->adapter); $items = iterator_to_array($cache->getMultiple(['item.key', 'item2'], 'default.value')); From 3c33a1ea4174cac86d19031a623f7ac6248452a1 Mon Sep 17 00:00:00 2001 From: Joshua Estes Date: Tue, 7 Nov 2023 11:03:38 -0500 Subject: [PATCH 14/29] meh --- .../Component/Cache/Adapter/ApcuAdapter.php | 117 ++++++++++++++++++ .../Component/Cache/Adapter/ArrayAdapter.php | 1 - .../Component/Cache/Adapter/ChainAdapter.php | 3 + .../Cache/Adapter/FilesystemAdapter.php | 12 -- .../Cache/Adapter/NativeFilesystemAdapter.php | 12 -- .../Cache/Tests/Adapter/ArrayAdapterTest.php | 1 - .../Cache/Tests/Adapter/NullAdapterTest.php | 1 - src/SonsOfPHP/Component/Cache/composer.json | 8 +- 8 files changed, 125 insertions(+), 30 deletions(-) create mode 100644 src/SonsOfPHP/Component/Cache/Adapter/ApcuAdapter.php delete mode 100644 src/SonsOfPHP/Component/Cache/Adapter/FilesystemAdapter.php delete mode 100644 src/SonsOfPHP/Component/Cache/Adapter/NativeFilesystemAdapter.php diff --git a/src/SonsOfPHP/Component/Cache/Adapter/ApcuAdapter.php b/src/SonsOfPHP/Component/Cache/Adapter/ApcuAdapter.php new file mode 100644 index 00000000..1fc6e15c --- /dev/null +++ b/src/SonsOfPHP/Component/Cache/Adapter/ApcuAdapter.php @@ -0,0 +1,117 @@ + + */ +class ApcuAdapter implements AdapterInterface +{ + private array $deferred = []; + + public function __construct() + { + if (!extension_loaded('apcu') || !filter_var(ini_get('apc.enabled'), FILTER_VALIDATE_BOOL)) { + throw new CacheException('APCu extension is required.'); + } + } + + /** + * {@inheritdoc} + */ + public function getItem(string $key): CacheItemInterface + { + if ($this->hasItem($key)) { + return (new CacheItem($key, true))->set(apcu_fetch($key)); + } + + return new CacheItem($key, false); + } + + /** + * {@inheritdoc} + */ + public function getItems(array $keys = []): iterable + { + foreach ($keys as $key) { + yield $key => $this->getItem($key); + } + } + + /** + * {@inheritdoc} + */ + public function hasItem(string $key): bool + { + return apcu_exists($key); + } + + /** + * {@inheritdoc} + */ + public function clear(): bool + { + return apcu_clear_cache(); + } + + /** + * {@inheritdoc} + */ + public function deleteItem(string $key): bool + { + return apcu_delete($key); + } + + /** + * {@inheritdoc} + */ + public function deleteItems(array $keys): bool + { + $return = true; + foreach (apcu_delete($keys) as $key => $result) { + if (!$result) { + $return = false; + } + } + + return $return; + } + + /** + * {@inheritdoc} + */ + public function save(CacheItemInterface $item): bool + { + $this->saveDeferred($item); + + return $this->commit(); + } + + /** + * {@inheritdoc} + */ + public function saveDeferred(CacheItemInterface $item): bool + { + $this->deferred[$item->getKey] = $item; + + return true; + } + + /** + * {@inheritdoc} + */ + public function commit(): bool + { + foreach ($this->deferred as $key => $item) { + apcu_store($key, $item->get(), 0); + } + + return true; + } +} diff --git a/src/SonsOfPHP/Component/Cache/Adapter/ArrayAdapter.php b/src/SonsOfPHP/Component/Cache/Adapter/ArrayAdapter.php index 6ecc3f3a..19c45b5d 100644 --- a/src/SonsOfPHP/Component/Cache/Adapter/ArrayAdapter.php +++ b/src/SonsOfPHP/Component/Cache/Adapter/ArrayAdapter.php @@ -5,7 +5,6 @@ namespace SonsOfPHP\Component\Cache\Adapter; use Psr\Cache\CacheItemInterface; -use SonsOfPHP\Component\Cache\Exception\InvalidArgumentException; use SonsOfPHP\Component\Cache\CacheItem; /** diff --git a/src/SonsOfPHP/Component/Cache/Adapter/ChainAdapter.php b/src/SonsOfPHP/Component/Cache/Adapter/ChainAdapter.php index 69cd3b88..9051b1ec 100644 --- a/src/SonsOfPHP/Component/Cache/Adapter/ChainAdapter.php +++ b/src/SonsOfPHP/Component/Cache/Adapter/ChainAdapter.php @@ -4,6 +4,8 @@ namespace SonsOfPHP\Component\Cache\Adapter; +use SonsOfPHP\Component\Cache\CacheItem; +use Psr\Cache\CacheItemInterface; use SonsOfPHP\Component\Cache\Exception\CacheException; /** @@ -14,6 +16,7 @@ * Usage: * $adapter = new ChainAdapter([ * new ArrayAdapter(), + * new ApcuAdapter(), * new NativeFilesystemAdapter(), * new RedisAdapter(), * ]); diff --git a/src/SonsOfPHP/Component/Cache/Adapter/FilesystemAdapter.php b/src/SonsOfPHP/Component/Cache/Adapter/FilesystemAdapter.php deleted file mode 100644 index e87a2b2f..00000000 --- a/src/SonsOfPHP/Component/Cache/Adapter/FilesystemAdapter.php +++ /dev/null @@ -1,12 +0,0 @@ - - */ -class FilesystemAdapter implements AdapterInterface {} diff --git a/src/SonsOfPHP/Component/Cache/Adapter/NativeFilesystemAdapter.php b/src/SonsOfPHP/Component/Cache/Adapter/NativeFilesystemAdapter.php deleted file mode 100644 index 01b36160..00000000 --- a/src/SonsOfPHP/Component/Cache/Adapter/NativeFilesystemAdapter.php +++ /dev/null @@ -1,12 +0,0 @@ - - */ -class NativeFilesystemAdapter implements AdapterInterface {} diff --git a/src/SonsOfPHP/Component/Cache/Tests/Adapter/ArrayAdapterTest.php b/src/SonsOfPHP/Component/Cache/Tests/Adapter/ArrayAdapterTest.php index 6e811c4a..ce163c9b 100644 --- a/src/SonsOfPHP/Component/Cache/Tests/Adapter/ArrayAdapterTest.php +++ b/src/SonsOfPHP/Component/Cache/Tests/Adapter/ArrayAdapterTest.php @@ -6,7 +6,6 @@ use PHPUnit\Framework\TestCase; use SonsOfPHP\Component\Cache\Adapter\ArrayAdapter; -use Psr\SimpleCache\CacheInterface; use SonsOfPHP\Component\Cache\Adapter\AdapterInterface; use Psr\Cache\CacheItemPoolInterface; use Psr\Cache\CacheItemInterface; diff --git a/src/SonsOfPHP/Component/Cache/Tests/Adapter/NullAdapterTest.php b/src/SonsOfPHP/Component/Cache/Tests/Adapter/NullAdapterTest.php index bd83ec84..421c9cf9 100644 --- a/src/SonsOfPHP/Component/Cache/Tests/Adapter/NullAdapterTest.php +++ b/src/SonsOfPHP/Component/Cache/Tests/Adapter/NullAdapterTest.php @@ -6,7 +6,6 @@ use PHPUnit\Framework\TestCase; use SonsOfPHP\Component\Cache\Adapter\NullAdapter; -use Psr\SimpleCache\CacheInterface; use SonsOfPHP\Component\Cache\Adapter\AdapterInterface; use Psr\Cache\CacheItemPoolInterface; use Psr\Cache\CacheItemInterface; diff --git a/src/SonsOfPHP/Component/Cache/composer.json b/src/SonsOfPHP/Component/Cache/composer.json index 02d84cba..51424838 100644 --- a/src/SonsOfPHP/Component/Cache/composer.json +++ b/src/SonsOfPHP/Component/Cache/composer.json @@ -1,7 +1,7 @@ { "name": "sonsofphp/cache", "type": "library", - "description": "", + "description": "Caching library for php", "keywords": [ "psr", "psr-6", @@ -33,14 +33,16 @@ "prefer-stable": true, "require": { "php": ">=8.1", - "psr/cache": "^1.0|^2.0|^3.0", + "psr/cache": "^2.0|^3.0" + }, + "require-dev": { "psr/simple-cache": "^1.0|^2.0|^3.0" }, "suggest": { "sonsofphp/filesystem": "Stores cache files using virtual filesystem" }, "provide": { - "psr/cache-implementation": "^1.0|^2.0|^3.0", + "psr/cache-implementation": "^2.0|^3.0", "psr/simple-cache-implementation": "^1.0|^2.0|^3.0" }, "extra": { From 44cdd66dc83d4d0032e7f94ab2263b0f97e9c725 Mon Sep 17 00:00:00 2001 From: Joshua Estes Date: Tue, 7 Nov 2023 11:32:58 -0500 Subject: [PATCH 15/29] testing --- .../Component/Cache/Adapter/ApcuAdapter.php | 2 +- .../Component/Cache/CacheItemFactory.php | 2 +- .../Cache/CacheItemFactoryInterface.php | 4 +- .../Cache/Tests/Adapter/ApcuAdapterTest.php | 124 +++++++++++++++++ .../Cache/Tests/Adapter/ChainAdapterTest.php | 131 ++++++++++++++++++ .../Cache/Tests/CacheItemFactoryTest.php | 40 ++++++ 6 files changed, 298 insertions(+), 5 deletions(-) create mode 100644 src/SonsOfPHP/Component/Cache/Tests/Adapter/ApcuAdapterTest.php create mode 100644 src/SonsOfPHP/Component/Cache/Tests/Adapter/ChainAdapterTest.php create mode 100644 src/SonsOfPHP/Component/Cache/Tests/CacheItemFactoryTest.php diff --git a/src/SonsOfPHP/Component/Cache/Adapter/ApcuAdapter.php b/src/SonsOfPHP/Component/Cache/Adapter/ApcuAdapter.php index 1fc6e15c..6dc6afa5 100644 --- a/src/SonsOfPHP/Component/Cache/Adapter/ApcuAdapter.php +++ b/src/SonsOfPHP/Component/Cache/Adapter/ApcuAdapter.php @@ -98,7 +98,7 @@ public function save(CacheItemInterface $item): bool */ public function saveDeferred(CacheItemInterface $item): bool { - $this->deferred[$item->getKey] = $item; + $this->deferred[$item->getKey()] = $item; return true; } diff --git a/src/SonsOfPHP/Component/Cache/CacheItemFactory.php b/src/SonsOfPHP/Component/Cache/CacheItemFactory.php index 2bccd817..db21fe85 100644 --- a/src/SonsOfPHP/Component/Cache/CacheItemFactory.php +++ b/src/SonsOfPHP/Component/Cache/CacheItemFactory.php @@ -9,7 +9,7 @@ /** * @author Joshua Estes */ -final class CacheItemFactroy implements CacheItemFactroyInterface +final class CacheItemFactory implements CacheItemFactoryInterface { public function createCacheItem(string $key, mixed $value, bool $hit = false, int $ttl = 0): CacheItemInterface { diff --git a/src/SonsOfPHP/Component/Cache/CacheItemFactoryInterface.php b/src/SonsOfPHP/Component/Cache/CacheItemFactoryInterface.php index 1f8d0866..76006dbf 100644 --- a/src/SonsOfPHP/Component/Cache/CacheItemFactoryInterface.php +++ b/src/SonsOfPHP/Component/Cache/CacheItemFactoryInterface.php @@ -9,9 +9,7 @@ /** * @author Joshua Estes */ -interface CacheItemFactroyInterface +interface CacheItemFactoryInterface { - /** - */ public function createCacheItem(string $key, mixed $value, bool $hit = false, int $ttl = 0): CacheItemInterface; } diff --git a/src/SonsOfPHP/Component/Cache/Tests/Adapter/ApcuAdapterTest.php b/src/SonsOfPHP/Component/Cache/Tests/Adapter/ApcuAdapterTest.php new file mode 100644 index 00000000..ecc8fe88 --- /dev/null +++ b/src/SonsOfPHP/Component/Cache/Tests/Adapter/ApcuAdapterTest.php @@ -0,0 +1,124 @@ +assertInstanceOf(AdapterInterface::class, $adapter); + $this->assertInstanceOf(CacheItemPoolInterface::class, $adapter); + } + + /** + * @covers ::getItem + */ + public function testGetItem(): void + { + $adapter = new ApcuAdapter(); + $item = $adapter->getItem('unit.test'); + + $this->assertInstanceOf(CacheItemInterface::class, $item); + } + + /** + * @covers ::getItems + */ + public function testGetItems(): void + { + $adapter = new ApcuAdapter(); + $items = $adapter->getItems(['unit.test']); + foreach ($items as $key => $item) { + $this->assertSame('unit.test', $key); + } + } + + /** + * @covers ::hasItem + */ + public function testHasItem(): void + { + $adapter = new ApcuAdapter(); + + $this->assertFalse($adapter->hasItem('item.key')); + } + + /** + * @covers ::clear + */ + public function testClear(): void + { + $adapter = new ApcuAdapter(); + + $this->assertTrue($adapter->clear()); + } + + /** + * @covers ::deleteItem + */ + public function testDeleteItem(): void + { + $adapter = new ApcuAdapter(); + + $this->assertFalse($adapter->deleteItem('item.key')); + } + + /** + * @covers ::deleteItems + */ + public function testDeleteItems(): void + { + $adapter = new ApcuAdapter(); + + $this->assertTrue($adapter->deleteItems(['item.key'])); + } + + /** + * @covers ::commit + */ + public function testCommit(): void + { + $adapter = new ApcuAdapter(); + + $this->assertTrue($adapter->commit()); + } + + /** + * @covers ::save + */ + public function testSave(): void + { + $adapter = new ApcuAdapter(); + + $this->assertTrue($adapter->save($this->createMock(CacheItemInterface::class))); + } + + /** + * @covers ::saveDeferred + */ + public function testSaveDeferred(): void + { + $adapter = new ApcuAdapter(); + + $this->assertTrue($adapter->saveDeferred($this->createMock(CacheItemInterface::class))); + } +} diff --git a/src/SonsOfPHP/Component/Cache/Tests/Adapter/ChainAdapterTest.php b/src/SonsOfPHP/Component/Cache/Tests/Adapter/ChainAdapterTest.php new file mode 100644 index 00000000..2b4a0130 --- /dev/null +++ b/src/SonsOfPHP/Component/Cache/Tests/Adapter/ChainAdapterTest.php @@ -0,0 +1,131 @@ +adapters[] = $this->createMock(AdapterInterface::class); + } + + /** + * @covers ::__construct + */ + public function testItHasTheCorrectInterface(): void + { + $adapter = new ChainAdapter($this->adapters); + + $this->assertInstanceOf(AdapterInterface::class, $adapter); + $this->assertInstanceOf(CacheItemPoolInterface::class, $adapter); + } + + /** + * @covers ::getItem + */ + public function testGetItem(): void + { + $adapter = new ChainAdapter($this->adapters); + $item = $adapter->getItem('unit.test'); + + $this->assertInstanceOf(CacheItemInterface::class, $item); + } + + /** + * @covers ::getItems + */ + public function testGetItems(): void + { + $adapter = new ChainAdapter($this->adapters); + $items = $adapter->getItems(['unit.test']); + foreach ($items as $key => $item) { + $this->assertSame('unit.test', $key); + } + } + + /** + * @covers ::hasItem + */ + public function testHasItem(): void + { + $adapter = new ChainAdapter($this->adapters); + + $this->assertFalse($adapter->hasItem('item.key')); + } + + /** + * @covers ::clear + */ + public function testClear(): void + { + $adapter = new ChainAdapter($this->adapters); + + $this->assertTrue($adapter->clear()); + } + + /** + * @covers ::deleteItem + */ + public function testDeleteHasItem(): void + { + $adapter = new ChainAdapter($this->adapters); + + $this->assertTrue($adapter->deleteItem('item.key')); + } + + /** + * @covers ::deleteItems + */ + public function testDeleteHasItems(): void + { + $adapter = new ChainAdapter($this->adapters); + + $this->assertTrue($adapter->deleteItems(['item.key'])); + } + + /** + * @covers ::commit + */ + public function testCommit(): void + { + $adapter = new ChainAdapter($this->adapters); + + $this->assertTrue($adapter->commit()); + } + + /** + * @covers ::save + */ + public function testSave(): void + { + $adapter = new ChainAdapter($this->adapters); + + $this->assertTrue($adapter->save($this->createMock(CacheItemInterface::class))); + } + + /** + * @covers ::saveDeferred + */ + public function testSaveDeferred(): void + { + $adapter = new ChainAdapter($this->adapters); + + $this->assertTrue($adapter->saveDeferred($this->createMock(CacheItemInterface::class))); + } +} diff --git a/src/SonsOfPHP/Component/Cache/Tests/CacheItemFactoryTest.php b/src/SonsOfPHP/Component/Cache/Tests/CacheItemFactoryTest.php new file mode 100644 index 00000000..097ec56c --- /dev/null +++ b/src/SonsOfPHP/Component/Cache/Tests/CacheItemFactoryTest.php @@ -0,0 +1,40 @@ +assertInstanceOf(CacheItemFactoryInterface::class, $factory); + } + + /** + * @covers ::createCacheItem + */ + public function testCreateCacheItem(): void + { + $factory = new CacheItemFactory(); + $item = $factory->createCacheItem(key: 'item.key', value: 'item.value'); + $this->assertSame('item.key', $item->getKey()); + $this->assertSame('item.value', $item->get()); + $this->assertFalse($item->isHit()); + } +} From 428a1daa12a91480cf6018b8935e0411facfd281 Mon Sep 17 00:00:00 2001 From: Joshua Estes Date: Tue, 7 Nov 2023 13:10:15 -0500 Subject: [PATCH 16/29] typos --- .../Component/Cache/TaggableCacheItemInterface.php | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/src/SonsOfPHP/Component/Cache/TaggableCacheItemInterface.php b/src/SonsOfPHP/Component/Cache/TaggableCacheItemInterface.php index 82621c33..ebbd9633 100644 --- a/src/SonsOfPHP/Component/Cache/TaggableCacheItemInterface.php +++ b/src/SonsOfPHP/Component/Cache/TaggableCacheItemInterface.php @@ -9,7 +9,17 @@ /** * @author Joshua Estes */ -interface TaggableCacheItem extends CacheItemInterface +interface TaggableCacheItemInterface { - public function getTags(): iterable; + /** + * Returns the tags on the cache item + */ + public function tags(): iterable; + + /** + * Adds tags to the cache item + * + * $item->tag('test'); + */ + public function tag(string|iterable $tags): static; } From a70a432972fa92af0df3ce6ae1105e4f6e10a1b2 Mon Sep 17 00:00:00 2001 From: Joshua Estes Date: Tue, 7 Nov 2023 13:53:50 -0500 Subject: [PATCH 17/29] bug fix --- src/SonsOfPHP/Component/Cache/Adapter/ApcuAdapter.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/SonsOfPHP/Component/Cache/Adapter/ApcuAdapter.php b/src/SonsOfPHP/Component/Cache/Adapter/ApcuAdapter.php index 6dc6afa5..3ea4987e 100644 --- a/src/SonsOfPHP/Component/Cache/Adapter/ApcuAdapter.php +++ b/src/SonsOfPHP/Component/Cache/Adapter/ApcuAdapter.php @@ -110,6 +110,7 @@ public function commit(): bool { foreach ($this->deferred as $key => $item) { apcu_store($key, $item->get(), 0); + unset($this->deferrred[$key]); } return true; From 0eb947d179371fe186530a60c8cc4b2d5129ed3a Mon Sep 17 00:00:00 2001 From: Joshua Estes Date: Tue, 7 Nov 2023 14:12:47 -0500 Subject: [PATCH 18/29] docs --- CHANGELOG.md | 1 + docs/components/cache/index.md | 55 +++++++++++++++++++ .../Component/Cache/Adapter/ChainAdapter.php | 8 ++- 3 files changed, 63 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 54393321..6a95b95b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -27,6 +27,7 @@ Examples: * [PR #59](https://github.com/SonsOfPHP/sonsofphp/pull/59) Added new HttpMessage component * [PR #59](https://github.com/SonsOfPHP/sonsofphp/pull/59) Added new HttpFactory component * [PR #70](https://github.com/SonsOfPHP/sonsofphp/pull/70) Added new Core contract +* [PR #112](https://github.com/SonsOfPHP/sonsofphp/pull/112) [Cache] Added new component ## [0.3.8] diff --git a/docs/components/cache/index.md b/docs/components/cache/index.md index ebb4b4f4..0e7b1894 100644 --- a/docs/components/cache/index.md +++ b/docs/components/cache/index.md @@ -9,3 +9,58 @@ Used for cache stuff ```shell composer require sonsofphp/cache ``` + +### PSR-16 - Simple Cache + +To add support for PSR-16 Simple Cache, require the PSR. + +```shell +composer require psr/simple-cache +``` + +## Usage + +```php +adapters[0]->getItem($key); + foreach ($this->adapters as $adapter) { + if ($adapter->hasItem($key)) { + return $adapter->getItem($key); + } + } + + return new CacheItem($key, false); } /** From 610ba42fde8d5ed9dfcbbe4149be10af7369f46c Mon Sep 17 00:00:00 2001 From: Joshua Estes Date: Tue, 7 Nov 2023 14:36:39 -0500 Subject: [PATCH 19/29] apcu tests --- Makefile | 14 ++++- .../Component/Cache/Adapter/ApcuAdapter.php | 11 ++-- .../Cache/Tests/Adapter/ApcuAdapterTest.php | 52 ++++++++++++++++++- 3 files changed, 66 insertions(+), 11 deletions(-) diff --git a/Makefile b/Makefile index de0c12b8..7ee8d4fd 100644 --- a/Makefile +++ b/Makefile @@ -39,7 +39,12 @@ purge: # Purge vendor and lock files rm -rf vendor/ src/SonsOfPHP/Component/*/vendor/ src/SonsOfPHP/Component/*/composer.lock test: ## Run PHPUnit Tests - XDEBUG_MODE=off $(PHP) -dxdebug.mode=off $(PHPUNIT) --order-by=defects + XDEBUG_MODE=off \ + $(PHP) \ + -dxdebug.mode=off \ + -dapc.enable_cli=1 \ + $(PHPUNIT) \ + --order-by=defects phpunit: test @@ -55,7 +60,12 @@ lint-php: # lint php files find src -name "*.php" -not -path "src/**/vendor/*" | xargs -I{} $(PHP) -l '{}' coverage: ## Build Code Coverage Report - XDEBUG_MODE=coverage $(PHP) -dxdebug.mode=coverage $(PHPUNIT) --coverage-html $(COVERAGE_DIR) + XDEBUG_MODE=coverage \ + $(PHP) \ + -dxdebug.mode=coverage \ + -dapc.enable_cli=1 \ + $(PHPUNIT) \ + --coverage-html $(COVERAGE_DIR) coverage-cache: XDEBUG_MODE=coverage $(PHP) -dxdebug.mode=coverage $(PHPUNIT) --testsuite cache --coverage-html $(COVERAGE_DIR) diff --git a/src/SonsOfPHP/Component/Cache/Adapter/ApcuAdapter.php b/src/SonsOfPHP/Component/Cache/Adapter/ApcuAdapter.php index 3ea4987e..8b942ea4 100644 --- a/src/SonsOfPHP/Component/Cache/Adapter/ApcuAdapter.php +++ b/src/SonsOfPHP/Component/Cache/Adapter/ApcuAdapter.php @@ -73,14 +73,9 @@ public function deleteItem(string $key): bool */ public function deleteItems(array $keys): bool { - $return = true; - foreach (apcu_delete($keys) as $key => $result) { - if (!$result) { - $return = false; - } - } + apcu_delete($keys); - return $return; + return true; } /** @@ -110,8 +105,8 @@ public function commit(): bool { foreach ($this->deferred as $key => $item) { apcu_store($key, $item->get(), 0); - unset($this->deferrred[$key]); } + $this->deferred = []; return true; } diff --git a/src/SonsOfPHP/Component/Cache/Tests/Adapter/ApcuAdapterTest.php b/src/SonsOfPHP/Component/Cache/Tests/Adapter/ApcuAdapterTest.php index ecc8fe88..775a18c4 100644 --- a/src/SonsOfPHP/Component/Cache/Tests/Adapter/ApcuAdapterTest.php +++ b/src/SonsOfPHP/Component/Cache/Tests/Adapter/ApcuAdapterTest.php @@ -18,6 +18,16 @@ */ final class ApcuAdapterTest extends TestCase { + public function setUp(): void + { + apcu_clear_cache(); + } + + protected function tearDown(): void + { + apcu_clear_cache(); + } + /** * @covers ::__construct */ @@ -40,6 +50,19 @@ public function testGetItem(): void $this->assertInstanceOf(CacheItemInterface::class, $item); } + /** + * @covers ::getItem + */ + public function testGetItemAfterSave(): void + { + $adapter = new ApcuAdapter(); + $item = $adapter->getItem('unit.test'); + $item->set('item.value'); + $adapter->save($item); + + $this->assertTrue($adapter->getItem('unit.test')->isHit()); + } + /** * @covers ::getItems */ @@ -85,7 +108,20 @@ public function testDeleteItem(): void /** * @covers ::deleteItems */ - public function testDeleteItems(): void + public function testDeleteItemsWithValuesInCache(): void + { + $adapter = new ApcuAdapter(); + $item = $adapter->getItem('unit.test'); + $item->set('item.value'); + $adapter->save($item); + + $this->assertTrue($adapter->deleteItems(['item.key', 'unit.test'])); + } + + /** + * @covers ::deleteItems + */ + public function testDeleteItemsWithEmptyCache(): void { $adapter = new ApcuAdapter(); @@ -112,6 +148,20 @@ public function testSave(): void $this->assertTrue($adapter->save($this->createMock(CacheItemInterface::class))); } + /** + * @covers ::save + */ + public function testSaveItemWithValue(): void + { + $adapter = new ApcuAdapter(); + $item = $adapter->getItem('unit.test'); + + $item->set('item.value'); + $adapter->save($item); + + $this->assertSame('item.value', $adapter->getItem('unit.test')->get()); + } + /** * @covers ::saveDeferred */ From 9dd89a7adfd9fda4c4e1cb27a6f41488e7686133 Mon Sep 17 00:00:00 2001 From: Joshua Estes Date: Tue, 7 Nov 2023 14:41:41 -0500 Subject: [PATCH 20/29] testing --- .../Cache/Tests/Adapter/ApcuAdapterTest.php | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/SonsOfPHP/Component/Cache/Tests/Adapter/ApcuAdapterTest.php b/src/SonsOfPHP/Component/Cache/Tests/Adapter/ApcuAdapterTest.php index 775a18c4..e157af2a 100644 --- a/src/SonsOfPHP/Component/Cache/Tests/Adapter/ApcuAdapterTest.php +++ b/src/SonsOfPHP/Component/Cache/Tests/Adapter/ApcuAdapterTest.php @@ -138,6 +138,21 @@ public function testCommit(): void $this->assertTrue($adapter->commit()); } + /** + * @covers ::commit + */ + public function testCommitWithDeferredValues(): void + { + $adapter = new ApcuAdapter(); + $item = $adapter->getItem('unit.test'); + $item->set('item.value'); + $adapter->saveDeferred($item); + + $this->assertFalse($adapter->hasItem('unit.test')); + $adapter->commit(); + $this->assertTrue($adapter->hasItem('unit.test')); + } + /** * @covers ::save */ From 801eca1cfc0e228740e9a76cd567602200a0ef4b Mon Sep 17 00:00:00 2001 From: Joshua Estes Date: Tue, 7 Nov 2023 14:45:41 -0500 Subject: [PATCH 21/29] makefile --- Makefile | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Makefile b/Makefile index 7ee8d4fd..fc89c623 100644 --- a/Makefile +++ b/Makefile @@ -37,6 +37,7 @@ purge: # Purge vendor and lock files rm -rf vendor/ src/SonsOfPHP/Bridge/*/vendor/ src/SonsOfPHP/Bridge/*/composer.lock rm -rf vendor/ src/SonsOfPHP/Bundle/*/vendor/ src/SonsOfPHP/Bundle/*/composer.lock rm -rf vendor/ src/SonsOfPHP/Component/*/vendor/ src/SonsOfPHP/Component/*/composer.lock + rm -rf vendor/ src/SonsOfPHP/Contract/*/vendor/ src/SonsOfPHP/Contract/*/composer.lock test: ## Run PHPUnit Tests XDEBUG_MODE=off \ @@ -44,6 +45,7 @@ test: ## Run PHPUnit Tests -dxdebug.mode=off \ -dapc.enable_cli=1 \ $(PHPUNIT) \ + --cache-result \ --order-by=defects phpunit: test @@ -65,6 +67,7 @@ coverage: ## Build Code Coverage Report -dxdebug.mode=coverage \ -dapc.enable_cli=1 \ $(PHPUNIT) \ + --cache-result \ --coverage-html $(COVERAGE_DIR) coverage-cache: From 228ad39231452262f600c126ab6493455d740e65 Mon Sep 17 00:00:00 2001 From: Joshua Estes Date: Tue, 7 Nov 2023 15:27:09 -0500 Subject: [PATCH 22/29] checkpoint --- .../Component/Cache/Adapter/NullAdapter.php | 8 +++++++- src/SonsOfPHP/Component/Cache/CacheItem.php | 18 ++++++++++++++++- .../Component/Cache/Tests/CacheItemTest.php | 20 ++++++++++++++++++- .../{CacheTest.php => SimpleCacheTest.php} | 0 4 files changed, 43 insertions(+), 3 deletions(-) rename src/SonsOfPHP/Component/Cache/Tests/{CacheTest.php => SimpleCacheTest.php} (100%) diff --git a/src/SonsOfPHP/Component/Cache/Adapter/NullAdapter.php b/src/SonsOfPHP/Component/Cache/Adapter/NullAdapter.php index 106a7a85..926b507d 100644 --- a/src/SonsOfPHP/Component/Cache/Adapter/NullAdapter.php +++ b/src/SonsOfPHP/Component/Cache/Adapter/NullAdapter.php @@ -35,7 +35,7 @@ public function getItems(array $keys = []): iterable */ public function hasItem(string $key): bool { - return false; + return $this->getItem($key)->isHit(); } /** @@ -51,6 +51,8 @@ public function clear(): bool */ public function deleteItem(string $key): bool { + CacheItem::validateKey($key); + return true; } @@ -59,6 +61,10 @@ public function deleteItem(string $key): bool */ public function deleteItems(array $keys): bool { + foreach ($keys as $key) { + CacheItem::validateKey($key); + } + return true; } diff --git a/src/SonsOfPHP/Component/Cache/CacheItem.php b/src/SonsOfPHP/Component/Cache/CacheItem.php index a396815d..0fdf5c76 100644 --- a/src/SonsOfPHP/Component/Cache/CacheItem.php +++ b/src/SonsOfPHP/Component/Cache/CacheItem.php @@ -5,6 +5,7 @@ namespace SonsOfPHP\Component\Cache; use Psr\Cache\CacheItemInterface; +use SonsOfPHP\Component\Cache\Exception\InvalidArgumentException; /** * @author Joshua Estes @@ -18,7 +19,22 @@ public function __construct( protected string $key, protected bool $isHit = false, ) { - // @todo throw exception for invalid key + static::validateKey($key); + } + + public static function validateKey(string $key): void + { + if ('' === $key) { + throw new InvalidArgumentException('$key is empty.'); + } + + if (1 === preg_match('/[\{\}\(\)\/\\\@\:]/', $key)) { + throw new InvalidArgumentException(sprintf('The key "%s" contains reserved characters', $key)); + } + + if (1 === preg_match('/[^A-Za-z0-9_.]/', $key)) { + throw new InvalidArgumentException(sprintf('The key "%s" is invalid. Only "A-Z", "a-z", "0-9", "_", and "." are allowed.', $key)); + } } /** diff --git a/src/SonsOfPHP/Component/Cache/Tests/CacheItemTest.php b/src/SonsOfPHP/Component/Cache/Tests/CacheItemTest.php index 73ccc0d0..ae9bde2d 100644 --- a/src/SonsOfPHP/Component/Cache/Tests/CacheItemTest.php +++ b/src/SonsOfPHP/Component/Cache/Tests/CacheItemTest.php @@ -7,6 +7,7 @@ use PHPUnit\Framework\TestCase; use SonsOfPHP\Component\Cache\CacheItem; use Psr\Cache\CacheItemInterface; +use SonsOfPHP\Component\Cache\Exception\InvalidArgumentException; /** * @coversDefaultClass \SonsOfPHP\Component\Cache\CacheItem @@ -16,7 +17,7 @@ final class CacheItemTest extends TestCase { /** - * @coversNothing + * @covers ::__construct */ public function testItHasTheCorrectInterface(): void { @@ -27,6 +28,23 @@ public function testItHasTheCorrectInterface(): void /** * @covers ::__construct + */ + public function testItWillThrowExceptionWhenInvalidKey(): void + { + $this->expectException(InvalidArgumentException::class); + $item = new CacheItem('not allowed'); + } + + /** + * @covers ::__construct + */ + public function testItWillThrowExceptionWhenKeyContainsReservedCharacters(): void + { + $this->expectException(InvalidArgumentException::class); + $item = new CacheItem('not@allowed'); + } + + /** * @covers ::getKey */ public function testGetKeyWorksAsExpected(): void diff --git a/src/SonsOfPHP/Component/Cache/Tests/CacheTest.php b/src/SonsOfPHP/Component/Cache/Tests/SimpleCacheTest.php similarity index 100% rename from src/SonsOfPHP/Component/Cache/Tests/CacheTest.php rename to src/SonsOfPHP/Component/Cache/Tests/SimpleCacheTest.php From 6383cc30cddbe1e5f3dd99af53de3faa262875c7 Mon Sep 17 00:00:00 2001 From: Joshua Estes Date: Tue, 7 Nov 2023 15:35:04 -0500 Subject: [PATCH 23/29] various updates --- .../Component/Cache/Adapter/ApcuAdapter.php | 13 +++++++++++-- .../Component/Cache/Adapter/ArrayAdapter.php | 4 ++++ .../Component/Cache/Adapter/ChainAdapter.php | 6 ++++++ .../Cache/Tests/Adapter/ApcuAdapterTest.php | 4 ++-- 4 files changed, 23 insertions(+), 4 deletions(-) diff --git a/src/SonsOfPHP/Component/Cache/Adapter/ApcuAdapter.php b/src/SonsOfPHP/Component/Cache/Adapter/ApcuAdapter.php index 8b942ea4..3c8931f8 100644 --- a/src/SonsOfPHP/Component/Cache/Adapter/ApcuAdapter.php +++ b/src/SonsOfPHP/Component/Cache/Adapter/ApcuAdapter.php @@ -49,6 +49,8 @@ public function getItems(array $keys = []): iterable */ public function hasItem(string $key): bool { + CacheItem::validateKey($key); + return apcu_exists($key); } @@ -65,6 +67,8 @@ public function clear(): bool */ public function deleteItem(string $key): bool { + CacheItem::validateKey($key); + return apcu_delete($key); } @@ -73,9 +77,14 @@ public function deleteItem(string $key): bool */ public function deleteItems(array $keys): bool { - apcu_delete($keys); + $ret = true; + foreach ($keys as $key) { + if (!$this->deleteItem($key)) { + $ret = false; + } + } - return true; + return $ret; } /** diff --git a/src/SonsOfPHP/Component/Cache/Adapter/ArrayAdapter.php b/src/SonsOfPHP/Component/Cache/Adapter/ArrayAdapter.php index 19c45b5d..ec79435c 100644 --- a/src/SonsOfPHP/Component/Cache/Adapter/ArrayAdapter.php +++ b/src/SonsOfPHP/Component/Cache/Adapter/ArrayAdapter.php @@ -41,6 +41,8 @@ public function getItems(array $keys = []): iterable */ public function hasItem(string $key): bool { + CacheItem::validateKey($key); + return array_key_exists($key, $this->values); } @@ -59,6 +61,8 @@ public function clear(): bool */ public function deleteItem(string $key): bool { + CacheItem::validateKey($key); + unset($this->values[$key]); return true; diff --git a/src/SonsOfPHP/Component/Cache/Adapter/ChainAdapter.php b/src/SonsOfPHP/Component/Cache/Adapter/ChainAdapter.php index 94361618..63b1a3f8 100644 --- a/src/SonsOfPHP/Component/Cache/Adapter/ChainAdapter.php +++ b/src/SonsOfPHP/Component/Cache/Adapter/ChainAdapter.php @@ -40,6 +40,8 @@ public function __construct( */ public function getItem(string $key): CacheItemInterface { + CacheItem::validateKey($key); + foreach ($this->adapters as $adapter) { if ($adapter->hasItem($key)) { return $adapter->getItem($key); @@ -64,6 +66,8 @@ public function getItems(array $keys = []): iterable */ public function hasItem(string $key): bool { + CacheItem::validateKey($key); + foreach ($this->adapters as $adapter) { if ($adapter->hasItem($key)) { return true; @@ -90,6 +94,8 @@ public function clear(): bool */ public function deleteItem(string $key): bool { + CacheItem::validateKey($key); + foreach ($this->adapters as $adapter) { $adapter->deleteItem($key); } diff --git a/src/SonsOfPHP/Component/Cache/Tests/Adapter/ApcuAdapterTest.php b/src/SonsOfPHP/Component/Cache/Tests/Adapter/ApcuAdapterTest.php index e157af2a..ec4fae19 100644 --- a/src/SonsOfPHP/Component/Cache/Tests/Adapter/ApcuAdapterTest.php +++ b/src/SonsOfPHP/Component/Cache/Tests/Adapter/ApcuAdapterTest.php @@ -115,7 +115,7 @@ public function testDeleteItemsWithValuesInCache(): void $item->set('item.value'); $adapter->save($item); - $this->assertTrue($adapter->deleteItems(['item.key', 'unit.test'])); + $this->assertTrue($adapter->deleteItems(['unit.test'])); } /** @@ -125,7 +125,7 @@ public function testDeleteItemsWithEmptyCache(): void { $adapter = new ApcuAdapter(); - $this->assertTrue($adapter->deleteItems(['item.key'])); + $this->assertFalse($adapter->deleteItems(['item.key'])); } /** From ef22c10a523f223a974e436481e31a3bb6c26735 Mon Sep 17 00:00:00 2001 From: Joshua Estes Date: Tue, 7 Nov 2023 15:36:06 -0500 Subject: [PATCH 24/29] cs fixes --- src/SonsOfPHP/Component/Cache/TaggableCacheItemInterface.php | 2 -- src/SonsOfPHP/Component/Cache/Tests/CacheItemFactoryTest.php | 1 - 2 files changed, 3 deletions(-) diff --git a/src/SonsOfPHP/Component/Cache/TaggableCacheItemInterface.php b/src/SonsOfPHP/Component/Cache/TaggableCacheItemInterface.php index ebbd9633..2c8a0dfa 100644 --- a/src/SonsOfPHP/Component/Cache/TaggableCacheItemInterface.php +++ b/src/SonsOfPHP/Component/Cache/TaggableCacheItemInterface.php @@ -4,8 +4,6 @@ namespace SonsOfPHP\Component\Cache; -use Psr\Cache\CacheItemInterface; - /** * @author Joshua Estes */ diff --git a/src/SonsOfPHP/Component/Cache/Tests/CacheItemFactoryTest.php b/src/SonsOfPHP/Component/Cache/Tests/CacheItemFactoryTest.php index 097ec56c..b3208735 100644 --- a/src/SonsOfPHP/Component/Cache/Tests/CacheItemFactoryTest.php +++ b/src/SonsOfPHP/Component/Cache/Tests/CacheItemFactoryTest.php @@ -7,7 +7,6 @@ use PHPUnit\Framework\TestCase; use SonsOfPHP\Component\Cache\CacheItemFactory; use SonsOfPHP\Component\Cache\CacheItemFactoryInterface; -use Psr\Cache\CacheItemInterface; /** * @coversDefaultClass \SonsOfPHP\Component\Cache\CacheItemFactory From 6c18841fbd7d0f5fde1e7a9b801ec1897f0350d8 Mon Sep 17 00:00:00 2001 From: Joshua Estes Date: Tue, 7 Nov 2023 15:47:46 -0500 Subject: [PATCH 25/29] testing --- .../Cache/Tests/Adapter/ArrayAdapterTest.php | 13 ++++++ .../Cache/Tests/Adapter/ChainAdapterTest.php | 42 +++++++++++++++++++ .../Component/Cache/Tests/CacheItemTest.php | 38 +++++++++-------- 3 files changed, 75 insertions(+), 18 deletions(-) diff --git a/src/SonsOfPHP/Component/Cache/Tests/Adapter/ArrayAdapterTest.php b/src/SonsOfPHP/Component/Cache/Tests/Adapter/ArrayAdapterTest.php index ce163c9b..49c9d73b 100644 --- a/src/SonsOfPHP/Component/Cache/Tests/Adapter/ArrayAdapterTest.php +++ b/src/SonsOfPHP/Component/Cache/Tests/Adapter/ArrayAdapterTest.php @@ -40,6 +40,19 @@ public function testGetItem(): void $this->assertInstanceOf(CacheItemInterface::class, $item); } + /** + * @covers ::getItem + */ + public function testGetItemAfterSave(): void + { + $adapter = new ArrayAdapter(); + $item = $adapter->getItem('unit.test'); + $item->set('item.value'); + $adapter->save($item); + + $this->assertTrue($adapter->getItem('unit.test')->isHit()); + } + /** * @covers ::getItems */ diff --git a/src/SonsOfPHP/Component/Cache/Tests/Adapter/ChainAdapterTest.php b/src/SonsOfPHP/Component/Cache/Tests/Adapter/ChainAdapterTest.php index 2b4a0130..7098053c 100644 --- a/src/SonsOfPHP/Component/Cache/Tests/Adapter/ChainAdapterTest.php +++ b/src/SonsOfPHP/Component/Cache/Tests/Adapter/ChainAdapterTest.php @@ -6,9 +6,11 @@ use PHPUnit\Framework\TestCase; use SonsOfPHP\Component\Cache\Adapter\ChainAdapter; +use SonsOfPHP\Component\Cache\Adapter\ArrayAdapter; use SonsOfPHP\Component\Cache\Adapter\AdapterInterface; use Psr\Cache\CacheItemPoolInterface; use Psr\Cache\CacheItemInterface; +use SonsOfPHP\Component\Cache\Exception\CacheException; /** * @coversDefaultClass \SonsOfPHP\Component\Cache\Adapter\ChainAdapter @@ -23,6 +25,7 @@ final class ChainAdapterTest extends TestCase public function setUp(): void { $this->adapters[] = $this->createMock(AdapterInterface::class); + $this->adapters[] = new ArrayAdapter(); } /** @@ -36,6 +39,17 @@ public function testItHasTheCorrectInterface(): void $this->assertInstanceOf(CacheItemPoolInterface::class, $adapter); } + /** + * @covers ::__construct + */ + public function testConstructWhenInvalidAdapter(): void + { + $this->adapters[] = new \stdClass(); + + $this->expectException(CacheException::class); + $adapter = new ChainAdapter($this->adapters); + } + /** * @covers ::getItem */ @@ -47,6 +61,19 @@ public function testGetItem(): void $this->assertInstanceOf(CacheItemInterface::class, $item); } + /** + * @covers ::getItem + */ + public function testGetItemAfterSave(): void + { + $adapter = new ChainAdapter($this->adapters); + $item = $adapter->getItem('unit.test'); + $item->set('item.value'); + $adapter->save($item); + + $this->assertTrue($adapter->getItem('unit.test')->isHit()); + } + /** * @covers ::getItems */ @@ -69,6 +96,21 @@ public function testHasItem(): void $this->assertFalse($adapter->hasItem('item.key')); } + /** + * @covers ::hasItem + */ + public function testHasItemWhenOneHasKey(): void + { + // Create new mock adapter and place at end of stack + $mock = $this->createMock(AdapterInterface::class); + $mock->expects($this->once())->method('hasItem')->willReturn(true); + $this->adapters[] = $mock; + + $adapter = new ChainAdapter($this->adapters); + + $this->assertTrue($adapter->hasItem('item.key')); + } + /** * @covers ::clear */ diff --git a/src/SonsOfPHP/Component/Cache/Tests/CacheItemTest.php b/src/SonsOfPHP/Component/Cache/Tests/CacheItemTest.php index ae9bde2d..25bb979a 100644 --- a/src/SonsOfPHP/Component/Cache/Tests/CacheItemTest.php +++ b/src/SonsOfPHP/Component/Cache/Tests/CacheItemTest.php @@ -26,24 +26,6 @@ public function testItHasTheCorrectInterface(): void $this->assertInstanceOf(CacheItemInterface::class, $item); } - /** - * @covers ::__construct - */ - public function testItWillThrowExceptionWhenInvalidKey(): void - { - $this->expectException(InvalidArgumentException::class); - $item = new CacheItem('not allowed'); - } - - /** - * @covers ::__construct - */ - public function testItWillThrowExceptionWhenKeyContainsReservedCharacters(): void - { - $this->expectException(InvalidArgumentException::class); - $item = new CacheItem('not@allowed'); - } - /** * @covers ::getKey */ @@ -155,4 +137,24 @@ public function testExpiresAfterWorksAsExpectedWithNull(): void $itemAsArray = (array) $item; $this->assertNull($itemAsArray["\0*\0expiry"]); } + + /** + * @covers ::validateKey + * + * @dataProvider invalidKeysProvider + */ + public function testValidateKeyWithInvalidValues(string $key): void + { + $this->expectException(InvalidArgumentException::class); + $item = new CacheItem($key); + } + + public static function invalidKeysProvider(): iterable + { + yield ['']; + + yield ['not allowed']; + + yield ['contains@reserved}characters']; + } } From 97465691d03d9cb93e91b3fdcb30f347a0a0bc01 Mon Sep 17 00:00:00 2001 From: Joshua Estes Date: Tue, 7 Nov 2023 15:49:21 -0500 Subject: [PATCH 26/29] hard core --- src/SonsOfPHP/Component/Cache/Tests/Adapter/ChainAdapterTest.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/SonsOfPHP/Component/Cache/Tests/Adapter/ChainAdapterTest.php b/src/SonsOfPHP/Component/Cache/Tests/Adapter/ChainAdapterTest.php index 7098053c..e60d2537 100644 --- a/src/SonsOfPHP/Component/Cache/Tests/Adapter/ChainAdapterTest.php +++ b/src/SonsOfPHP/Component/Cache/Tests/Adapter/ChainAdapterTest.php @@ -17,6 +17,7 @@ * * @uses \SonsOfPHP\Component\Cache\CacheItem * @uses \SonsOfPHP\Component\Cache\Adapter\ChainAdapter + * @uses \SonsOfPHP\Component\Cache\Adapter\ArrayAdapter */ final class ChainAdapterTest extends TestCase { From a3ea0cb73b231b18675c1856dd1ae54588596a7c Mon Sep 17 00:00:00 2001 From: Joshua Estes Date: Tue, 7 Nov 2023 15:56:27 -0500 Subject: [PATCH 27/29] meh --- .github/workflows/codecov.yml | 1 + .github/workflows/unit-tests.yml | 1 + src/SonsOfPHP/Component/Cache/Tests/Adapter/ApcuAdapterTest.php | 2 ++ 3 files changed, 4 insertions(+) diff --git a/.github/workflows/codecov.yml b/.github/workflows/codecov.yml index 17246481..15418a7f 100644 --- a/.github/workflows/codecov.yml +++ b/.github/workflows/codecov.yml @@ -24,6 +24,7 @@ jobs: with: php-version: ${{ matrix.php-version }} coverage: xdebug + extensions: apcu - name: Cache Composer Packages id: composer-cache uses: actions/cache@v3 diff --git a/.github/workflows/unit-tests.yml b/.github/workflows/unit-tests.yml index 43e72674..f63623cc 100644 --- a/.github/workflows/unit-tests.yml +++ b/.github/workflows/unit-tests.yml @@ -36,6 +36,7 @@ jobs: with: php-version: ${{ matrix.php-version }} coverage: none + extensions: apcu - name: Cache Composer Packages id: composer-cache uses: actions/cache@v3 diff --git a/src/SonsOfPHP/Component/Cache/Tests/Adapter/ApcuAdapterTest.php b/src/SonsOfPHP/Component/Cache/Tests/Adapter/ApcuAdapterTest.php index ec4fae19..2b47512d 100644 --- a/src/SonsOfPHP/Component/Cache/Tests/Adapter/ApcuAdapterTest.php +++ b/src/SonsOfPHP/Component/Cache/Tests/Adapter/ApcuAdapterTest.php @@ -11,6 +11,8 @@ use Psr\Cache\CacheItemInterface; /** + * @requires extension apcu + * * @coversDefaultClass \SonsOfPHP\Component\Cache\Adapter\ApcuAdapter * * @uses \SonsOfPHP\Component\Cache\CacheItem From e475c7f2462d042081b60a2df172988b23b7ad56 Mon Sep 17 00:00:00 2001 From: Joshua Estes Date: Tue, 7 Nov 2023 16:01:24 -0500 Subject: [PATCH 28/29] updates --- src/SonsOfPHP/Component/Cache/Adapter/ApcuAdapter.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/SonsOfPHP/Component/Cache/Adapter/ApcuAdapter.php b/src/SonsOfPHP/Component/Cache/Adapter/ApcuAdapter.php index 3c8931f8..e7189d94 100644 --- a/src/SonsOfPHP/Component/Cache/Adapter/ApcuAdapter.php +++ b/src/SonsOfPHP/Component/Cache/Adapter/ApcuAdapter.php @@ -17,7 +17,7 @@ class ApcuAdapter implements AdapterInterface public function __construct() { - if (!extension_loaded('apcu') || !filter_var(ini_get('apc.enabled'), FILTER_VALIDATE_BOOL)) { + if (!extension_loaded('apcu') || !filter_var(ini_get('apc.enabled'), FILTER_VALIDATE_BOOL) || false === apc_enabled()) { throw new CacheException('APCu extension is required.'); } } From fb2ca991cab2a15125bc878e313246e3a05ca4b7 Mon Sep 17 00:00:00 2001 From: Joshua Estes Date: Tue, 7 Nov 2023 16:22:46 -0500 Subject: [PATCH 29/29] typo --- src/SonsOfPHP/Component/Cache/Adapter/ApcuAdapter.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/SonsOfPHP/Component/Cache/Adapter/ApcuAdapter.php b/src/SonsOfPHP/Component/Cache/Adapter/ApcuAdapter.php index e7189d94..bc872955 100644 --- a/src/SonsOfPHP/Component/Cache/Adapter/ApcuAdapter.php +++ b/src/SonsOfPHP/Component/Cache/Adapter/ApcuAdapter.php @@ -17,7 +17,7 @@ class ApcuAdapter implements AdapterInterface public function __construct() { - if (!extension_loaded('apcu') || !filter_var(ini_get('apc.enabled'), FILTER_VALIDATE_BOOL) || false === apc_enabled()) { + if (!extension_loaded('apcu') || !filter_var(ini_get('apc.enabled'), FILTER_VALIDATE_BOOL) || false === apcu_enabled()) { throw new CacheException('APCu extension is required.'); } }