From 7fb81d578ee0834d44839955be606c1a79561aa4 Mon Sep 17 00:00:00 2001 From: Adrian Suter Date: Fri, 12 Jun 2020 15:15:27 +0200 Subject: [PATCH 01/14] Add .idea --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 7579f74..4f38912 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ +.idea vendor composer.lock From 4d4447089f3bdf0825210a6d53a64cb1e26a0777 Mon Sep 17 00:00:00 2001 From: Adrian Suter Date: Fri, 12 Jun 2020 16:38:44 +0200 Subject: [PATCH 02/14] Add some folders and files to be ignored --- .gitignore | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/.gitignore b/.gitignore index 4f38912..9668a62 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,5 @@ -.idea -vendor +/.idea +/coverage +/vendor +.phpunit.result.cache composer.lock From 45c30a0ac0903c9aea94f989c47c08d435a9fd8f Mon Sep 17 00:00:00 2001 From: Adrian Suter Date: Fri, 12 Jun 2020 16:40:34 +0200 Subject: [PATCH 03/14] Update for slim 4 compatibility --- composer.json | 78 +++++++++++++++++++++++++++++++-------------------- 1 file changed, 48 insertions(+), 30 deletions(-) diff --git a/composer.json b/composer.json index 6d6a38a..5ec21a4 100644 --- a/composer.json +++ b/composer.json @@ -1,33 +1,51 @@ { - "name": "slim/http-cache", - "type": "library", - "description": "Slim Framework HTTP cache middleware and service provider", - "keywords": ["slim","framework","middleware","cache"], - "homepage": "http://slimframework.com", - "license": "MIT", - "authors": [ - { - "name": "Josh Lockhart", - "email": "hello@joshlockhart.com", - "homepage": "http://joshlockhart.com" - } - ], - "require": { - "php": ">=5.5.0", - "psr/http-message": "^1.0" - }, - "require-dev": { - "slim/slim": "^3.0", - "phpunit/phpunit": "^4.0" - }, - "autoload": { - "psr-4": { - "Slim\\HttpCache\\": "src" - } - }, - "autoload-dev": { - "psr-4": { - "Slim\\HttpCache\\Tests\\": "tests" - } + "name": "slim/http-cache", + "type": "library", + "description": "Slim Framework HTTP cache middleware and service provider", + "keywords": [ + "slim", + "framework", + "middleware", + "cache" + ], + "homepage": "https://www.slimframework.com", + "license": "MIT", + "authors": [ + { + "name": "Josh Lockhart", + "email": "hello@joshlockhart.com", + "homepage": "http://joshlockhart.com" + } + ], + "require": { + "php": "^7.2", + "psr/http-message": "^1.0", + "psr/http-server-middleware": "^1.0" + }, + "require-dev": { + "slim/psr7": "^1.1", + "phpunit/phpunit": "^8.5", + "squizlabs/php_codesniffer": "^3.5", + "phpstan/phpstan": "^0.12.28" + }, + "autoload": { + "psr-4": { + "Slim\\HttpCache\\": "src" } + }, + "autoload-dev": { + "psr-4": { + "Slim\\HttpCache\\Tests\\": "tests" + } + }, + "scripts": { + "test": [ + "@phpunit", + "@phpcs", + "@phpstan" + ], + "phpunit": "phpunit", + "phpcs": "phpcs", + "phpstan": "phpstan analyse src --memory-limit=-1" + } } From 4a5be76d1e90efa2b633af81a9f583db70328a27 Mon Sep 17 00:00:00 2001 From: Adrian Suter Date: Fri, 12 Jun 2020 16:41:05 +0200 Subject: [PATCH 04/14] Add phpcs, phpstan and phpunit configurations --- phpcs.xml.dist | 18 ++++++++++++++++++ phpstan.neon.dist | 3 +++ phpunit.xml.dist | 26 ++++++++++++++++++-------- 3 files changed, 39 insertions(+), 8 deletions(-) create mode 100644 phpcs.xml.dist create mode 100644 phpstan.neon.dist diff --git a/phpcs.xml.dist b/phpcs.xml.dist new file mode 100644 index 0000000..94eaa7a --- /dev/null +++ b/phpcs.xml.dist @@ -0,0 +1,18 @@ + + + Slim coding standard + + + + + + + + + + + + + src + tests + diff --git a/phpstan.neon.dist b/phpstan.neon.dist new file mode 100644 index 0000000..036e5a5 --- /dev/null +++ b/phpstan.neon.dist @@ -0,0 +1,3 @@ +parameters: + level: max + inferPrivatePropertyTypeFromConstructor: true diff --git a/phpunit.xml.dist b/phpunit.xml.dist index 8259dc4..1f1adc7 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -1,25 +1,35 @@ - - - - tests/ + + ./tests/ - - - src/ + + ./src/ + + + From 6b399aefcb7f4084bde51d21108ca0e10fe5cb3f Mon Sep 17 00:00:00 2001 From: Adrian Suter Date: Fri, 12 Jun 2020 16:41:27 +0200 Subject: [PATCH 05/14] Add slim 4 compatibility --- src/Cache.php | 69 ++++++++++------- src/CacheProvider.php | 57 +++++++++----- tests/CacheProviderTest.php | 107 ++++++++++++++++++++++---- tests/CacheTest.php | 149 ++++++++++++++++++++---------------- tests/bootstrap.php | 8 +- 5 files changed, 263 insertions(+), 127 deletions(-) diff --git a/src/Cache.php b/src/Cache.php index 6fe9e2f..051312c 100644 --- a/src/Cache.php +++ b/src/Cache.php @@ -1,10 +1,26 @@ type = $type; $this->maxAge = $maxAge; @@ -42,36 +58,37 @@ public function __construct($type = 'private', $maxAge = 86400, $mustRevalidate } /** - * Invoke cache middleware - * - * @param RequestInterface $request A PSR7 request object - * @param ResponseInterface $response A PSR7 response object - * @param callable $next The next middleware callable - * - * @return ResponseInterface A PSR7 response object + * {@inheritDoc} */ - public function __invoke(RequestInterface $request, ResponseInterface $response, callable $next) + public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface { - $response = $next($request, $response); + $response = $handler->handle($request); // Cache-Control header if (!$response->hasHeader('Cache-Control')) { if ($this->maxAge === 0) { - $response = $response->withHeader('Cache-Control', sprintf( - '%s, no-cache%s', - $this->type, - $this->mustRevalidate ? ', must-revalidate' : '' - )); + $response = $response->withHeader( + 'Cache-Control', + sprintf( + '%s, no-cache%s', + $this->type, + $this->mustRevalidate ? ', must-revalidate' : '' + ) + ); } else { - $response = $response->withHeader('Cache-Control', sprintf( - '%s, max-age=%s%s', - $this->type, - $this->maxAge, - $this->mustRevalidate ? ', must-revalidate' : '' - )); + $response = $response->withHeader( + 'Cache-Control', + sprintf( + '%s, max-age=%s%s', + $this->type, + $this->maxAge, + $this->mustRevalidate ? ', must-revalidate' : '' + ) + ); } } + // ETag header and conditional GET check $etag = $response->getHeader('ETag'); $etag = reset($etag); @@ -81,7 +98,7 @@ public function __invoke(RequestInterface $request, ResponseInterface $response, if ($ifNoneMatch) { $etagList = preg_split('@\s*,\s*@', $ifNoneMatch); - if (in_array($etag, $etagList) || in_array('*', $etagList)) { + if (is_array($etagList) && (in_array($etag, $etagList) || in_array('*', $etagList))) { return $response->withStatus(304); } } @@ -92,7 +109,7 @@ public function __invoke(RequestInterface $request, ResponseInterface $response, $lastModified = $response->getHeaderLine('Last-Modified'); if ($lastModified) { - if (!is_integer($lastModified)) { + if (!is_numeric($lastModified)) { $lastModified = strtotime($lastModified); } diff --git a/src/CacheProvider.php b/src/CacheProvider.php index e39cbad..c62a939 100644 --- a/src/CacheProvider.php +++ b/src/CacheProvider.php @@ -1,37 +1,54 @@ withHeader('Cache-Control', $headerValue); @@ -40,7 +57,7 @@ public function allowCache(ResponseInterface $response, $type = 'private', $maxA /** * Disable client-side HTTP caching * - * @param ResponseInterface $response PSR7 response object + * @param ResponseInterface $response PSR7 response object * * @return ResponseInterface A new PSR7 response object with `Cache-Control` header */ @@ -52,8 +69,8 @@ public function denyCache(ResponseInterface $response) /** * Add `Expires` header to PSR7 response object * - * @param ResponseInterface $response A PSR7 response object - * @param int|string $time A UNIX timestamp or a valid `strtotime()` string + * @param ResponseInterface $response A PSR7 response object + * @param int|string $time A UNIX timestamp or a valid `strtotime()` string * * @return ResponseInterface A new PSR7 response object with `Expires` header * @throws InvalidArgumentException if the expiration date cannot be parsed @@ -73,9 +90,9 @@ public function withExpires(ResponseInterface $response, $time) /** * Add `ETag` header to PSR7 response object * - * @param ResponseInterface $response A PSR7 response object - * @param string $value The ETag value - * @param string $type ETag type: "strong" or "weak" + * @param ResponseInterface $response A PSR7 response object + * @param string $value The ETag value + * @param string $type ETag type: "strong" or "weak" * * @return ResponseInterface A new PSR7 response object with `ETag` header * @throws InvalidArgumentException if the etag type is invalid @@ -85,9 +102,9 @@ public function withEtag(ResponseInterface $response, $value, $type = 'strong') if (!in_array($type, ['strong', 'weak'])) { throw new InvalidArgumentException('Invalid etag type. Must be "strong" or "weak".'); } - $value = '"' . $value . '"'; + $value = '"'.$value.'"'; if ($type === 'weak') { - $value = 'W/' . $value; + $value = 'W/'.$value; } return $response->withHeader('ETag', $value); @@ -96,8 +113,8 @@ public function withEtag(ResponseInterface $response, $value, $type = 'strong') /** * Add `Last-Modified` header to PSR7 response object * - * @param ResponseInterface $response A PSR7 response object - * @param int|string $time A UNIX timestamp or a valid `strtotime()` string + * @param ResponseInterface $response A PSR7 response object + * @param int|string $time A UNIX timestamp or a valid `strtotime()` string * * @return ResponseInterface A new PSR7 response object with `Last-Modified` header * @throws InvalidArgumentException if the last modified date cannot be parsed diff --git a/tests/CacheProviderTest.php b/tests/CacheProviderTest.php index b7e6b68..59587a2 100644 --- a/tests/CacheProviderTest.php +++ b/tests/CacheProviderTest.php @@ -1,15 +1,35 @@ createResponse(); + } + public function testAllowCache() { $cacheProvider = new CacheProvider(); - $res = $cacheProvider->allowCache(new Response(), 'private', 43200); + $res = $cacheProvider->allowCache($this->createResponse(), 'private', 43200); $cacheControl = $res->getHeaderLine('Cache-Control'); @@ -19,17 +39,36 @@ public function testAllowCache() public function testAllowCacheWithMustRevalidate() { $cacheProvider = new CacheProvider(); - $res = $cacheProvider->allowCache(new Response(), 'private', 43200, true); + $res = $cacheProvider->allowCache($this->createResponse(), 'private', 43200, true); $cacheControl = $res->getHeaderLine('Cache-Control'); $this->assertEquals('private, max-age=43200, must-revalidate', $cacheControl); } + public function testAllowCacheWithInvalidType() + { + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage('Invalid Cache-Control type. Must be "public" or "private".'); + + $cacheProvider = new CacheProvider(); + $cacheProvider->allowCache($this->createResponse(), 'unknown'); + } + + public function testAllowCacheWithMaxAgeAsString() + { + $cacheProvider = new CacheProvider(); + $res = $cacheProvider->allowCache($this->createResponse(), 'private', '+30 seconds'); + + $cacheControl = $res->getHeaderLine('Cache-Control'); + + $this->assertEquals('private, max-age=30', $cacheControl); + } + public function testDenyCache() { $cacheProvider = new CacheProvider(); - $res = $cacheProvider->denyCache(new Response()); + $res = $cacheProvider->denyCache($this->createResponse()); $cacheControl = $res->getHeaderLine('Cache-Control'); @@ -40,53 +79,91 @@ public function testWithExpires() { $now = time(); $cacheProvider = new CacheProvider(); - $res = $cacheProvider->withExpires(new Response(), $now); + $res = $cacheProvider->withExpires($this->createResponse(), $now); $expires = $res->getHeaderLine('Expires'); $this->assertEquals(gmdate('D, d M Y H:i:s T', $now), $expires); } + public function testWithExpiresTimeAsString() + { + $cacheProvider = new CacheProvider(); + $res = $cacheProvider->withExpires($this->createResponse(), '+30 seconds'); + $time = strtotime('+30 seconds'); + + $expires = $res->getHeaderLine('Expires'); + $this->assertEquals(gmdate('D, d M Y H:i:s T', $time), $expires); + } + + public function testWithExpiresTimeAsInvalidString() + { + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage('Expiration value could not be parsed with `strtotime()`.'); + + $cacheProvider = new CacheProvider(); + $cacheProvider->withExpires($this->createResponse(), 'this-is-not-a-valid-datetime'); + } + public function testWithETag() { $etag = 'abc'; $cacheProvider = new CacheProvider(); - $res = $cacheProvider->withEtag(new Response(), $etag); + $res = $cacheProvider->withEtag($this->createResponse(), $etag); $etagHeader = $res->getHeaderLine('ETag'); - $this->assertEquals('"' . $etag . '"', $etagHeader); + $this->assertEquals('"'.$etag.'"', $etagHeader); } public function testWithETagWeak() { $etag = 'abc'; $cacheProvider = new CacheProvider(); - $res = $cacheProvider->withEtag(new Response(), $etag, 'weak'); + $res = $cacheProvider->withEtag($this->createResponse(), $etag, 'weak'); $etagHeader = $res->getHeaderLine('ETag'); - $this->assertEquals('W/"' . $etag . '"', $etagHeader); + $this->assertEquals('W/"'.$etag.'"', $etagHeader); } - /** - * @expectedException \InvalidArgumentException - */ public function testWithETagInvalidType() { + $this->expectException(InvalidArgumentException::class); + $etag = 'abc'; $cacheProvider = new CacheProvider(); - $cacheProvider->withEtag(new Response(), $etag, 'bork'); + $cacheProvider->withEtag($this->createResponse(), $etag, 'bork'); } public function testWithLastModified() { $now = time(); $cacheProvider = new CacheProvider(); - $res = $cacheProvider->withLastModified(new Response(), $now); + $res = $cacheProvider->withLastModified($this->createResponse(), $now); $lastModified = $res->getHeaderLine('Last-Modified'); $this->assertEquals(gmdate('D, d M Y H:i:s T', $now), $lastModified); } + + public function testWithLastModifiedTimeAsString() + { + $cacheProvider = new CacheProvider(); + $res = $cacheProvider->withLastModified($this->createResponse(), '+30 seconds'); + $time = strtotime('+30 seconds'); + + $lastModified = $res->getHeaderLine('Last-Modified'); + + $this->assertEquals(gmdate('D, d M Y H:i:s T', $time), $lastModified); + } + + public function testWithLastModifiedTimeAsInvalidString() + { + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage('Last Modified value could not be parsed with `strtotime()`.'); + + $cacheProvider = new CacheProvider(); + $cacheProvider->withLastModified($this->createResponse(), 'this-is-not-a-valid-datetime'); + } } diff --git a/tests/CacheTest.php b/tests/CacheTest.php index 110f732..f39cb1e 100644 --- a/tests/CacheTest.php +++ b/tests/CacheTest.php @@ -1,36 +1,74 @@ createServerRequest('GET', 'https://example.com:443/foo/bar?abc=123'); + } + + protected function createResponse(): ResponseInterface + { + $responseFactory = new ResponseFactory(); + + return $responseFactory->createResponse(); + } + + /** + * Create a request handler that simply assigns the $request that it receives to a public property + * of the returned response, so that we can then inspect that request. + * + * @param ResponseInterface|null $response + * + * @return RequestHandlerInterface + */ + protected function createRequestHandler(ResponseInterface $response = null): RequestHandlerInterface { - $uri = Uri::createFromString('https://example.com:443/foo/bar?abc=123'); - $headers = new Headers(); - $cookies = []; - $serverParams = []; - $body = new Body(fopen('php://temp', 'r+')); + $response = $response ?? $this->createResponse(); + + return new class($response) implements RequestHandlerInterface { + private $response; + + public function __construct(ResponseInterface $response) + { + $this->response = $response; + } + + public function handle(ServerRequestInterface $request): ResponseInterface + { + $this->response->request = $request; - return new Request('GET', $uri, $headers, $cookies, $serverParams, $body); + return $this->response; + } + }; } public function testCacheControlHeader() { $cache = new Cache('public', 86400); $req = $this->requestFactory(); - $res = new Response(); - $next = function (Request $req, Response $res) { - return $res; - }; - $res = $cache($req, $res, $next); + + $res = $cache->process($req, $this->createRequestHandler()); $cacheControl = $res->getHeaderLine('Cache-Control'); @@ -41,11 +79,8 @@ public function testCacheControlHeaderWithMustRevalidate() { $cache = new Cache('private', 86400, true); $req = $this->requestFactory(); - $res = new Response(); - $next = function (Request $req, Response $res) { - return $res; - }; - $res = $cache($req, $res, $next); + + $res = $cache->process($req, $this->createRequestHandler()); $cacheControl = $res->getHeaderLine('Cache-Control'); @@ -56,11 +91,8 @@ public function testCacheControlHeaderWithZeroMaxAge() { $cache = new Cache('private', 0, false); $req = $this->requestFactory(); - $res = new Response(); - $next = function (Request $req, Response $res) { - return $res; - }; - $res = $cache($req, $res, $next); + + $res = $cache->process($req, $this->createRequestHandler()); $cacheControl = $res->getHeaderLine('Cache-Control'); @@ -71,11 +103,9 @@ public function testCacheControlHeaderDoesNotOverrideExistingHeader() { $cache = new Cache('public', 86400); $req = $this->requestFactory(); - $res = new Response(); - $next = function (Request $req, Response $res) { - return $res->withHeader('Cache-Control', 'no-cache,no-store'); - }; - $res = $cache($req, $res, $next); + + $res = $this->createResponse()->withHeader('Cache-Control', 'no-cache,no-store'); + $res = $cache->process($req, $this->createRequestHandler($res)); $cacheControl = $res->getHeaderLine('Cache-Control'); @@ -88,12 +118,11 @@ public function testLastModifiedWithCacheHit() $lastModified = gmdate('D, d M Y H:i:s T', $now + 86400); $ifModifiedSince = gmdate('D, d M Y H:i:s T', $now + 86400); $cache = new Cache('public', 86400); + $req = $this->requestFactory()->withHeader('If-Modified-Since', $ifModifiedSince); - $res = new Response(); - $next = function (Request $req, Response $res) use ($lastModified) { - return $res->withHeader('Last-Modified', $lastModified); - }; - $res = $cache($req, $res, $next); + + $res = $this->createResponse()->withHeader('Last-Modified', $lastModified); + $res = $cache->process($req, $this->createRequestHandler($res)); $this->assertEquals(304, $res->getStatusCode()); } @@ -105,11 +134,9 @@ public function testLastModifiedWithCacheHitAndNewerDate() $ifModifiedSince = gmdate('D, d M Y H:i:s T', $now + 172800); // <-- Newer date $cache = new Cache('public', 86400); $req = $this->requestFactory()->withHeader('If-Modified-Since', $ifModifiedSince); - $res = new Response(); - $next = function (Request $req, Response $res) use ($lastModified) { - return $res->withHeader('Last-Modified', $lastModified); - }; - $res = $cache($req, $res, $next); + + $res = $this->createResponse()->withHeader('Last-Modified', $lastModified); + $res = $cache->process($req, $this->createRequestHandler($res)); $this->assertEquals(304, $res->getStatusCode()); } @@ -121,11 +148,9 @@ public function testLastModifiedWithCacheHitAndOlderDate() $ifModifiedSince = gmdate('D, d M Y H:i:s T', $now); // <-- Older date $cache = new Cache('public', 86400); $req = $this->requestFactory()->withHeader('If-Modified-Since', $ifModifiedSince); - $res = new Response(); - $next = function (Request $req, Response $res) use ($lastModified) { - return $res->withHeader('Last-Modified', $lastModified); - }; - $res = $cache($req, $res, $next); + + $res = $this->createResponse()->withHeader('Last-Modified', $lastModified); + $res = $cache->process($req, $this->createRequestHandler($res)); $this->assertEquals(200, $res->getStatusCode()); } @@ -137,11 +162,9 @@ public function testLastModifiedWithCacheMiss() $ifModifiedSince = gmdate('D, d M Y H:i:s T', $now - 86400); $cache = new Cache('public', 86400); $req = $this->requestFactory()->withHeader('If-Modified-Since', $ifModifiedSince); - $res = new Response(); - $next = function (Request $req, Response $res) use ($lastModified) { - return $res->withHeader('Last-Modified', $lastModified); - }; - $res = $cache($req, $res, $next); + + $res = $this->createResponse()->withHeader('Last-Modified', $lastModified); + $res = $cache->process($req, $this->createRequestHandler($res)); $this->assertEquals(200, $res->getStatusCode()); } @@ -152,11 +175,9 @@ public function testETagWithCacheHit() $ifNoneMatch = 'abc'; $cache = new Cache('public', 86400); $req = $this->requestFactory()->withHeader('If-None-Match', $ifNoneMatch); - $res = new Response(); - $next = function (Request $req, Response $res) use ($etag) { - return $res->withHeader('ETag', $etag); - }; - $res = $cache($req, $res, $next); + + $res = $this->createResponse()->withHeader('Etag', $etag); + $res = $cache->process($req, $this->createRequestHandler($res)); $this->assertEquals(304, $res->getStatusCode()); } @@ -167,11 +188,9 @@ public function testETagWithCacheMiss() $ifNoneMatch = 'xyz'; $cache = new Cache('public', 86400); $req = $this->requestFactory()->withHeader('If-None-Match', $ifNoneMatch); - $res = new Response(); - $next = function (Request $req, Response $res) use ($etag) { - return $res->withHeader('ETag', $etag); - }; - $res = $cache($req, $res, $next); + + $res = $this->createResponse()->withHeader('Etag', $etag); + $res = $cache->process($req, $this->createRequestHandler($res)); $this->assertEquals(200, $res->getStatusCode()); } diff --git a/tests/bootstrap.php b/tests/bootstrap.php index 5330160..9526a60 100644 --- a/tests/bootstrap.php +++ b/tests/bootstrap.php @@ -1,2 +1,8 @@ Date: Fri, 12 Jun 2020 16:42:02 +0200 Subject: [PATCH 06/14] Update to make it slim 4 compatible --- .travis.yml | 29 ++++++++++++++++++++++------- 1 file changed, 22 insertions(+), 7 deletions(-) diff --git a/.travis.yml b/.travis.yml index 0479fcd..c9e508b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,11 +1,26 @@ language: php -php: - - 5.5 - - 5.6 - - 7.0 - - 7.1 +dist: trusty -before_script: composer install +matrix: + include: + - php: 7.2 + - php: 7.3 + - php: 7.4 + env: ANALYSIS='true' + - php: nightly + allow_failures: + - php: nightly -script: phpunit --coverage-text +before_script: + - if [[ "$ANALYSIS" == 'true' ]]; then composer require php-coveralls/php-coveralls:^2.1.0 ; fi + - composer install -n + +script: + - if [[ "$ANALYSIS" != 'true' ]]; then vendor/bin/phpunit ; fi + - if [[ "$ANALYSIS" == 'true' ]]; then vendor/bin/phpunit --coverage-clover clover.xml ; fi + - if [[ "$ANALYSIS" == 'true' ]]; then vendor/bin/phpcs ; fi + - if [[ "$ANALYSIS" == 'true' ]]; then vendor/bin/phpstan analyse src ; fi + +after_success: + - if [[ "$ANALYSIS" == 'true' ]]; then vendor/bin/php-coveralls --coverage_clover=clover.xml -v ; fi From 848ce5bc8bdc04ca4dd58f0ecdc7512721042ae5 Mon Sep 17 00:00:00 2001 From: Adrian Suter Date: Fri, 12 Jun 2020 20:50:28 +0200 Subject: [PATCH 07/14] Add git attributes --- .gitattributes | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 .gitattributes diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..b0756ef --- /dev/null +++ b/.gitattributes @@ -0,0 +1,14 @@ +# Enforce Unix newlines +* text=lf + +# Exclude unused files +# see: https://redd.it/2jzp6k +/tests export-ignore +/.gitattributes export-ignore +/.gitignore export-ignore +/.travis.yml export-ignore +/CONTRIBUTING.md export-ignore +/phpcs.xml.dist export-ignore +/phpstan.neon.dist export-ignore +/phpunit.xml.dist export-ignore +/README.md export-ignore From 8a507538bd30ea84fc58b76bbbed7d9df873019c Mon Sep 17 00:00:00 2001 From: Adrian Suter Date: Fri, 12 Jun 2020 20:50:47 +0200 Subject: [PATCH 08/14] Fix code hints --- src/CacheProvider.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/CacheProvider.php b/src/CacheProvider.php index c62a939..90c4a05 100644 --- a/src/CacheProvider.php +++ b/src/CacheProvider.php @@ -61,7 +61,7 @@ public function allowCache( * * @return ResponseInterface A new PSR7 response object with `Cache-Control` header */ - public function denyCache(ResponseInterface $response) + public function denyCache(ResponseInterface $response): ResponseInterface { return $response->withHeader('Cache-Control', 'no-store,no-cache'); } @@ -75,7 +75,7 @@ public function denyCache(ResponseInterface $response) * @return ResponseInterface A new PSR7 response object with `Expires` header * @throws InvalidArgumentException if the expiration date cannot be parsed */ - public function withExpires(ResponseInterface $response, $time) + public function withExpires(ResponseInterface $response, $time): ResponseInterface { if (!is_integer($time)) { $time = strtotime($time); @@ -97,7 +97,7 @@ public function withExpires(ResponseInterface $response, $time) * @return ResponseInterface A new PSR7 response object with `ETag` header * @throws InvalidArgumentException if the etag type is invalid */ - public function withEtag(ResponseInterface $response, $value, $type = 'strong') + public function withEtag(ResponseInterface $response, string $value, string $type = 'strong'): ResponseInterface { if (!in_array($type, ['strong', 'weak'])) { throw new InvalidArgumentException('Invalid etag type. Must be "strong" or "weak".'); @@ -119,7 +119,7 @@ public function withEtag(ResponseInterface $response, $value, $type = 'strong') * @return ResponseInterface A new PSR7 response object with `Last-Modified` header * @throws InvalidArgumentException if the last modified date cannot be parsed */ - public function withLastModified(ResponseInterface $response, $time) + public function withLastModified(ResponseInterface $response, $time): ResponseInterface { if (!is_integer($time)) { $time = strtotime($time); From b0af91e345aca03c68efa36527fd4ca60d61ca88 Mon Sep 17 00:00:00 2001 From: Adrian Suter Date: Fri, 12 Jun 2020 20:50:57 +0200 Subject: [PATCH 09/14] Remove unused line --- tests/CacheTest.php | 2 -- 1 file changed, 2 deletions(-) diff --git a/tests/CacheTest.php b/tests/CacheTest.php index f39cb1e..4094f9b 100644 --- a/tests/CacheTest.php +++ b/tests/CacheTest.php @@ -56,8 +56,6 @@ public function __construct(ResponseInterface $response) public function handle(ServerRequestInterface $request): ResponseInterface { - $this->response->request = $request; - return $this->response; } }; From 27585a20c484ad973bffbf7ee41a99497051345b Mon Sep 17 00:00:00 2001 From: Adrian Suter Date: Fri, 12 Jun 2020 20:56:05 +0200 Subject: [PATCH 10/14] Remove slim coding ruleset --- phpcs.xml.dist | 1 - 1 file changed, 1 deletion(-) diff --git a/phpcs.xml.dist b/phpcs.xml.dist index 94eaa7a..94458ea 100644 --- a/phpcs.xml.dist +++ b/phpcs.xml.dist @@ -10,7 +10,6 @@ - src From 1cb4a91d4f9805d436b8b758962c89e45b9c1a13 Mon Sep 17 00:00:00 2001 From: Adrian Suter Date: Wed, 17 Jun 2020 22:09:10 +0200 Subject: [PATCH 11/14] Order the test scripts alphabetically --- composer.json | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/composer.json b/composer.json index 5ec21a4..bea90df 100644 --- a/composer.json +++ b/composer.json @@ -40,12 +40,12 @@ }, "scripts": { "test": [ - "@phpunit", "@phpcs", - "@phpstan" + "@phpstan", + "@phpunit" ], - "phpunit": "phpunit", "phpcs": "phpcs", - "phpstan": "phpstan analyse src --memory-limit=-1" + "phpstan": "phpstan analyse src --memory-limit=-1", + "phpunit": "phpunit" } } From 49b7588dc4a5e8f9cfd49948888b3066482b7c98 Mon Sep 17 00:00:00 2001 From: Adrian Suter Date: Wed, 17 Jun 2020 22:24:53 +0200 Subject: [PATCH 12/14] Update example code --- README.md | 38 ++++++++++++++++++++++++-------------- 1 file changed, 24 insertions(+), 14 deletions(-) diff --git a/README.md b/README.md index 912a872..202506e 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,8 @@ # Slim Framework HTTP Cache [![Build Status](https://travis-ci.org/slimphp/Slim-HttpCache.svg?branch=master)](https://travis-ci.org/slimphp/Slim-HttpCache) +[![Latest Stable Version](https://poser.pugx.org/slim/http-cache/v)](//packagist.org/packages/slim/http-cache) +[![License](https://poser.pugx.org/slim/http-cache/license)](https://packagist.org/packages/slim/http-cache) This repository contains a Slim Framework HTTP cache middleware and service provider. @@ -12,30 +14,38 @@ Via Composer $ composer require slim/http-cache ``` -Requires Slim 3.0.0 or newer. +Requires Slim 4.0.0 or newer. ## Usage ```php -$app = new \Slim\App(); +declare(strict_types=1); -// Register middleware +use Psr\Http\Message\ResponseInterface as Response; +use Psr\Http\Message\ServerRequestInterface as Request; + +require __DIR__.'/../vendor/autoload.php'; + +$app = \Slim\Factory\AppFactory::create(); + +// Register the http cache middleware. $app->add(new \Slim\HttpCache\Cache('public', 86400)); -// Fetch DI Container -$container = $app->getContainer(); +// Create the cache provider. +$cacheProvider = new \Slim\HttpCache\CacheProvider(); -// Register service provider -$container['cache'] = function () { - return new \Slim\HttpCache\CacheProvider(); -}; +// Register a route and pass the cache provider to the closure callback. +$app->get( + '/', + function (Request $request, Response $response, array $args) use ($cacheProvider): Response { + // Use the cache provider. + $response = $cacheProvider->withEtag($response, 'abc'); -// Example route with ETag header -$app->get('/foo', function ($req, $res, $args) { - $resWithEtag = $this->cache->withEtag($res, 'abc'); + $response->getBody()->write('Hello world!'); - return $resWithEtag; -}); + return $response; + } +); $app->run(); ``` From 0bcdd24896da3ffcf09f4dd9358f4455648b3c0b Mon Sep 17 00:00:00 2001 From: Adrian Suter Date: Wed, 17 Jun 2020 22:26:23 +0200 Subject: [PATCH 13/14] Add strict types declaration --- src/Cache.php | 2 ++ src/CacheProvider.php | 2 ++ tests/CacheProviderTest.php | 2 ++ tests/CacheTest.php | 2 ++ tests/bootstrap.php | 2 ++ 5 files changed, 10 insertions(+) diff --git a/src/Cache.php b/src/Cache.php index 051312c..4f0c147 100644 --- a/src/Cache.php +++ b/src/Cache.php @@ -5,6 +5,8 @@ * @license https://github.com/slimphp/Slim-HttpCache/blob/master/LICENSE.md (MIT License) */ +declare(strict_types=1); + namespace Slim\HttpCache; use Psr\Http\Message\ResponseInterface; diff --git a/src/CacheProvider.php b/src/CacheProvider.php index 90c4a05..17d46af 100644 --- a/src/CacheProvider.php +++ b/src/CacheProvider.php @@ -5,6 +5,8 @@ * @license https://github.com/slimphp/Slim-HttpCache/blob/master/LICENSE.md (MIT License) */ +declare(strict_types=1); + namespace Slim\HttpCache; use InvalidArgumentException; diff --git a/tests/CacheProviderTest.php b/tests/CacheProviderTest.php index 59587a2..8c3907f 100644 --- a/tests/CacheProviderTest.php +++ b/tests/CacheProviderTest.php @@ -5,6 +5,8 @@ * @license https://github.com/slimphp/Slim-HttpCache/blob/master/LICENSE.md (MIT License) */ +declare(strict_types=1); + namespace Slim\HttpCache\Tests; use InvalidArgumentException; diff --git a/tests/CacheTest.php b/tests/CacheTest.php index 4094f9b..e8b4d57 100644 --- a/tests/CacheTest.php +++ b/tests/CacheTest.php @@ -5,6 +5,8 @@ * @license https://github.com/slimphp/Slim-HttpCache/blob/master/LICENSE.md (MIT License) */ +declare(strict_types=1); + namespace Slim\HttpCache\Tests; use PHPUnit\Framework\TestCase; diff --git a/tests/bootstrap.php b/tests/bootstrap.php index 9526a60..47fd7f1 100644 --- a/tests/bootstrap.php +++ b/tests/bootstrap.php @@ -5,4 +5,6 @@ * @license https://github.com/slimphp/Slim-HttpCache/blob/master/LICENSE.md (MIT License) */ +declare(strict_types=1); + require __DIR__.'/../vendor/autoload.php'; From e7228fb19e921016807911b2fbf2700a19baa102 Mon Sep 17 00:00:00 2001 From: Adrian Suter Date: Wed, 17 Jun 2020 22:32:35 +0200 Subject: [PATCH 14/14] Minor rewrite of comment --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 202506e..9f29b74 100644 --- a/README.md +++ b/README.md @@ -34,7 +34,7 @@ $app->add(new \Slim\HttpCache\Cache('public', 86400)); // Create the cache provider. $cacheProvider = new \Slim\HttpCache\CacheProvider(); -// Register a route and pass the cache provider to the closure callback. +// Register a route and let the closure callback inherit the cache provider. $app->get( '/', function (Request $request, Response $response, array $args) use ($cacheProvider): Response {