From c73473a627dcc23f28c7b4f4117a9303a0b82059 Mon Sep 17 00:00:00 2001 From: David Buchmann Date: Sun, 24 Mar 2024 11:18:23 +0100 Subject: [PATCH] strict typing --- .phpstan/classAliases.php | 22 ----- phpstan.neon.dist | 2 - src/CacheInvalidator.php | 57 ++++--------- src/EventListener/LogListener.php | 17 ++-- src/Exception/ExceptionCollection.php | 31 +++---- src/Exception/InvalidUrlException.php | 16 ++-- src/Exception/MissingHostException.php | 4 +- src/Exception/ProxyResponseException.php | 5 +- src/Exception/ProxyUnreachableException.php | 5 +- .../UnsupportedProxyOperationException.php | 4 +- src/ProxyClient/Cloudflare.php | 29 +++---- src/ProxyClient/Dispatcher.php | 11 ++- src/ProxyClient/Fastly.php | 18 ++-- src/ProxyClient/HttpDispatcher.php | 53 ++++-------- src/ProxyClient/HttpProxyClient.php | 40 ++++----- src/ProxyClient/Invalidation/BanCapable.php | 22 ++--- src/ProxyClient/Invalidation/ClearCapable.php | 4 +- src/ProxyClient/Invalidation/PurgeCapable.php | 10 +-- .../Invalidation/RefreshCapable.php | 10 +-- src/ProxyClient/Invalidation/TagCapable.php | 6 +- src/ProxyClient/MultiplexerClient.php | 71 +++++----------- src/ProxyClient/Nginx.php | 13 ++- src/ProxyClient/Noop.php | 14 ++-- src/ProxyClient/ProxyClient.php | 2 +- src/ProxyClient/Symfony.php | 13 ++- src/ProxyClient/Varnish.php | 25 +++--- src/ResponseTagger.php | 41 ++++----- src/SymfonyCache/AccessControlledListener.php | 13 +-- src/SymfonyCache/CleanupCacheTagsListener.php | 9 +- src/SymfonyCache/CustomTtlListener.php | 24 +++--- src/SymfonyCache/DebugListener.php | 9 +- .../EventDispatchingHttpCache.php | 6 +- src/SymfonyCache/HttpCacheAware.php | 12 +-- src/SymfonyCache/HttpCacheProvider.php | 5 +- src/SymfonyCache/KernelDispatcher.php | 2 +- src/SymfonyCache/PurgeListener.php | 14 +--- src/SymfonyCache/PurgeTagsListener.php | 19 ++--- src/SymfonyCache/RefreshListener.php | 2 +- src/SymfonyCache/UserContextListener.php | 14 +--- .../CommaSeparatedTagHeaderFormatter.php | 26 ++---- .../MaxHeaderValueLengthFormatter.php | 33 +++----- src/TagHeaderFormatter/TagHeaderFormatter.php | 6 +- src/TagHeaderFormatter/TagHeaderParser.php | 2 +- src/Test/CacheAssertions.php | 8 +- .../EventDispatchingHttpCacheTestCase.php | 29 +++---- src/Test/HttpCaller.php | 23 ++--- src/Test/HttpClient.php | 46 +++------- src/Test/NginxTest.php | 40 +++------ .../PHPUnit/AbstractCacheConstraintTrait.php | 20 ++--- src/Test/PHPUnit/IsCacheHitConstraint.php | 2 +- src/Test/PHPUnit/IsCacheMissConstraint.php | 2 +- src/Test/Proxy/AbstractProxy.php | 73 ++++------------ src/Test/Proxy/NginxProxy.php | 33 +++----- src/Test/Proxy/ProxyInterface.php | 6 +- src/Test/Proxy/SymfonyProxy.php | 24 ++---- src/Test/Proxy/VarnishProxy.php | 84 +++++-------------- src/Test/SymfonyTest.php | 32 ++----- src/Test/VarnishTest.php | 51 ++++------- src/UserContext/AnonymousRequestMatcher.php | 7 +- src/UserContext/DefaultHashGenerator.php | 8 +- src/UserContext/HashGenerator.php | 7 +- src/UserContext/UserContext.php | 22 +++-- .../Varnish/UserContextFailureTest.php | 12 ++- .../Varnish/UserContextNocacheTest.php | 12 ++- tests/Unit/ProxyClient/HttpDispatcherTest.php | 11 --- tests/Unit/ResponseTaggerTest.php | 20 +++-- tests/Unit/Test/Proxy/AbstractProxyTest.php | 12 +-- tests/Unit/Test/Proxy/VarnishProxyTest.php | 18 ++-- 68 files changed, 444 insertions(+), 899 deletions(-) delete mode 100644 .phpstan/classAliases.php diff --git a/.phpstan/classAliases.php b/.phpstan/classAliases.php deleted file mode 100644 index 2eb016467..000000000 --- a/.phpstan/classAliases.php +++ /dev/null @@ -1,22 +0,0 @@ -=')) { - class_alias( - CacheInvalidationS6::class, - CacheInvalidation::class - ); -} else { - class_alias( - CacheInvalidationLegacy::class, - CacheInvalidation::class - ); -} \ No newline at end of file diff --git a/phpstan.neon.dist b/phpstan.neon.dist index ac6edee46..3fe08f90d 100644 --- a/phpstan.neon.dist +++ b/phpstan.neon.dist @@ -2,8 +2,6 @@ parameters: level: 1 paths: - src - bootstrapFiles: - - .phpstan/classAliases.php excludePaths: analyseAndScan: # contains code to support legacy phpunit versions diff --git a/src/CacheInvalidator.php b/src/CacheInvalidator.php index 41e808a43..1523d8111 100644 --- a/src/CacheInvalidator.php +++ b/src/CacheInvalidator.php @@ -61,21 +61,10 @@ class CacheInvalidator */ public const CLEAR = 'clear'; - /** - * @var ProxyClient - */ - private $cache; + private ProxyClient $cache; - /** - * @var EventDispatcherInterface - */ - private $eventDispatcher; + private EventDispatcherInterface $eventDispatcher; - /** - * Constructor. - * - * @param ProxyClient $cache HTTP cache - */ public function __construct(ProxyClient $cache) { $this->cache = $cache; @@ -91,11 +80,9 @@ public function __construct(ProxyClient $cache) * * @param string $operation one of the class constants * - * @return bool - * * @throws InvalidArgumentException */ - public function supports(string $operation) + public function supports(string $operation): bool { switch ($operation) { case self::PATH: @@ -125,7 +112,7 @@ public function supports(string $operation) */ public function setEventDispatcher(EventDispatcherInterface $eventDispatcher): void { - if ($this->eventDispatcher) { + if (isset($this->eventDispatcher)) { // if you want to set a custom event dispatcher, do so right after instantiating // the invalidator. throw new \Exception('You may not change the event dispatcher once it is set.'); @@ -135,12 +122,10 @@ public function setEventDispatcher(EventDispatcherInterface $eventDispatcher): v /** * Get the event dispatcher used by the cache invalidator. - * - * @return EventDispatcherInterface */ - public function getEventDispatcher() + public function getEventDispatcher(): EventDispatcherInterface { - if (!$this->eventDispatcher) { + if (!isset($this->eventDispatcher)) { $this->eventDispatcher = new EventDispatcher(); } @@ -150,14 +135,12 @@ public function getEventDispatcher() /** * Invalidate a path or URL. * - * @param string $path Path or URL - * @param array $headers HTTP headers (optional) - * - * @return $this + * @param string $path Path or URL + * @param array $headers HTTP headers (optional) * * @throws UnsupportedProxyOperationException */ - public function invalidatePath($path, array $headers = []): static + public function invalidatePath(string $path, array $headers = []): static { if (!$this->cache instanceof PurgeCapable) { throw UnsupportedProxyOperationException::cacheDoesNotImplement('PURGE'); @@ -171,16 +154,14 @@ public function invalidatePath($path, array $headers = []): static /** * Refresh a path or URL. * - * @param string $path Path or URL - * @param array $headers HTTP headers (optional) + * @param string $path Path or URL + * @param array $headers HTTP headers (optional) * * @see RefreshCapable::refresh() * - * @return $this - * * @throws UnsupportedProxyOperationException */ - public function refreshPath($path, array $headers = []): static + public function refreshPath(string $path, array $headers = []): static { if (!$this->cache instanceof RefreshCapable) { throw UnsupportedProxyOperationException::cacheDoesNotImplement('REFRESH'); @@ -199,9 +180,7 @@ public function refreshPath($path, array $headers = []): static * * @see BanCapable::ban() * - * @param array $headers HTTP headers that path must match to be banned - * - * @return $this + * @param array $headers HTTP headers that path must match to be banned * * @throws UnsupportedProxyOperationException If HTTP cache does not support BAN requests */ @@ -221,9 +200,7 @@ public function invalidate(array $headers): static * * @see TagCapable::tags() * - * @param array $tags Tags that should be removed/expired from the cache. An empty tag list is ignored. - * - * @return $this + * @param string[] $tags Tags that should be removed/expired from the cache. An empty tag list is ignored. * * @throws UnsupportedProxyOperationException If HTTP cache does not support Tags invalidation */ @@ -257,8 +234,6 @@ public function invalidateTags(array $tags): static * @param array|string|null $hosts Regular expression of a host name or list of * exact host names to limit banning * - * @return $this - * * @throws UnsupportedProxyOperationException If HTTP cache does not support BAN requests * *@see BanCapable::banPath() @@ -277,8 +252,6 @@ public function invalidateRegex(string $path, ?string $contentType = null, array /** * Clear the cache completely. * - * @return $this - * * @throws UnsupportedProxyOperationException if HTTP cache does not support clearing the cache completely */ public function clearCache(): static @@ -299,7 +272,7 @@ public function clearCache(): static * * @throws ExceptionCollection if any errors occurred during flush */ - public function flush() + public function flush(): int { try { return $this->cache->flush(); diff --git a/src/EventListener/LogListener.php b/src/EventListener/LogListener.php index 477574b26..a8031d681 100644 --- a/src/EventListener/LogListener.php +++ b/src/EventListener/LogListener.php @@ -22,10 +22,7 @@ */ class LogListener implements EventSubscriberInterface { - /** - * @var LoggerInterface - */ - private $logger; + private LoggerInterface $logger; public function __construct(LoggerInterface $logger) { @@ -40,22 +37,22 @@ public static function getSubscribedEvents(): array ]; } - public function onProxyUnreachableError(Event $event) + public function onProxyUnreachableError(Event $event): void { - $this->log(LogLevel::CRITICAL, $event->getException()); + $this->log($event->getException()); } - public function onProxyResponseError(Event $event) + public function onProxyResponseError(Event $event): void { - $this->log(LogLevel::CRITICAL, $event->getException()); + $this->log($event->getException()); } - private function log($level, \Exception $exception) + private function log(\Throwable $exception): void { $context = [ 'exception' => $exception, ]; - $this->logger->log($level, $exception->getMessage(), $context); + $this->logger->log(LogLevel::CRITICAL, $exception->getMessage(), $context); } } diff --git a/src/Exception/ExceptionCollection.php b/src/Exception/ExceptionCollection.php index d3ae2389f..eec0651a1 100644 --- a/src/Exception/ExceptionCollection.php +++ b/src/Exception/ExceptionCollection.php @@ -17,8 +17,14 @@ */ class ExceptionCollection extends \Exception implements \IteratorAggregate, \Countable, HttpCacheException { - private $exceptions = []; + /** + * @var \Throwable[] + */ + private array $exceptions = []; + /** + * @param \Throwable[] $exceptions + */ public function __construct(array $exceptions = []) { foreach ($exceptions as $exception) { @@ -28,10 +34,8 @@ public function __construct(array $exceptions = []) /** * Add an exception to the collection. - * - * @return $this */ - public function add(\Exception $e) + public function add(\Throwable $e): static { if (!$this->message) { $this->message = $e->getMessage(); @@ -44,34 +48,25 @@ public function add(\Exception $e) /** * Get first exception in collection or null, if there is none. - * - * @return \Exception|null */ - public function getFirst() + public function getFirst(): ?\Throwable { if ($this->count() > 0) { return $this->exceptions[0]; } + + return null; } - /** - * Get exception iterator. - * - * @return \ArrayIterator - */ - #[\ReturnTypeWillChange] - public function getIterator() + public function getIterator(): \ArrayIterator { return new \ArrayIterator($this->exceptions); } /** * Get number of exceptions in collection. - * - * @return int */ - #[\ReturnTypeWillChange] - public function count() + public function count(): int { return count($this->exceptions); } diff --git a/src/Exception/InvalidUrlException.php b/src/Exception/InvalidUrlException.php index 48f33293e..475faf94c 100644 --- a/src/Exception/InvalidUrlException.php +++ b/src/Exception/InvalidUrlException.php @@ -17,12 +17,10 @@ class InvalidUrlException extends InvalidArgumentException { /** - * @param string $url the invalid URL - * @param string $reason Further explanation why the URL was invalid (optional) - * - * @return self + * @param string $url the invalid URL + * @param string|null $reason Further explanation why the URL was invalid (optional) */ - public static function invalidUrl($url, $reason = null) + public static function invalidUrl(string $url, ?string $reason = null): InvalidUrlException { $msg = sprintf('URL "%s" is invalid.', $url); if ($reason) { @@ -33,12 +31,10 @@ public static function invalidUrl($url, $reason = null) } /** - * @param string $server Invalid server - * @param array $allowed Allowed URL parts - * - * @return self + * @param string $server Invalid server + * @param string[] $allowed Allowed URL parts */ - public static function invalidUrlParts($server, array $allowed) + public static function invalidUrlParts(string $server, array $allowed): InvalidUrlException { return new self(sprintf( 'Server "%s" is invalid. Only %s URL parts are allowed.', diff --git a/src/Exception/MissingHostException.php b/src/Exception/MissingHostException.php index 10babeb0b..6bd312a40 100644 --- a/src/Exception/MissingHostException.php +++ b/src/Exception/MissingHostException.php @@ -19,10 +19,8 @@ class MissingHostException extends \RuntimeException implements HttpCacheExcepti { /** * @param string $path the path that was asked to be invalidated - * - * @return MissingHostException */ - public static function missingHost($path) + public static function missingHost(string $path): MissingHostException { $msg = sprintf( 'Path "%s" cannot be invalidated without a host. ' diff --git a/src/Exception/ProxyResponseException.php b/src/Exception/ProxyResponseException.php index f6181e827..c2d9dd2db 100644 --- a/src/Exception/ProxyResponseException.php +++ b/src/Exception/ProxyResponseException.php @@ -18,10 +18,7 @@ */ class ProxyResponseException extends \RuntimeException implements HttpCacheException { - /** - * @return ProxyResponseException - */ - public static function proxyResponse(HttpException $exception) + public static function proxyResponse(HttpException $exception): ProxyResponseException { $message = sprintf( '%s error response "%s" from caching proxy', diff --git a/src/Exception/ProxyUnreachableException.php b/src/Exception/ProxyUnreachableException.php index 09c6744a2..81dc8bba9 100644 --- a/src/Exception/ProxyUnreachableException.php +++ b/src/Exception/ProxyUnreachableException.php @@ -19,10 +19,7 @@ */ class ProxyUnreachableException extends \RuntimeException implements HttpCacheException { - /** - * @return ProxyUnreachableException - */ - public static function proxyUnreachable(NetworkException $requestException) + public static function proxyUnreachable(NetworkException $requestException): ProxyUnreachableException { $message = sprintf( 'Request to caching proxy at %s failed with message "%s"', diff --git a/src/Exception/UnsupportedProxyOperationException.php b/src/Exception/UnsupportedProxyOperationException.php index 2d3500550..d8f76ffba 100644 --- a/src/Exception/UnsupportedProxyOperationException.php +++ b/src/Exception/UnsupportedProxyOperationException.php @@ -19,10 +19,8 @@ class UnsupportedProxyOperationException extends \RuntimeException implements Ht { /** * @param string $method name of the HTTP method that would be required - * - * @return UnsupportedProxyOperationException */ - public static function cacheDoesNotImplement($method) + public static function cacheDoesNotImplement(string $method): UnsupportedProxyOperationException { return new self(sprintf('HTTP cache does not support %s requests', $method)); } diff --git a/src/ProxyClient/Cloudflare.php b/src/ProxyClient/Cloudflare.php index 89089138d..b2535e070 100644 --- a/src/ProxyClient/Cloudflare.php +++ b/src/ProxyClient/Cloudflare.php @@ -15,6 +15,8 @@ use FOS\HttpCache\ProxyClient\Invalidation\PurgeCapable; use FOS\HttpCache\ProxyClient\Invalidation\TagCapable; use Http\Message\RequestFactory; +use Psr\Http\Message\UriInterface; +use Symfony\Component\OptionsResolver\OptionsResolver; /** * Cloudflare HTTP cache invalidator. @@ -47,10 +49,10 @@ class Cloudflare extends HttpProxyClient implements ClearCapable, PurgeCapable, * * @var array */ - private $purgeByUrlsData = []; + private array $purgeByUrlsData = []; public function __construct( - Dispatcher $httpDispatcher, + Dispatcher $dispatcher, array $options = [], ?RequestFactory $messageFactory = null ) { @@ -58,7 +60,7 @@ public function __construct( throw new \Exception('ext-json is required for cloudflare invalidation'); } - parent::__construct($httpDispatcher, $options, $messageFactory); + parent::__construct($dispatcher, $options, $messageFactory); } /** @@ -68,7 +70,7 @@ public function __construct( * * @see https://api.cloudflare.com/#zone-purge-files-by-cache-tags,-host-or-prefix */ - public function invalidateTags(array $tags) + public function invalidateTags(array $tags): static { if (!$tags) { return $this; @@ -89,7 +91,7 @@ public function invalidateTags(array $tags) * @see https://api.cloudflare.com/#zone-purge-files-by-url * @see https://developers.cloudflare.com/cache/how-to/purge-cache#purge-by-single-file-by-url For details on headers you can pass to clear the cache correctly */ - public function purge($url, array $headers = []) + public function purge(string $url, array $headers = []): static { if (!empty($headers)) { $this->purgeByUrlsData[] = [ @@ -106,7 +108,7 @@ public function purge($url, array $headers = []) /** * @see https://api.cloudflare.com/#zone-purge-all-files */ - public function clear() + public function clear(): static { $this->queueRequest( 'POST', @@ -119,10 +121,7 @@ public function clear() return $this; } - /** - * {@inheritdoc} Queue requests for purge by URLs - */ - public function flush() + public function flush(): int { // Queue requests for purge by URL foreach (\array_chunk($this->purgeByUrlsData, self::URL_BATCH_PURGE_LIMIT) as $urlChunk) { @@ -140,9 +139,11 @@ public function flush() } /** - * {@inheritdoc} Always provides authentication token + * {@inheritdoc} + * + * Always provides authentication token */ - protected function queueRequest($method, $url, array $headers, $validateHost = true, $body = null) + protected function queueRequest(string $method, UriInterface|string $url, array $headers, bool $validateHost = true, $body = null): void { parent::queueRequest( $method, @@ -153,7 +154,7 @@ protected function queueRequest($method, $url, array $headers, $validateHost = t ); } - protected function configureOptions() + protected function configureOptions(): OptionsResolver { $resolver = parent::configureOptions(); @@ -167,7 +168,7 @@ protected function configureOptions() private function json_encode(array $data): string { - $json = json_encode($data, JSON_UNESCAPED_SLASHES); + $json = json_encode($data, JSON_THROW_ON_ERROR | JSON_UNESCAPED_SLASHES); if (false === $json) { throw new \InvalidArgumentException(sprintf('Cannot encode "$data": %s', json_last_error_msg())); } diff --git a/src/ProxyClient/Dispatcher.php b/src/ProxyClient/Dispatcher.php index 160a24424..47874f6ea 100644 --- a/src/ProxyClient/Dispatcher.php +++ b/src/ProxyClient/Dispatcher.php @@ -25,12 +25,11 @@ interface Dispatcher /** * Queue invalidation request. * - * @param bool $validateHost If false, do not validate - * that we either have a base - * uri or the invalidation - * request specifies the host + * @param bool $validateHost If false, do not validate that we either have + * a base uri or the invalidation request + * specifies the host */ - public function invalidate(RequestInterface $invalidationRequest, $validateHost = true); + public function invalidate(RequestInterface $invalidationRequest, bool $validateHost = true); /** * Send all pending invalidation requests and make sure the requests have @@ -41,5 +40,5 @@ public function invalidate(RequestInterface $invalidationRequest, $validateHost * * @throws ExceptionCollection If any errors occurred during flush */ - public function flush(); + public function flush(): int; } diff --git a/src/ProxyClient/Fastly.php b/src/ProxyClient/Fastly.php index 459fb7764..97aacf6f8 100644 --- a/src/ProxyClient/Fastly.php +++ b/src/ProxyClient/Fastly.php @@ -16,6 +16,8 @@ use FOS\HttpCache\ProxyClient\Invalidation\RefreshCapable; use FOS\HttpCache\ProxyClient\Invalidation\TagCapable; use Http\Message\RequestFactory; +use Psr\Http\Message\UriInterface; +use Symfony\Component\OptionsResolver\OptionsResolver; /** * Fastly HTTP cache invalidator. @@ -46,7 +48,7 @@ class Fastly extends HttpProxyClient implements ClearCapable, PurgeCapable, Refr private const API_ENDPOINT = 'https://api.fastly.com'; public function __construct( - Dispatcher $httpDispatcher, + Dispatcher $dispatcher, array $options = [], ?RequestFactory $messageFactory = null ) { @@ -54,13 +56,13 @@ public function __construct( throw new \Exception('ext-json is required for fastly invalidation'); } - parent::__construct($httpDispatcher, $options, $messageFactory); + parent::__construct($dispatcher, $options, $messageFactory); } /** * @see https://docs.fastly.com/api/purge#purge_db35b293f8a724717fcf25628d713583 */ - public function invalidateTags(array $tags) + public function invalidateTags(array $tags): static { if (!$tags) { return $this; @@ -90,7 +92,7 @@ public function invalidateTags(array $tags) * @see https://docs.fastly.com/api/purge#soft_purge_0c4f56f3d68e9bed44fb8b638b78ea36 * @see https://docs.fastly.com/guides/purging/authenticating-api-purge-requests#purging-urls-with-an-api-token */ - public function purge($url, array $headers = []) + public function purge(string $url, array $headers = []): static { if (true === $this->options['soft_purge']) { $headers['Fastly-Soft-Purge'] = 1; @@ -106,7 +108,7 @@ public function purge($url, array $headers = []) return $this; } - public function refresh($url, array $headers = []) + public function refresh(string $url, array $headers = []): static { // First soft purge url $this->queueRequest( @@ -134,7 +136,7 @@ public function refresh($url, array $headers = []) * - Does not support soft purge, for that use an "all" key. * - Requires a API token of a user with at least Engineer permissions. */ - public function clear() + public function clear(): static { $this->queueRequest( 'POST', @@ -149,7 +151,7 @@ public function clear() /** * {@inheritdoc} Always provides default authentication token on "Fastly-Key" header. */ - protected function queueRequest($method, $url, array $headers, $validateHost = true, $body = null) + protected function queueRequest(string $method, UriInterface|string $url, array $headers, bool $validateHost = true, $body = null): void { parent::queueRequest( $method, @@ -160,7 +162,7 @@ protected function queueRequest($method, $url, array $headers, $validateHost = t ); } - protected function configureOptions() + protected function configureOptions(): OptionsResolver { $resolver = parent::configureOptions(); diff --git a/src/ProxyClient/HttpDispatcher.php b/src/ProxyClient/HttpDispatcher.php index e209b7b01..571cf568a 100644 --- a/src/ProxyClient/HttpDispatcher.php +++ b/src/ProxyClient/HttpDispatcher.php @@ -36,36 +36,27 @@ */ class HttpDispatcher implements Dispatcher { - /** - * @var HttpAsyncClient - */ - private $httpClient; - - /** - * @var UriFactory - */ - private $uriFactory; + private HttpAsyncClient $httpClient; + private UriFactory $uriFactory; /** * Queued requests. * * @var RequestInterface[] */ - private $queue = []; + private array $queue = []; /** * Caching proxy server host names or IP addresses. * * @var UriInterface[] */ - private $servers; + private array $servers; /** * Application host name and optional base URL. - * - * @var UriInterface */ - private $baseUri; + private ?UriInterface $baseUri; /** * If you specify a custom HTTP client, make sure that it converts HTTP @@ -90,7 +81,7 @@ class HttpDispatcher implements Dispatcher */ public function __construct( array $servers, - $baseUri = '', + string $baseUri = '', ?HttpAsyncClient $httpClient = null, ?UriFactory $uriFactory = null ) { @@ -107,7 +98,7 @@ public function __construct( $this->setBaseUri($baseUri); } - public function invalidate(RequestInterface $invalidationRequest, $validateHost = true) + public function invalidate(RequestInterface $invalidationRequest, bool $validateHost = true): void { if ($validateHost && !$this->baseUri && !$invalidationRequest->getUri()->getHost()) { throw MissingHostException::missingHost((string) $invalidationRequest->getUri()); @@ -122,7 +113,7 @@ public function invalidate(RequestInterface $invalidationRequest, $validateHost $this->queue[$signature] = $invalidationRequest; } - public function flush() + public function flush(): int { $queue = $this->queue; $this->queue = []; @@ -167,7 +158,7 @@ public function flush() * * @return UriInterface[] */ - protected function getServers() + protected function getServers(): array { return $this->servers; } @@ -179,7 +170,7 @@ protected function getServers() * * @return RequestInterface[] */ - private function fanOut(RequestInterface $request) + private function fanOut(RequestInterface $request): array { $requests = []; @@ -244,7 +235,7 @@ private function fanOut(RequestInterface $request) * @throws InvalidUrlException If server is invalid or contains URL * parts other than scheme, host, port */ - private function setServers(array $servers) + private function setServers(array $servers): void { $this->servers = []; foreach ($servers as $server) { @@ -256,11 +247,11 @@ private function setServers(array $servers) * Set application base URI that will be prefixed to relative purge and * refresh requests, and validate it. * - * @param string $uriString Your application’s base URI + * @param string|null $uriString Your application’s base URI * * @throws InvalidUrlException If the base URI is not a valid URI */ - private function setBaseUri($uriString = null) + private function setBaseUri(?string $uriString = null): void { if (!$uriString) { $this->baseUri = null; @@ -277,7 +268,6 @@ private function setBaseUri($uriString = null) * Prefix the URL with "http://" if it has no scheme, then check the URL * for validity. You can specify what parts of the URL are allowed. * - * @param string $uriString * @param string[] $allowedParts Array of allowed URL parts (optional) * * @return UriInterface Filtered URI (with default scheme if there was no scheme) @@ -285,19 +275,12 @@ private function setBaseUri($uriString = null) * @throws InvalidUrlException If URL is invalid, the scheme is not http or * contains parts that are not expected */ - private function filterUri($uriString, array $allowedParts = []) + private function filterUri(string $uriString, array $allowedParts = []): UriInterface { - if (!is_string($uriString)) { - throw new \InvalidArgumentException(sprintf( - 'URI parameter must be a string, %s given', - gettype($uriString) - )); - } - // Creating a PSR-7 URI without scheme (with parse_url) results in the // original hostname to be seen as path. So first add a scheme if none // is given. - if (false === strpos($uriString, '://')) { + if (!str_contains($uriString, '://')) { $uriString = sprintf('%s://%s', 'http', $uriString); } @@ -327,12 +310,8 @@ private function filterUri($uriString, array $allowedParts = []) * for the same requests. * * This signature is used to avoid sending the same invalidation request twice. - * - * @param RequestInterface $request An invalidation request - * - * @return string A signature for this request */ - private function getRequestSignature(RequestInterface $request) + private function getRequestSignature(RequestInterface $request): string { $headers = $request->getHeaders(); ksort($headers); diff --git a/src/ProxyClient/HttpProxyClient.php b/src/ProxyClient/HttpProxyClient.php index 104f7bc7a..299b1d3a1 100644 --- a/src/ProxyClient/HttpProxyClient.php +++ b/src/ProxyClient/HttpProxyClient.php @@ -26,54 +26,45 @@ abstract class HttpProxyClient implements ProxyClient { /** * Dispatcher for invalidation HTTP requests. - * - * @var HttpDispatcher */ - private $httpDispatcher; + private Dispatcher $httpDispatcher; - /** - * @var RequestFactory - */ - private $requestFactory; + private RequestFactory $requestFactory; /** * The options configured in the constructor argument or default values. * * @var array The resolved options */ - protected $options; + protected array $options; /** - * Constructor. - * * The base class has no options. * - * @param Dispatcher $httpDispatcher Helper to send HTTP requests to caching proxy + * @param Dispatcher $dispatcher Helper to send instructions to the caching proxy * @param array $options Options for this client * @param RequestFactory|null $messageFactory Factory for PSR-7 messages. If none supplied, * a default one is created */ public function __construct( - Dispatcher $httpDispatcher, + Dispatcher $dispatcher, array $options = [], ?RequestFactory $messageFactory = null ) { - $this->httpDispatcher = $httpDispatcher; + $this->httpDispatcher = $dispatcher; $this->options = $this->configureOptions()->resolve($options); $this->requestFactory = $messageFactory ?: MessageFactoryDiscovery::find(); } - public function flush() + public function flush(): int { return $this->httpDispatcher->flush(); } /** * Get options resolver with default settings. - * - * @return OptionsResolver */ - protected function configureOptions() + protected function configureOptions(): OptionsResolver { return new OptionsResolver(); } @@ -81,12 +72,11 @@ protected function configureOptions() /** * Create a request and queue it with the HTTP dispatcher. * - * @param string $method - * @param string|UriInterface $url + * @param array $headers * @param bool $validateHost see Dispatcher::invalidate * @param resource|string|StreamInterface|null $body */ - protected function queueRequest($method, $url, array $headers, $validateHost = true, $body = null) + protected function queueRequest(string $method, UriInterface|string $url, array $headers, bool $validateHost = true, $body = null): void { $this->httpDispatcher->invalidate( $this->requestFactory->createRequest($method, $url, $headers, $body), @@ -106,13 +96,13 @@ protected function queueRequest($method, $url, array $headers, $validateHost = t * collisions would in the worst case lead to unintended invalidations, * which is not a bug. * - * @param array $tags The tags to escape + * @param string[] $tags The tags to escape * - * @return array Sane tags + * @return string[] Sane tags */ - protected function escapeTags(array $tags) + protected function escapeTags(array $tags): array { - array_walk($tags, function (&$tag) { + array_walk($tags, static function (&$tag) { // WARNING: changing the list of characters that are escaped is a BC break for existing installations, // as existing tags on the cache would not be invalidated anymore if they contain a character that is // newly escaped @@ -132,7 +122,7 @@ protected function escapeTags(array $tags) * * @return int Number of tags per tag invalidation request */ - protected function determineTagsPerHeader($escapedTags, $glue) + protected function determineTagsPerHeader(array $escapedTags, string $glue): int { if (mb_strlen(implode($glue, $escapedTags)) < $this->options['header_length']) { return count($escapedTags); diff --git a/src/ProxyClient/Invalidation/BanCapable.php b/src/ProxyClient/Invalidation/BanCapable.php index f556d27b3..30a612edc 100644 --- a/src/ProxyClient/Invalidation/BanCapable.php +++ b/src/ProxyClient/Invalidation/BanCapable.php @@ -35,11 +35,9 @@ interface BanCapable extends ProxyClient * host name, configure your proxy to copy the host to a custom HTTP header * such as X-Host. * - * @param array $headers HTTP headers that path must match to be banned - * - * @return $this + * @param array $headers HTTP headers that path must match to be banned */ - public function ban(array $headers); + public function ban(array $headers): static; /** * Ban URLs based on a regular expression for the URI, an optional @@ -65,14 +63,12 @@ public function ban(array $headers); * * $client->banPath('*.png$', null, '^www.example.com$'); * - * @param string $path regular expression pattern for URI to - * invalidate - * @param string $contentType regular expression pattern for the content - * type to limit banning, for instance 'text' - * @param array|string $hosts regular expression of a host name or list - * of exact host names to limit banning - * - * @return $this + * @param string $path regular expression pattern for URI to + * invalidate + * @param string|null $contentType regular expression pattern for the content + * type to limit banning, for instance 'text' + * @param array|string|null $hosts regular expression of a host name or list + * of exact host names to limit banning */ - public function banPath($path, $contentType = null, $hosts = null); + public function banPath(string $path, ?string $contentType = null, array|string|null $hosts = null): static; } diff --git a/src/ProxyClient/Invalidation/ClearCapable.php b/src/ProxyClient/Invalidation/ClearCapable.php index 750d62fac..bec7b3956 100644 --- a/src/ProxyClient/Invalidation/ClearCapable.php +++ b/src/ProxyClient/Invalidation/ClearCapable.php @@ -24,8 +24,6 @@ interface ClearCapable extends ProxyClient { /** * Remove all cache items from this cache. - * - * @return $this */ - public function clear(); + public function clear(): static; } diff --git a/src/ProxyClient/Invalidation/PurgeCapable.php b/src/ProxyClient/Invalidation/PurgeCapable.php index ade75e312..17ccd0939 100644 --- a/src/ProxyClient/Invalidation/PurgeCapable.php +++ b/src/ProxyClient/Invalidation/PurgeCapable.php @@ -36,11 +36,9 @@ interface PurgeCapable extends ProxyClient * Please note that purge will invalidate all variants, so you do not need * to specify variants headers, such as ``Accept``. * - * @param string $url Path or URL to purge - * @param array $headers Extra HTTP headers to send to the caching proxy - * (optional) - * - * @return $this + * @param string $url Path or URL to purge + * @param array $headers Extra HTTP headers to send to the caching proxy + * (optional) */ - public function purge($url, array $headers = []); + public function purge(string $url, array $headers = []): static; } diff --git a/src/ProxyClient/Invalidation/RefreshCapable.php b/src/ProxyClient/Invalidation/RefreshCapable.php index 3b0e5bb00..deb25decd 100644 --- a/src/ProxyClient/Invalidation/RefreshCapable.php +++ b/src/ProxyClient/Invalidation/RefreshCapable.php @@ -47,11 +47,9 @@ interface RefreshCapable extends ProxyClient * ->flush() * ; * - * @param string $url Path or URL to refresh - * @param array $headers Extra HTTP headers to send to the caching proxy - * (optional) - * - * @return $this + * @param string $url Path or URL to refresh + * @param array $headers Extra HTTP headers to send to the caching proxy + * (optional) */ - public function refresh($url, array $headers = []); + public function refresh(string $url, array $headers = []): static; } diff --git a/src/ProxyClient/Invalidation/TagCapable.php b/src/ProxyClient/Invalidation/TagCapable.php index 0ed19a59c..23f131442 100644 --- a/src/ProxyClient/Invalidation/TagCapable.php +++ b/src/ProxyClient/Invalidation/TagCapable.php @@ -25,9 +25,7 @@ interface TagCapable extends ProxyClient /** * Remove/Expire cache objects based on cache tags. * - * @param array $tags Tags that should be removed/expired from the cache. An empty tag list should be ignored. - * - * @return $this + * @param string[] $tags Tags that should be removed/expired from the cache. An empty tag list should be ignored. */ - public function invalidateTags(array $tags); + public function invalidateTags(array $tags): static; } diff --git a/src/ProxyClient/MultiplexerClient.php b/src/ProxyClient/MultiplexerClient.php index b8d35ab3a..e31d5bc53 100644 --- a/src/ProxyClient/MultiplexerClient.php +++ b/src/ProxyClient/MultiplexerClient.php @@ -11,7 +11,6 @@ namespace FOS\HttpCache\ProxyClient; -use FOS\HttpCache\Exception\ExceptionCollection; use FOS\HttpCache\Exception\InvalidArgumentException; use FOS\HttpCache\ProxyClient\Invalidation\BanCapable; use FOS\HttpCache\ProxyClient\Invalidation\ClearCapable; @@ -29,7 +28,7 @@ class MultiplexerClient implements BanCapable, PurgeCapable, RefreshCapable, Tag /** * @var ProxyClient[] */ - private $proxyClients; + private array $proxyClients; /** * MultiplexerClient constructor. @@ -41,8 +40,7 @@ public function __construct(array $proxyClients) foreach ($proxyClients as $proxyClient) { if (!$proxyClient instanceof ProxyClient) { throw new InvalidArgumentException( - 'Expected ProxyClientInterface, got: '. - (is_object($proxyClient) ? get_class($proxyClient) : gettype($proxyClient)) + 'Expected ProxyClientInterface, got: '.get_debug_type($proxyClient) ); } } @@ -50,31 +48,14 @@ public function __construct(array $proxyClients) $this->proxyClients = $proxyClients; } - /** - * Forwards to all clients. - * - * @param array $headers HTTP headers that path must match to be banned - * - * @return $this - */ - public function ban(array $headers) + public function ban(array $headers): static { $this->invoke(BanCapable::class, 'ban', [$headers]); return $this; } - /** - * Forwards to all clients. - * - * @param string $path Regular expression pattern for URI to invalidate - * @param string $contentType Regular expression pattern for the content type to limit banning, for instance - * 'text' - * @param array|string $hosts Regular expression of a host name or list of exact host names to limit banning - * - * @return $this - */ - public function banPath($path, $contentType = null, $hosts = null) + public function banPath(string $path, ?string $contentType = null, array|string|null $hosts = null): static { $this->invoke(BanCapable::class, 'banPath', [$path, $contentType, $hosts]); @@ -82,13 +63,11 @@ public function banPath($path, $contentType = null, $hosts = null) } /** - * Forwards to all clients. - * - * @return int The number of cache invalidations performed per caching server + * {@inheritDoc} * - * @throws ExceptionCollection If any errors occurred during flush + * Forwards to all clients. */ - public function flush() + public function flush(): int { $count = 0; foreach ($this->proxyClients as $proxyClient) { @@ -102,10 +81,8 @@ public function flush() * Forwards tag invalidation request to all clients. * * {@inheritdoc} - * - * @return $this */ - public function invalidateTags(array $tags) + public function invalidateTags(array $tags): static { if (!$tags) { return $this; @@ -119,12 +96,9 @@ public function invalidateTags(array $tags) /** * Forwards to all clients. * - * @param string $url Path or URL to purge - * @param array $headers Extra HTTP headers to send to the caching proxy (optional) - * - * @return $this + * {@inheritdoc} */ - public function purge($url, array $headers = []) + public function purge(string $url, array $headers = []): static { $this->invoke(PurgeCapable::class, 'purge', [$url, $headers]); @@ -134,12 +108,9 @@ public function purge($url, array $headers = []) /** * Forwards to all clients. * - * @param string $url Path or URL to refresh - * @param array $headers Extra HTTP headers to send to the caching proxy (optional) - * - * @return $this + * {@inheritdoc} */ - public function refresh($url, array $headers = []) + public function refresh(string $url, array $headers = []): static { $this->invoke(RefreshCapable::class, 'refresh', [$url, $headers]); @@ -149,9 +120,9 @@ public function refresh($url, array $headers = []) /** * Forwards to all clients. * - * @return $this + * {@inheritdoc} */ - public function clear() + public function clear(): static { $this->invoke(ClearCapable::class, 'clear', []); @@ -162,11 +133,11 @@ public function clear() * Invoke the given $method on all available ProxyClients implementing the * given $interface. * - * @param string $interface The FQN of the interface - * @param string $method The method to invoke - * @param array $arguments The arguments to be passed to the method + * @param string $interface The FQN of the interface + * @param string $method The method to invoke + * @param array $arguments The arguments to be passed to the method */ - private function invoke($interface, $method, array $arguments) + private function invoke(string $interface, string $method, array $arguments): void { foreach ($this->getProxyClients($interface) as $proxyClient) { call_user_func_array([$proxyClient, $method], $arguments); @@ -176,15 +147,15 @@ private function invoke($interface, $method, array $arguments) /** * Get proxy clients that implement a feature interface. * - * @param string $interface + * @param class-string $interface * * @return ProxyClient[] */ - private function getProxyClients($interface) + private function getProxyClients(string $interface): array { return array_filter( $this->proxyClients, - function ($proxyClient) use ($interface) { + static function ($proxyClient) use ($interface) { return is_subclass_of($proxyClient, $interface); } ); diff --git a/src/ProxyClient/Nginx.php b/src/ProxyClient/Nginx.php index 97deb240c..b3b695ce5 100644 --- a/src/ProxyClient/Nginx.php +++ b/src/ProxyClient/Nginx.php @@ -13,6 +13,7 @@ use FOS\HttpCache\ProxyClient\Invalidation\PurgeCapable; use FOS\HttpCache\ProxyClient\Invalidation\RefreshCapable; +use Symfony\Component\OptionsResolver\OptionsResolver; /** * NGINX HTTP cache invalidator. @@ -31,7 +32,7 @@ class Nginx extends HttpProxyClient implements PurgeCapable, RefreshCapable public const HTTP_HEADER_REFRESH = 'X-Refresh'; - public function refresh($url, array $headers = []) + public function refresh(string $url, array $headers = []): static { $headers = array_merge($headers, [self::HTTP_HEADER_REFRESH => '1']); $this->queueRequest(self::HTTP_METHOD_REFRESH, $url, $headers); @@ -39,7 +40,7 @@ public function refresh($url, array $headers = []) return $this; } - public function purge($url, array $headers = []) + public function purge(string $url, array $headers = []): static { $purgeUrl = $this->buildPurgeUrl($url); $this->queueRequest(self::HTTP_METHOD_PURGE, $purgeUrl, $headers); @@ -47,7 +48,7 @@ public function purge($url, array $headers = []) return $this; } - protected function configureOptions() + protected function configureOptions(): OptionsResolver { $resolver = parent::configureOptions(); $resolver->setDefaults(['purge_location' => false]); @@ -57,12 +58,8 @@ protected function configureOptions() /** * Create the correct URL to purge a resource. - * - * @param string $url URL - * - * @return string Rewritten URL */ - private function buildPurgeUrl($url) + private function buildPurgeUrl(string $url): string { if (!$this->options['purge_location']) { return $url; diff --git a/src/ProxyClient/Noop.php b/src/ProxyClient/Noop.php index 2d00ff0fd..904b7c4b7 100644 --- a/src/ProxyClient/Noop.php +++ b/src/ProxyClient/Noop.php @@ -28,37 +28,37 @@ */ class Noop implements ProxyClient, BanCapable, PurgeCapable, RefreshCapable, TagCapable, ClearCapable { - public function ban(array $headers) + public function ban(array $headers): static { return $this; } - public function banPath($path, $contentType = null, $hosts = null) + public function banPath(string $path, ?string $contentType = null, array|string|null $hosts = null): static { return $this; } - public function invalidateTags(array $tags) + public function invalidateTags(array $tags): static { return $this; } - public function purge($url, array $headers = []) + public function purge(string $url, array $headers = []): static { return $this; } - public function refresh($url, array $headers = []) + public function refresh(string $url, array $headers = []): static { return $this; } - public function flush() + public function flush(): int { return 0; } - public function clear() + public function clear(): static { return $this; } diff --git a/src/ProxyClient/ProxyClient.php b/src/ProxyClient/ProxyClient.php index 3f3f924e8..fdeb9d694 100644 --- a/src/ProxyClient/ProxyClient.php +++ b/src/ProxyClient/ProxyClient.php @@ -27,5 +27,5 @@ interface ProxyClient * * @throws ExceptionCollection if any errors occurred during flush */ - public function flush(); + public function flush(): int; } diff --git a/src/ProxyClient/Symfony.php b/src/ProxyClient/Symfony.php index 07f5059c4..eacbf733f 100644 --- a/src/ProxyClient/Symfony.php +++ b/src/ProxyClient/Symfony.php @@ -17,6 +17,7 @@ use FOS\HttpCache\ProxyClient\Invalidation\TagCapable; use FOS\HttpCache\SymfonyCache\PurgeListener; use FOS\HttpCache\SymfonyCache\PurgeTagsListener; +use Symfony\Component\OptionsResolver\OptionsResolver; /** * Symfony HttpCache invalidator. @@ -31,14 +32,14 @@ class Symfony extends HttpProxyClient implements PurgeCapable, RefreshCapable, T { public const HTTP_METHOD_REFRESH = 'GET'; - public function purge($url, array $headers = []) + public function purge(string $url, array $headers = []): static { $this->queueRequest($this->options['purge_method'], $url, $headers); return $this; } - public function refresh($url, array $headers = []) + public function refresh(string $url, array $headers = []): static { $headers = array_merge($headers, ['Cache-Control' => 'no-cache']); $this->queueRequest(self::HTTP_METHOD_REFRESH, $url, $headers); @@ -46,7 +47,7 @@ public function refresh($url, array $headers = []) return $this; } - protected function configureOptions() + protected function configureOptions(): OptionsResolver { $resolver = parent::configureOptions(); $resolver->setDefaults([ @@ -67,7 +68,7 @@ protected function configureOptions() return $resolver; } - public function invalidateTags(array $tags) + public function invalidateTags(array $tags): static { if (!$tags) { return $this; @@ -94,10 +95,8 @@ public function invalidateTags(array $tags) * * Clearing the cache is implemented with a purge request with a special * header to indicate that the whole cache should be removed. - * - * @return $this */ - public function clear() + public function clear(): static { $this->queueRequest( $this->options['purge_method'], diff --git a/src/ProxyClient/Varnish.php b/src/ProxyClient/Varnish.php index e85ba7ea4..a4b7137e2 100644 --- a/src/ProxyClient/Varnish.php +++ b/src/ProxyClient/Varnish.php @@ -17,6 +17,7 @@ use FOS\HttpCache\ProxyClient\Invalidation\RefreshCapable; use FOS\HttpCache\ProxyClient\Invalidation\TagCapable; use Symfony\Component\OptionsResolver\Options; +use Symfony\Component\OptionsResolver\OptionsResolver; /** * Varnish HTTP cache invalidator. @@ -60,14 +61,12 @@ class Varnish extends HttpProxyClient implements BanCapable, PurgeCapable, Refre * * This happens to be the same as TagHeaderFormatter::DEFAULT_HEADER_NAME * but does not technically need to be the same. - * - * @var string */ public const DEFAULT_HTTP_HEADER_CACHE_TAGS = 'X-Cache-Tags'; public const DEFAULT_HTTP_HEADER_CACHE_XKEY = 'xkey-softpurge'; - public function invalidateTags(array $tags) + public function invalidateTags(array $tags): static { if (!$tags) { return $this; @@ -93,7 +92,7 @@ public function invalidateTags(array $tags) return $this; } - public function ban(array $headers) + public function ban(array $headers): static { $headers = array_merge( $this->options['default_ban_headers'], @@ -105,7 +104,7 @@ public function ban(array $headers) return $this; } - public function banPath($path, $contentType = null, $hosts = null) + public function banPath(string $path, ?string $contentType = null, array|string|null $hosts = null): static { if (is_array($hosts)) { if (!count($hosts)) { @@ -128,14 +127,14 @@ public function banPath($path, $contentType = null, $hosts = null) return $this->ban($headers); } - public function purge($url, array $headers = []) + public function purge(string $url, array $headers = []): static { $this->queueRequest(self::HTTP_METHOD_PURGE, $url, $headers); return $this; } - public function refresh($url, array $headers = []) + public function refresh(string $url, array $headers = []): static { $headers = array_merge($headers, ['Cache-Control' => 'no-cache']); $this->queueRequest(self::HTTP_METHOD_REFRESH, $url, $headers); @@ -143,7 +142,7 @@ public function refresh($url, array $headers = []) return $this; } - protected function configureOptions() + protected function configureOptions(): OptionsResolver { $resolver = parent::configureOptions(); $resolver->setDefaults([ @@ -174,13 +173,19 @@ protected function configureOptions() return $resolver; } - private function invalidateByBan(array $tagchunk) + /** + * @param string[] $tagchunk + */ + private function invalidateByBan(array $tagchunk): void { $tagExpression = sprintf('(^|,)(%s)(,|$)', implode('|', $tagchunk)); $this->ban([$this->options['tags_header'] => $tagExpression]); } - private function invalidateByPurgekeys(array $tagchunk) + /** + * @param string[] $tagchunk + */ + private function invalidateByPurgekeys(array $tagchunk): void { $this->queueRequest( self::HTTP_METHOD_PURGEKEYS, diff --git a/src/ResponseTagger.php b/src/ResponseTagger.php index 495a694c7..6b68dadab 100644 --- a/src/ResponseTagger.php +++ b/src/ResponseTagger.php @@ -34,20 +34,14 @@ */ class ResponseTagger { - /** - * @var array - */ - private $options; + private array $options; - /** - * @var TagHeaderFormatter - */ - private $headerFormatter; + private TagHeaderFormatter $headerFormatter; /** - * @var array + * @var string[] */ - private $tags = []; + private array $tags = []; /** * Create the response tagger with a tag header formatter and options. @@ -77,10 +71,8 @@ public function __construct(array $options = []) /** * Get the HTTP header name that will hold cache tags. - * - * @return string */ - public function getTagsHeaderName() + public function getTagsHeaderName(): string { return $this->headerFormatter->getTagsHeaderName(); } @@ -90,9 +82,9 @@ public function getTagsHeaderName() * * This concatenates all tags and ensures correct encoding. * - * @erturn string + * @return string|string[] */ - public function getTagsHeaderValue() + public function getTagsHeaderValue(): string|array { return $this->headerFormatter->getTagsHeaderValue($this->tags); } @@ -104,23 +96,21 @@ public function getTagsHeaderValue() * * @return string[] */ - protected function parseTagsHeaderValue(array|string $headers) + protected function parseTagsHeaderValue(array|string $headers): array { if ($this->headerFormatter instanceof TagHeaderParser) { return $this->headerFormatter->parseTagsHeaderValue($headers); } - return array_merge(...array_map(function ($header) { + return array_merge(...array_map(static function ($header) { return explode(',', $header); }, $headers)); } /** * Check whether the tag handler has any tags to set on the response. - * - * @return bool */ - public function hasTags() + public function hasTags(): bool { return 0 < count($this->tags); } @@ -132,11 +122,9 @@ public function hasTags() * * @param string[] $tags List of tags to add * - * @return $this - * * @throws InvalidTagException */ - public function addTags(array $tags) + public function addTags(array $tags): self { $filtered = array_filter($tags, 'is_string'); $filtered = array_filter($filtered, 'strlen'); @@ -166,11 +154,9 @@ public function clear(): void * * @param ResponseInterface $response Original response * @param bool $replace Whether to replace the current tags - * on the response - * - * @return ResponseInterface + * on the response or add them additionally */ - public function tagResponse(ResponseInterface $response, bool $replace = false) + public function tagResponse(ResponseInterface $response, bool $replace = false): ResponseInterface { if (!$this->hasTags()) { return $response; @@ -179,6 +165,7 @@ public function tagResponse(ResponseInterface $response, bool $replace = false) $tagsHeaderValue = $this->getTagsHeaderValue(); $this->clear(); + // withHeader accepts a single header or an array of multiple headers. if ($replace) { return $response->withHeader($this->getTagsHeaderName(), $tagsHeaderValue); } diff --git a/src/SymfonyCache/AccessControlledListener.php b/src/SymfonyCache/AccessControlledListener.php index faa497a48..21e28df18 100644 --- a/src/SymfonyCache/AccessControlledListener.php +++ b/src/SymfonyCache/AccessControlledListener.php @@ -59,10 +59,8 @@ public function __construct(array $options = []) /** * Get the options resolver for the constructor arguments. - * - * @return OptionsResolver */ - protected function getOptionsResolver() + protected function getOptionsResolver(): OptionsResolver { $resolver = new OptionsResolver(); $resolver->setDefaults([ @@ -75,14 +73,7 @@ protected function getOptionsResolver() return $resolver; } - /** - * Check whether the request is allowed. - * - * @param Request $request The request to check - * - * @return bool Whether access is granted - */ - protected function isRequestAllowed(Request $request) + protected function isRequestAllowed(Request $request): bool { return $this->clientMatcher->matches($request); } diff --git a/src/SymfonyCache/CleanupCacheTagsListener.php b/src/SymfonyCache/CleanupCacheTagsListener.php index 2de9d5a66..16b65a1fe 100644 --- a/src/SymfonyCache/CleanupCacheTagsListener.php +++ b/src/SymfonyCache/CleanupCacheTagsListener.php @@ -22,20 +22,17 @@ */ class CleanupCacheTagsListener implements EventSubscriberInterface { - /** - * @var string - */ - private $tagsHeader; + private string $tagsHeader; /** * @param string $tagsHeader The header that is used for cache tags */ - public function __construct($tagsHeader = TagHeaderFormatter::DEFAULT_HEADER_NAME) + public function __construct(string $tagsHeader = TagHeaderFormatter::DEFAULT_HEADER_NAME) { $this->tagsHeader = $tagsHeader; } - public function removeTagsHeader(CacheEvent $e) + public function removeTagsHeader(CacheEvent $e): void { if (null === $response = $e->getResponse()) { return; diff --git a/src/SymfonyCache/CustomTtlListener.php b/src/SymfonyCache/CustomTtlListener.php index 850fe1845..8bad52a5d 100644 --- a/src/SymfonyCache/CustomTtlListener.php +++ b/src/SymfonyCache/CustomTtlListener.php @@ -23,20 +23,12 @@ */ class CustomTtlListener implements EventSubscriberInterface { - /** - * @var string - */ - private $ttlHeader; + private string $ttlHeader; - /** - * @var bool - */ - private $keepTtlHeader; + private bool $keepTtlHeader; /** * Header used for backing up the s-maxage. - * - * @var string */ public const SMAXAGE_BACKUP = 'FOS-Smaxage-Backup'; @@ -44,7 +36,7 @@ class CustomTtlListener implements EventSubscriberInterface * @param string $ttlHeader The header name that is used to specify the time to live * @param bool $keepTtlHeader Keep the custom TTL header on the response for later usage (e.g. debugging) */ - public function __construct($ttlHeader = 'X-Reverse-Proxy-TTL', $keepTtlHeader = false) + public function __construct(string $ttlHeader = 'X-Reverse-Proxy-TTL', bool $keepTtlHeader = false) { $this->ttlHeader = $ttlHeader; $this->keepTtlHeader = $keepTtlHeader; @@ -56,9 +48,12 @@ public function __construct($ttlHeader = 'X-Reverse-Proxy-TTL', $keepTtlHeader = * If there is such a header, the original s_maxage is backed up to the * static::SMAXAGE_BACKUP header. */ - public function useCustomTtl(CacheEvent $e) + public function useCustomTtl(CacheEvent $e): void { $response = $e->getResponse(); + if (!$response) { + return; + } if (!$response->headers->has($this->ttlHeader)) { return; } @@ -73,9 +68,12 @@ public function useCustomTtl(CacheEvent $e) /** * Remove the custom TTL header and restore s_maxage from the backup. */ - public function cleanResponse(CacheEvent $e) + public function cleanResponse(CacheEvent $e): void { $response = $e->getResponse(); + if (!$response) { + return; + } if (!$response->headers->has($this->ttlHeader) && !$response->headers->has(static::SMAXAGE_BACKUP) ) { diff --git a/src/SymfonyCache/DebugListener.php b/src/SymfonyCache/DebugListener.php index b3738e88d..0294f6409 100644 --- a/src/SymfonyCache/DebugListener.php +++ b/src/SymfonyCache/DebugListener.php @@ -35,13 +35,16 @@ public static function getSubscribedEvents(): array * For this header to be present, the HttpCache must be created with the * debug option set to true. */ - public function handleDebug(CacheEvent $event) + public function handleDebug(CacheEvent $event): void { $response = $event->getResponse(); + if (!$response) { + return; + } if ($response->headers->has('X-Symfony-Cache')) { - if (false !== strpos($response->headers->get('X-Symfony-Cache'), 'miss')) { + if (str_contains($response->headers->get('X-Symfony-Cache'), 'miss')) { $state = 'MISS'; - } elseif (false !== strpos($response->headers->get('X-Symfony-Cache'), 'fresh')) { + } elseif (str_contains($response->headers->get('X-Symfony-Cache'), 'fresh')) { $state = 'HIT'; } else { $state = 'UNDETERMINED'; diff --git a/src/SymfonyCache/EventDispatchingHttpCache.php b/src/SymfonyCache/EventDispatchingHttpCache.php index 1be403a1b..36a3c4ab9 100644 --- a/src/SymfonyCache/EventDispatchingHttpCache.php +++ b/src/SymfonyCache/EventDispatchingHttpCache.php @@ -66,7 +66,7 @@ public function addSubscriber(EventSubscriberInterface $subscriber): void * * @see EventDispatcherInterface::addListener */ - public function addListener($eventName, $listener, $priority = 0): void + public function addListener(string $eventName, callable $listener, int $priority = 0): void { $this->getEventDispatcher()->addListener($eventName, $listener, $priority); } @@ -76,7 +76,7 @@ public function addListener($eventName, $listener, $priority = 0): void * * Adding the Events::PRE_HANDLE and Events::POST_HANDLE events. */ - public function handle(Request $request, $type = HttpKernelInterface::MAIN_REQUEST, $catch = true): Response + public function handle(Request $request, int $type = HttpKernelInterface::MAIN_REQUEST, bool $catch = true): Response { // trigger loading the CacheEvent to avoid fatal error when HttpKernel::loadClassCache is used. class_exists(CacheEvent::class); @@ -107,7 +107,7 @@ protected function store(Request $request, Response $response): void * * Adding the Events::PRE_INVALIDATE event. */ - protected function invalidate(Request $request, $catch = false): Response + protected function invalidate(Request $request, bool $catch = false): Response { if ($response = $this->dispatch(Events::PRE_INVALIDATE, $request)) { return $response; diff --git a/src/SymfonyCache/HttpCacheAware.php b/src/SymfonyCache/HttpCacheAware.php index b736678dc..17a2c3511 100644 --- a/src/SymfonyCache/HttpCacheAware.php +++ b/src/SymfonyCache/HttpCacheAware.php @@ -18,20 +18,14 @@ */ trait HttpCacheAware { - /** - * @var HttpKernelInterface|null - */ - private $httpCache; + private ?HttpKernelInterface $httpCache; - /** - * @return HttpKernelInterface|null - */ - public function getHttpCache() + public function getHttpCache(): ?HttpKernelInterface { return $this->httpCache; } - public function setHttpCache(HttpKernelInterface $httpCache) + public function setHttpCache(HttpKernelInterface $httpCache): void { $this->httpCache = $httpCache; } diff --git a/src/SymfonyCache/HttpCacheProvider.php b/src/SymfonyCache/HttpCacheProvider.php index 055b4a395..9dbf14d64 100644 --- a/src/SymfonyCache/HttpCacheProvider.php +++ b/src/SymfonyCache/HttpCacheProvider.php @@ -15,8 +15,5 @@ interface HttpCacheProvider { - /** - * @return HttpKernelInterface|null - */ - public function getHttpCache(); + public function getHttpCache(): ?HttpKernelInterface; } diff --git a/src/SymfonyCache/KernelDispatcher.php b/src/SymfonyCache/KernelDispatcher.php index 789adf24c..c7a23a47a 100644 --- a/src/SymfonyCache/KernelDispatcher.php +++ b/src/SymfonyCache/KernelDispatcher.php @@ -44,7 +44,7 @@ public function __construct(HttpCacheProvider $httpCacheProvider) $this->httpCacheProvider = $httpCacheProvider; } - public function invalidate(RequestInterface $invalidationRequest, $validateHost = true): void + public function invalidate(RequestInterface $invalidationRequest, bool $validateHost = true): void { $request = Request::create( $invalidationRequest->getUri(), diff --git a/src/SymfonyCache/PurgeListener.php b/src/SymfonyCache/PurgeListener.php index d146ae3ce..7c819695b 100644 --- a/src/SymfonyCache/PurgeListener.php +++ b/src/SymfonyCache/PurgeListener.php @@ -29,17 +29,13 @@ class PurgeListener extends AccessControlledListener /** * The purge method to use. - * - * @var string */ - private $purgeMethod; + private string $purgeMethod; /** * The clear cache header to use. - * - * @var string */ - private $clearCacheHeader; + private string $clearCacheHeader; /** * When creating the purge listener, you can configure an additional option. @@ -73,7 +69,7 @@ public static function getSubscribedEvents(): array * * Prevents access when the request comes from a non-authorized client. */ - public function handlePurge(CacheEvent $event) + public function handlePurge(CacheEvent $event): void { $request = $event->getRequest(); if ($this->purgeMethod !== $request->getMethod()) { @@ -117,10 +113,8 @@ public function handlePurge(CacheEvent $event) /** * Add the purge_method option. - * - * @return OptionsResolver */ - protected function getOptionsResolver() + protected function getOptionsResolver(): OptionsResolver { $resolver = parent::getOptionsResolver(); $resolver->setDefault('purge_method', static::DEFAULT_PURGE_METHOD); diff --git a/src/SymfonyCache/PurgeTagsListener.php b/src/SymfonyCache/PurgeTagsListener.php index 90649dfad..acf863c8e 100644 --- a/src/SymfonyCache/PurgeTagsListener.php +++ b/src/SymfonyCache/PurgeTagsListener.php @@ -30,22 +30,15 @@ class PurgeTagsListener extends AccessControlledListener /** * The purge tags method to use. - * - * @var string */ - private $tagsMethod; + private string $tagsMethod; /** * The purge tags header to use. - * - * @var string */ - private $tagsHeader; + private string $tagsHeader; - /** - * @var TagHeaderParser - */ - private $tagsParser; + private TagHeaderParser $tagsParser; /** * When creating the purge listener, you can configure an additional option. @@ -85,7 +78,7 @@ public static function getSubscribedEvents(): array * * Prevents access when the request comes from a non-authorized client. */ - public function handlePurgeTags(CacheEvent $event) + public function handlePurgeTags(CacheEvent $event): void { $request = $event->getRequest(); if ($this->tagsMethod !== $request->getMethod()) { @@ -141,10 +134,8 @@ public function handlePurgeTags(CacheEvent $event) /** * Add the purge_method option. - * - * @return OptionsResolver */ - protected function getOptionsResolver() + protected function getOptionsResolver(): OptionsResolver { $resolver = parent::getOptionsResolver(); $resolver->setDefaults([ diff --git a/src/SymfonyCache/RefreshListener.php b/src/SymfonyCache/RefreshListener.php index 5807355a3..995638e3b 100644 --- a/src/SymfonyCache/RefreshListener.php +++ b/src/SymfonyCache/RefreshListener.php @@ -36,7 +36,7 @@ public static function getSubscribedEvents(): array * When the request comes from a non-authorized client, ignore refresh to * let normal lookup happen. */ - public function handleRefresh(CacheEvent $event) + public function handleRefresh(CacheEvent $event): void { $request = $event->getRequest(); // BC - we can drop this check when we only support Symfony 3.1 and newer diff --git a/src/SymfonyCache/UserContextListener.php b/src/SymfonyCache/UserContextListener.php index c5c46cc96..37e6b70af 100644 --- a/src/SymfonyCache/UserContextListener.php +++ b/src/SymfonyCache/UserContextListener.php @@ -27,17 +27,13 @@ class UserContextListener implements EventSubscriberInterface { /** * The options configured in the constructor argument or default values. - * - * @var array */ - private $options; + private array $options; /** * Generated user hash. - * - * @var string */ - private $userHash; + private string $userHash; /** * When creating this listener, you can configure a number of options. @@ -193,12 +189,10 @@ private function isAnonymous(Request $request): bool /** * Checks if passed string can be considered as a session name, such as would be used in cookies. - * - * @param string $name */ - private function isSessionName($name): bool + private function isSessionName(string $name): bool { - return 0 === strpos($name, $this->options['session_name_prefix']); + return str_starts_with($name, $this->options['session_name_prefix']); } /** diff --git a/src/TagHeaderFormatter/CommaSeparatedTagHeaderFormatter.php b/src/TagHeaderFormatter/CommaSeparatedTagHeaderFormatter.php index 36ddc5008..cb34c1fb6 100644 --- a/src/TagHeaderFormatter/CommaSeparatedTagHeaderFormatter.php +++ b/src/TagHeaderFormatter/CommaSeparatedTagHeaderFormatter.php @@ -18,37 +18,27 @@ */ class CommaSeparatedTagHeaderFormatter implements TagHeaderFormatter, TagHeaderParser { - /** - * @var string - */ - private $headerName; - - /** - * @var string - */ - private $glue; - - /** - * @param string $headerName - * @param string $glue Separator character for the tag header - */ - public function __construct($headerName = TagHeaderFormatter::DEFAULT_HEADER_NAME, $glue = ',') + private string $headerName; + + private string $glue; + + public function __construct(string $headerName = TagHeaderFormatter::DEFAULT_HEADER_NAME, string $glue = ',') { $this->headerName = $headerName; $this->glue = $glue; } - public function getTagsHeaderName() + public function getTagsHeaderName(): string { return $this->headerName; } - public function getTagsHeaderValue(array $tags) + public function getTagsHeaderValue(array $tags): array|string { return implode($this->glue, $tags); } - public function parseTagsHeaderValue($tags): array + public function parseTagsHeaderValue(array|string $tags): array { if (is_string($tags)) { $tags = [$tags]; diff --git a/src/TagHeaderFormatter/MaxHeaderValueLengthFormatter.php b/src/TagHeaderFormatter/MaxHeaderValueLengthFormatter.php index aa051697d..5895f6b66 100644 --- a/src/TagHeaderFormatter/MaxHeaderValueLengthFormatter.php +++ b/src/TagHeaderFormatter/MaxHeaderValueLengthFormatter.php @@ -23,43 +23,35 @@ */ class MaxHeaderValueLengthFormatter implements TagHeaderFormatter, TagHeaderParser { - /** - * @var TagHeaderFormatter - */ - private $inner; + private TagHeaderFormatter $inner; - /** - * @var int - */ - private $maxHeaderValueLength; + private int $maxHeaderValueLength; /** * The default value of the maximum header length is 4096 because most * servers limit header values to 4kb. * HTTP messages cannot carry characters outside the ISO-8859-1 standard so they all * use up just one byte. - * - * @param int $maxHeaderValueLength */ - public function __construct(TagHeaderFormatter $inner, $maxHeaderValueLength = 4096) + public function __construct(TagHeaderFormatter $inner, int $maxHeaderValueLength = 4096) { $this->inner = $inner; $this->maxHeaderValueLength = $maxHeaderValueLength; } - public function getTagsHeaderName() + public function getTagsHeaderName(): string { return $this->inner->getTagsHeaderName(); } - public function getTagsHeaderValue(array $tags) + public function getTagsHeaderValue(array $tags): array|string { $values = (array) $this->inner->getTagsHeaderValue($tags); $newValues = [[]]; foreach ($values as $value) { if ($this->isHeaderTooLong($value)) { - list($firstTags, $secondTags) = $this->splitTagsInHalves($tags); + [$firstTags, $secondTags] = $this->splitTagsInHalves($tags); $newValues[] = (array) $this->getTagsHeaderValue($firstTags); $newValues[] = (array) $this->getTagsHeaderValue($secondTags); @@ -77,7 +69,7 @@ public function getTagsHeaderValue(array $tags) return $newValues; } - public function parseTagsHeaderValue($tags): array + public function parseTagsHeaderValue(array|string $tags): array { if ($this->inner instanceof TagHeaderParser) { return $this->inner->parseTagsHeaderValue($tags); @@ -86,12 +78,7 @@ public function parseTagsHeaderValue($tags): array throw new \BadMethodCallException('The inner formatter does not implement '.TagHeaderParser::class); } - /** - * @param string $value - * - * @return bool - */ - private function isHeaderTooLong($value) + private function isHeaderTooLong(string $value): bool { return mb_strlen($value) > $this->maxHeaderValueLength; } @@ -99,11 +86,11 @@ private function isHeaderTooLong($value) /** * Split an array of tags in two more or less equal sized arrays. * - * @return array + * @return string[][] * * @throws InvalidTagException */ - private function splitTagsInHalves(array $tags) + private function splitTagsInHalves(array $tags): array { if (1 === count($tags)) { throw new InvalidTagException(sprintf( diff --git a/src/TagHeaderFormatter/TagHeaderFormatter.php b/src/TagHeaderFormatter/TagHeaderFormatter.php index 83fe3be00..d972f9af8 100644 --- a/src/TagHeaderFormatter/TagHeaderFormatter.php +++ b/src/TagHeaderFormatter/TagHeaderFormatter.php @@ -27,10 +27,8 @@ interface TagHeaderFormatter /** * Get the HTTP header name that will hold cache tags. - * - * @return string */ - public function getTagsHeaderName(); + public function getTagsHeaderName(): string; /** * Get the value for the HTTP tag header. @@ -39,5 +37,5 @@ public function getTagsHeaderName(); * * @return string|string[] */ - public function getTagsHeaderValue(array $tags); + public function getTagsHeaderValue(array $tags): array|string; } diff --git a/src/TagHeaderFormatter/TagHeaderParser.php b/src/TagHeaderFormatter/TagHeaderParser.php index c176cf981..6d1ecdc13 100644 --- a/src/TagHeaderFormatter/TagHeaderParser.php +++ b/src/TagHeaderFormatter/TagHeaderParser.php @@ -25,5 +25,5 @@ interface TagHeaderParser * * @return string[] */ - public function parseTagsHeaderValue($tags): array; + public function parseTagsHeaderValue(array|string $tags): array; } diff --git a/src/Test/CacheAssertions.php b/src/Test/CacheAssertions.php index 52c45584b..c5eb8d109 100644 --- a/src/Test/CacheAssertions.php +++ b/src/Test/CacheAssertions.php @@ -33,7 +33,7 @@ trait CacheAssertions * * @param string $message Test failure message (optional) */ - public function assertMiss(ResponseInterface $response, $message = '') + public function assertMiss(ResponseInterface $response, string $message = ''): void { TestCase::assertThat($response, self::isCacheMiss(), $message); } @@ -43,17 +43,17 @@ public function assertMiss(ResponseInterface $response, $message = '') * * @param string $message Test failure message (optional) */ - public function assertHit(ResponseInterface $response, $message = '') + public function assertHit(ResponseInterface $response, string $message = ''): void { TestCase::assertThat($response, self::isCacheHit(), $message); } - public static function isCacheHit() + public static function isCacheHit(): IsCacheHitConstraint { return new IsCacheHitConstraint(); } - public static function isCacheMiss() + public static function isCacheMiss(): IsCacheMissConstraint { return new IsCacheMissConstraint(); } diff --git a/src/Test/EventDispatchingHttpCacheTestCase.php b/src/Test/EventDispatchingHttpCacheTestCase.php index 6c4f5ab64..c59e79990 100644 --- a/src/Test/EventDispatchingHttpCacheTestCase.php +++ b/src/Test/EventDispatchingHttpCacheTestCase.php @@ -32,18 +32,16 @@ abstract class EventDispatchingHttpCacheTestCase extends TestCase /** * Specify the CacheInvalidationInterface HttpCache class to test. * - * @return string Fully qualified class name of the AppCache + * @return class-string Fully qualified class name of the AppCache */ - abstract protected function getCacheClass(); + abstract protected function getCacheClass(): string; /** * Create a partial mock of the HttpCache to only test some methods. * - * @param array $mockedMethods List of methods to mock - * - * @return CacheInvalidation|EventDispatchingHttpCache|MockObject + * @param string[] $mockedMethods List of methods to mock */ - protected function getHttpCachePartialMock(?array $mockedMethods = null) + protected function getHttpCachePartialMock(?array $mockedMethods = null): MockObject|CacheInvalidation|EventDispatchingHttpCache { $mock = $this ->getMockBuilder($this->getCacheClass()) @@ -70,11 +68,9 @@ protected function getHttpCachePartialMock(?array $mockedMethods = null) $refHttpCache = new \ReflectionClass(HttpCache::class); $refOptions = $refHttpCache->getProperty('options'); - $refOptions->setAccessible(true); $refOptions->setValue($mock, $options); $surrogate = $refHttpCache->getProperty('surrogate'); - $surrogate->setAccessible(true); $surrogate->setValue($mock, null); return $mock; @@ -83,7 +79,7 @@ protected function getHttpCachePartialMock(?array $mockedMethods = null) /** * Set the store property on a HttpCache to a StoreInterface expecting one write with request and response. */ - protected function setStoreMock(CacheInvalidation $httpCache, Request $request, Response $response) + protected function setStoreMock(CacheInvalidation $httpCache, Request $request, Response $response): void { $store = $this->createMock(StoreInterface::class); $store @@ -93,14 +89,13 @@ protected function setStoreMock(CacheInvalidation $httpCache, Request $request, ; $refHttpCache = new \ReflectionClass(HttpCache::class); $refStore = $refHttpCache->getProperty('store'); - $refStore->setAccessible(true); $refStore->setValue($httpCache, $store); } /** * Assert that preHandle and postHandle are called. */ - public function testHandleCalled() + public function testHandleCalled(): void { $catch = true; $request = Request::create('/foo', 'GET'); @@ -176,7 +171,7 @@ public function testPostHandleReturn(): void * * @depends testHandleCalled */ - public function testPostHandleAfterPreHandle() + public function testPostHandleAfterPreHandle(): void { $catch = true; $request = Request::create('/foo', 'GET'); @@ -201,7 +196,7 @@ public function testPostHandleAfterPreHandle() /** * Assert that preStore is called. */ - public function testPreStoreCalled() + public function testPreStoreCalled(): void { $request = Request::create('/foo', 'GET'); $response = new Response(); @@ -214,7 +209,6 @@ public function testPreStoreCalled() $refHttpCache = new \ReflectionObject($httpCache); $method = $refHttpCache->getMethod('store'); - $method->setAccessible(true); $method->invokeArgs($httpCache, [$request, $response]); $this->assertEquals(1, $testListener->preStoreCalls); } @@ -222,7 +216,7 @@ public function testPreStoreCalled() /** * Assert that preStore response is used when provided. */ - public function testPreStoreResponse() + public function testPreStoreResponse(): void { $request = Request::create('/foo', 'GET'); $regularResponse = new Response(); @@ -237,7 +231,6 @@ public function testPreStoreResponse() $refHttpCache = new \ReflectionObject($httpCache); $method = $refHttpCache->getMethod('store'); - $method->setAccessible(true); $method->invokeArgs($httpCache, [$request, $regularResponse]); $this->assertEquals(1, $testListener->preStoreCalls); } @@ -245,7 +238,7 @@ public function testPreStoreResponse() /** * Assert that preInvalidate is called. */ - public function testPreInvalidateCalled() + public function testPreInvalidateCalled(): void { $catch = true; $request = Request::create('/foo', 'GET'); @@ -261,7 +254,6 @@ public function testPreInvalidateCalled() ; $refHttpCache = new \ReflectionObject($httpCache); $method = $refHttpCache->getMethod('invalidate'); - $method->setAccessible(true); $this->assertSame($response, $method->invokeArgs($httpCache, [$request, $catch])); $this->assertEquals(1, $testListener->preInvalidateCalls); @@ -288,7 +280,6 @@ public function testPreInvalidateReturnEarly(): void ; $refHttpCache = new \ReflectionObject($httpCache); $method = $refHttpCache->getMethod('invalidate'); - $method->setAccessible(true); $this->assertSame($response, $method->invokeArgs($httpCache, [$request, $catch])); $this->assertEquals(1, $testListener->preInvalidateCalls); diff --git a/src/Test/HttpCaller.php b/src/Test/HttpCaller.php index a9de5bf7d..d705d712a 100644 --- a/src/Test/HttpCaller.php +++ b/src/Test/HttpCaller.php @@ -20,23 +20,18 @@ trait HttpCaller { /** * HTTP client for requests to the application. - * - * @var HttpClient */ - private $httpClient; + private HttpClient $httpClient; /** * Call a HTTP resource from your test. * - * @param string $uri HTTP URI, domain and port are added from the embedding class if not specified - * @param array $headers HTTP headers - * @param string $method HTTP method - * - * @return ResponseInterface + * @param string $uri HTTP URI, domain and port are added from the embedding class if not specified + * @param array $headers HTTP headers */ - protected function getResponse($uri, array $headers = [], $method = 'GET') + protected function getResponse(string $uri, array $headers = [], string $method = 'GET'): ResponseInterface { - if (!$this->httpClient) { + if (!isset($this->httpClient)) { $this->httpClient = new HttpClient($this->getHostName(), $this->getCachingProxyPort()); } @@ -45,15 +40,11 @@ protected function getResponse($uri, array $headers = [], $method = 'GET') /** * Get the default host name to use. - * - * @return string */ - abstract protected function getHostName(); + abstract protected function getHostName(): string; /** * Get the default port to use. - * - * @return string */ - abstract protected function getCachingProxyPort(); + abstract protected function getCachingProxyPort(): int; } diff --git a/src/Test/HttpClient.php b/src/Test/HttpClient.php index 3b02ec4f6..7a280c374 100644 --- a/src/Test/HttpClient.php +++ b/src/Test/HttpClient.php @@ -26,26 +26,18 @@ class HttpClient { /** * HTTP client for requests to the application. - * - * @var PhpHttpClient */ - private $httpClient; + private PhpHttpClient $httpClient; - /** - * @var string - */ - private $hostname; + private string $hostname; - /** - * @var string - */ - private $port; + private string $port; /** * @param string $hostname Default hostname if not specified in the URL * @param string $port Default port if not specified in the URL */ - public function __construct($hostname, $port) + public function __construct(string $hostname, string $port) { $this->hostname = $hostname; $this->port = $port; @@ -57,10 +49,8 @@ public function __construct($hostname, $port) * @param string $uri HTTP URI * @param array $headers HTTP headers * @param string $method HTTP method - * - * @return ResponseInterface */ - public function getResponse($uri, array $headers, $method) + public function getResponse(string $uri, array $headers, string $method): ResponseInterface { $request = $this->createRequest($method, $uri, $headers); @@ -69,10 +59,8 @@ public function getResponse($uri, array $headers, $method) /** * Send PSR HTTP request to your application. - * - * @return ResponseInterface */ - public function sendRequest(RequestInterface $request) + public function sendRequest(RequestInterface $request): ResponseInterface { // Close connections to make sure invalidation (PURGE/BAN) requests will // not interfere with content (GET) requests. @@ -83,12 +71,10 @@ public function sendRequest(RequestInterface $request) /** * Get HTTP client for your application. - * - * @return PhpHttpClient */ - private function getHttpClient() + private function getHttpClient(): PhpHttpClient { - if (null === $this->httpClient) { + if (!isset($this->httpClient)) { $this->httpClient = HttpClientDiscovery::find(); } @@ -96,17 +82,11 @@ private function getHttpClient() } /** - * Create a request. - * - * @param string $method - * @param string $uri - * @param array $headers - * - * @return RequestInterface + * @param array $headers * * @throws \Exception */ - private function createRequest($method, $uri, $headers) + private function createRequest(string $method, string $uri, array $headers): RequestInterface { $uri = $this->createUri($uri); if ('' === $uri->getHost()) { @@ -131,12 +111,8 @@ private function createRequest($method, $uri, $headers) /** * Create PSR-7 URI object from URI string. - * - * @param string $uriString - * - * @return UriInterface */ - private function createUri($uriString) + private function createUri(string $uriString): UriInterface { return UriFactoryDiscovery::find()->createUri($uriString); } diff --git a/src/Test/NginxTest.php b/src/Test/NginxTest.php index 64a3ea399..563dd6ec8 100644 --- a/src/Test/NginxTest.php +++ b/src/Test/NginxTest.php @@ -41,15 +41,8 @@ */ trait NginxTest { - /** - * @var Nginx - */ - protected $proxyClient; - - /** - * @var NginxProxy - */ - protected $proxy; + protected Nginx $proxyClient; + protected NginxProxy $proxy; protected function setUp(): void { @@ -68,7 +61,7 @@ protected function tearDown(): void * * @throws \Exception */ - protected function getConfigFile() + protected function getConfigFile(): string { // @codeCoverageIgnoreStart if (!defined('NGINX_FILE')) { @@ -85,20 +78,16 @@ protected function getConfigFile() /** * Defaults to "nginx". - * - * @return string */ - protected function getBinary() + protected function getBinary(): ?string { return defined('NGINX_BINARY') ? NGINX_BINARY : null; } /** * Defaults to 8088. - * - * @return int */ - protected function getCachingProxyPort() + protected function getCachingProxyPort(): int { return defined('NGINX_PORT') ? NGINX_PORT : 8088; } @@ -106,7 +95,7 @@ protected function getCachingProxyPort() /** * Get NGINX cache directory. */ - protected function getCacheDir() + protected function getCacheDir(): ?string { return defined('NGINX_CACHE_PATH') ? NGINX_CACHE_PATH : null; } @@ -114,11 +103,9 @@ protected function getCacheDir() /** * Get the hostname where your application can be reached. * - * @return string - * * @throws \Exception */ - protected function getHostName() + protected function getHostName(): string { // @codeCoverageIgnoreStart if (!defined('WEB_SERVER_HOSTNAME')) { @@ -131,12 +118,9 @@ protected function getHostName() return WEB_SERVER_HOSTNAME; } - /** - * @return NginxProxy - */ - protected function getProxy() + protected function getProxy(): NginxProxy { - if (null === $this->proxy) { + if (!isset($this->proxy)) { $this->proxy = new NginxProxy($this->getConfigFile()); $this->proxy->setPort($this->getCachingProxyPort()); @@ -156,12 +140,10 @@ protected function getProxy() * Get proxy client. * * @param string $purgeLocation Optional purgeLocation - * - * @return Nginx */ - protected function getProxyClient($purgeLocation = '') + protected function getProxyClient(string $purgeLocation = ''): Nginx { - if (null === $this->proxyClient) { + if (!isset($this->proxyClient)) { $httpDispatcher = new HttpDispatcher( ['http://127.0.0.1:'.$this->getCachingProxyPort()], $this->getHostName().':'.$this->getCachingProxyPort() diff --git a/src/Test/PHPUnit/AbstractCacheConstraintTrait.php b/src/Test/PHPUnit/AbstractCacheConstraintTrait.php index 0d6597213..db18ef45b 100644 --- a/src/Test/PHPUnit/AbstractCacheConstraintTrait.php +++ b/src/Test/PHPUnit/AbstractCacheConstraintTrait.php @@ -19,31 +19,21 @@ */ trait AbstractCacheConstraintTrait { - protected $header = 'X-Cache'; + protected string $header; - /** - * Constructor. - * - * @param string $header Cache debug header; defaults to X-Cache-Debug - */ - public function __construct($header = null) + public function __construct(string $header = 'X-Cache') { - if ($header) { - $this->header = $header; - } + $this->header = $header; if (version_compare(Version::id(), '8.0.0', '<')) { parent::__construct(); } } - /** - * @param ResponseInterface $other The guzzle response object - */ public function matches($other): bool { if (!$other instanceof ResponseInterface) { - throw new \RuntimeException(sprintf('Expected a GuzzleHttp\Psr7\Response but got %s', get_class($other))); + throw new \InvalidArgumentException('compare must compare with '.ResponseInterface::class.' got '.get_debug_type($other)); } if (!$other->hasHeader($this->header)) { $message = sprintf( @@ -70,7 +60,7 @@ public function matches($other): bool throw new \RuntimeException($message); } - return false !== strpos((string) $other->getHeaderLine($this->header), $this->getValue()); + return str_contains($other->getHeaderLine($this->header), $this->getValue()); } public function failureDescription($other): string diff --git a/src/Test/PHPUnit/IsCacheHitConstraint.php b/src/Test/PHPUnit/IsCacheHitConstraint.php index 13d369367..1c54b3906 100644 --- a/src/Test/PHPUnit/IsCacheHitConstraint.php +++ b/src/Test/PHPUnit/IsCacheHitConstraint.php @@ -18,7 +18,7 @@ public function toString(): string return 'is a cache hit'; } - public function getValue() + public function getValue(): string { return 'HIT'; } diff --git a/src/Test/PHPUnit/IsCacheMissConstraint.php b/src/Test/PHPUnit/IsCacheMissConstraint.php index 52e04b25f..60149125f 100644 --- a/src/Test/PHPUnit/IsCacheMissConstraint.php +++ b/src/Test/PHPUnit/IsCacheMissConstraint.php @@ -18,7 +18,7 @@ public function toString(): string return 'is a cache miss'; } - public function getValue() + public function getValue(): string { return 'MISS'; } diff --git a/src/Test/Proxy/AbstractProxy.php b/src/Test/Proxy/AbstractProxy.php index 174458df1..3b0296714 100644 --- a/src/Test/Proxy/AbstractProxy.php +++ b/src/Test/Proxy/AbstractProxy.php @@ -15,24 +15,22 @@ abstract class AbstractProxy implements ProxyInterface { - protected $port; + protected int $port; - protected $binary; + protected string $binary; - protected $configFile; + protected string $configFile; - protected $ip = '127.0.0.1'; + protected string $ip = '127.0.0.1'; /** * Wait for caching proxy to be started up and reachable. * - * @param string $ip - * @param int $port - * @param int $timeout Timeout in milliseconds + * @param int $timeout Timeout in milliseconds * * @throws \RuntimeException If proxy is not reachable within timeout */ - protected function waitFor($ip, $port, $timeout) + protected function waitFor(string $ip, int $port, int $timeout): void { if (!$this->wait( $timeout, @@ -53,13 +51,11 @@ function () use ($ip, $port) { /** * Wait for caching proxy to be started up and reachable. * - * @param string $ip - * @param int $port - * @param int $timeout Timeout in milliseconds + * @param int $timeout Timeout in milliseconds * * @throws \RuntimeException If proxy is not reachable within timeout */ - protected function waitUntil($ip, $port, $timeout) + protected function waitUntil(string $ip, int $port, int $timeout): void { if (!$this->wait( $timeout, @@ -77,7 +73,7 @@ function () use ($ip, $port) { } } - protected function wait($timeout, $callback) + protected function wait(int $timeout, callable $callback): bool { for ($i = 0; $i < $timeout; ++$i) { if ($callback()) { @@ -93,11 +89,9 @@ protected function wait($timeout, $callback) /** * Run a shell command. * - * @param string $command - * * @throws \RuntimeException If command execution fails */ - protected function runCommand($command, array $arguments) + protected function runCommand(string $command, array $arguments): void { $process = new Process(array_merge([$command], $arguments)); $process->run(); @@ -107,68 +101,40 @@ protected function runCommand($command, array $arguments) } } - /** - * @param int $port - */ - public function setPort($port) + public function setPort(int $port): void { $this->port = $port; } - /** - * @return int - */ - public function getPort() + public function getPort(): int { return $this->port; } - /** - * Set Varnish binary (defaults to varnishd). - * - * @param string $binary - */ - public function setBinary($binary) + public function setBinary(string $binary): void { $this->binary = $binary; } - /** - * Get Varnish binary. - * - * @return string - */ - public function getBinary() + public function getBinary(): string { return $this->binary; } - /** - * Set IP address (defaults to 127.0.0.1). - * - * @param string $ip - */ - public function setIp($ip) + public function setIp(string $ip): void { $this->ip = $ip; } - /** - * Get IP address. - * - * @return string - */ - public function getIp() + public function getIp(): string { return $this->ip; } /** - * @param string $configFile - * * @throws \InvalidArgumentException */ - public function setConfigFile($configFile) + public function setConfigFile(string $configFile): void { if (!file_exists($configFile)) { throw new \InvalidArgumentException('Cannot find config file: '.$configFile); @@ -177,10 +143,7 @@ public function setConfigFile($configFile) $this->configFile = $configFile; } - /** - * @return string - */ - public function getConfigFile() + public function getConfigFile(): string { return $this->configFile; } diff --git a/src/Test/Proxy/NginxProxy.php b/src/Test/Proxy/NginxProxy.php index 727094cbf..d0d104757 100644 --- a/src/Test/Proxy/NginxProxy.php +++ b/src/Test/Proxy/NginxProxy.php @@ -13,28 +13,23 @@ class NginxProxy extends AbstractProxy { - protected $binary = 'nginx'; + protected string $binary = 'nginx'; - protected $configFile; + protected string $configFile; - protected $port = 8080; + protected int $port = 8080; - protected $pid = '/tmp/foshttpcache-nginx.pid'; + protected string $pid = '/tmp/foshttpcache-nginx.pid'; - protected $cacheDir; + protected string $cacheDir; - /** - * Constructor. - * - * @param string $configFile Path to NGINX configuration file - */ - public function __construct($configFile) + public function __construct(string $configFile) { $this->setConfigFile($configFile); $this->setCacheDir(sys_get_temp_dir().DIRECTORY_SEPARATOR.'foshttpcache-nginx'); } - public function start() + public function start(): void { $this->runCommand( $this->getBinary(), @@ -47,31 +42,25 @@ public function start() $this->waitFor($this->getIp(), $this->getPort(), 2000); } - public function stop() + public function stop(): void { if (file_exists($this->pid)) { $this->runCommand('kill', [trim(file_get_contents($this->pid))]); } } - public function clear() + public function clear(): void { $this->runCommand('rm', ['-rf', $this->getCacheDir()]); $this->start(); } - /** - * @param string $cacheDir - */ - public function setCacheDir($cacheDir) + public function setCacheDir(string $cacheDir): void { $this->cacheDir = $cacheDir; } - /** - * @return string - */ - public function getCacheDir() + public function getCacheDir(): string { return $this->cacheDir; } diff --git a/src/Test/Proxy/ProxyInterface.php b/src/Test/Proxy/ProxyInterface.php index 52e35d6a2..3122e7cc2 100644 --- a/src/Test/Proxy/ProxyInterface.php +++ b/src/Test/Proxy/ProxyInterface.php @@ -19,15 +19,15 @@ interface ProxyInterface /** * Start the proxy server. */ - public function start(); + public function start(): void; /** * Stop the proxy server. */ - public function stop(); + public function stop(): void; /** * Clear all cached content from the proxy server. */ - public function clear(); + public function clear(): void; } diff --git a/src/Test/Proxy/SymfonyProxy.php b/src/Test/Proxy/SymfonyProxy.php index 87aacd3f4..adee4db4c 100644 --- a/src/Test/Proxy/SymfonyProxy.php +++ b/src/Test/Proxy/SymfonyProxy.php @@ -19,12 +19,7 @@ */ class SymfonyProxy implements ProxyInterface { - /** - * Get Symfony cache directory. - * - * @return string - */ - public function getCacheDir() + public function getCacheDir(): string { $path = defined('SYMFONY_CACHE_DIR') ? SYMFONY_CACHE_DIR : sys_get_temp_dir().'/foshttpcache-symfony'; if (!$path || '/' === $path) { @@ -34,26 +29,17 @@ public function getCacheDir() return $path; } - /** - * Start the proxy server. - */ - public function start() + public function start(): void { $this->clear(); } - /** - * Stop the proxy server. - */ - public function stop() + public function stop(): void { // nothing to do } - /** - * Clear all cached content from the proxy server. - */ - public function clear() + public function clear(): void { $path = realpath($this->getCacheDir()); @@ -63,7 +49,7 @@ public function clear() } $path = $this->getCacheDir(); - if (0 === stripos(PHP_OS, 'WIN')) { + if (0 === stripos(PHP_OS_FAMILY, 'WIN')) { // @codeCoverageIgnoreStart system('DEL /S '.$path); } else { diff --git a/src/Test/Proxy/VarnishProxy.php b/src/Test/Proxy/VarnishProxy.php index e104c2437..ef248b0d0 100644 --- a/src/Test/Proxy/VarnishProxy.php +++ b/src/Test/Proxy/VarnishProxy.php @@ -13,34 +13,32 @@ class VarnishProxy extends AbstractProxy { - protected $binary = 'varnishd'; + protected string $binary = 'varnishd'; - protected $port = 6181; + protected int $port = 6181; - protected $managementPort = 6182; + protected int $managementPort = 6182; - protected $pid = '/tmp/foshttpcache-varnish.pid'; + protected string $pid = '/tmp/foshttpcache-varnish.pid'; - protected $configFile; + protected string $configFile; - protected $configDir; + protected ?string $configDir = null; - protected $cacheDir; + protected string $cacheDir; - protected $allowInlineC = false; + protected bool $allowInlineC = false; /** - * Constructor. - * * @param string $configFile Path to VCL file */ - public function __construct($configFile) + public function __construct(string $configFile) { $this->setConfigFile($configFile); $this->setCacheDir(sys_get_temp_dir().DIRECTORY_SEPARATOR.'foshttpcache-varnish'); } - public function start() + public function start(): void { $vclPath = ((int) $this->getVarnishVersion()) >= 5 ? 'vcl_path' : 'vcl_dir'; @@ -63,7 +61,7 @@ public function start() $this->waitFor($this->ip, $this->getPort(), 5000); } - public function stop() + public function stop(): void { if (file_exists($this->pid)) { try { @@ -76,26 +74,20 @@ public function stop() } } - public function clear() + public function clear(): void { $this->stop(); $this->start(); } - /** - * @param string $configDir - */ - public function setConfigDir($configDir) + public function setConfigDir(string $configDir): void { $this->configDir = $configDir; } - /** - * @return string - */ - public function getConfigDir() + public function getConfigDir(): string { - if (null === $this->configDir && null !== $this->configFile) { + if (null === $this->configDir) { return dirname(realpath($this->getConfigFile())); } @@ -104,70 +96,38 @@ public function getConfigDir() /** * Set Varnish management port (defaults to 6182). - * - * @param int $managementPort */ - public function setManagementPort($managementPort) + public function setManagementPort(int $managementPort): void { $this->managementPort = $managementPort; } - /** - * Get Varnish management port. - * - * @return int - */ - public function getManagementPort() + public function getManagementPort(): int { return $this->managementPort; } - /** - * Set Varnish cache directory. - * - * @param string $cacheDir - */ - public function setCacheDir($cacheDir) + public function setCacheDir(string $cacheDir): void { $this->cacheDir = $cacheDir; } - /** - * Get Varnish cache directory. - * - * @return string - */ - public function getCacheDir() + public function getCacheDir(): string { return $this->cacheDir; } - /** - * Whether the inline C flag should be set. - * - * @return bool - */ - public function getAllowInlineC() + public function getAllowInlineC(): bool { return $this->allowInlineC; } - /** - * Set whether the inline c flag should be on or off. - * - * @param bool $allowInlineC True for on, false for off - */ - public function setAllowInlineC($allowInlineC) + public function setAllowInlineC(bool $allowInlineC): void { $this->allowInlineC = (bool) $allowInlineC; } - /** - * Defaults to 4. - * - * @return int - */ - private function getVarnishVersion() + private function getVarnishVersion(): string { return getenv('VARNISH_VERSION') ?: '4.0'; } diff --git a/src/Test/SymfonyTest.php b/src/Test/SymfonyTest.php index e7cd63bd0..eb65e3bac 100644 --- a/src/Test/SymfonyTest.php +++ b/src/Test/SymfonyTest.php @@ -35,15 +35,8 @@ */ trait SymfonyTest { - /** - * @var Symfony - */ - protected $proxyClient; - - /** - * @var SymfonyProxy - */ - protected $proxy; + protected Symfony $proxyClient; + protected SymfonyProxy $proxy; /** * Clear Symfony HttpCache. @@ -58,11 +51,9 @@ protected function setUp(): void /** * Get server port. * - * @return int - * * @throws \Exception */ - protected function getCachingProxyPort() + protected function getCachingProxyPort(): int { // @codeCoverageIgnoreStart if (!defined('WEB_SERVER_PORT')) { @@ -76,11 +67,9 @@ protected function getCachingProxyPort() /** * Get the hostname where your application can be reached. * - * @return string - * * @throws \Exception */ - protected function getHostName() + protected function getHostName(): string { // @codeCoverageIgnoreStart if (!defined('WEB_SERVER_HOSTNAME')) { @@ -93,12 +82,9 @@ protected function getHostName() return WEB_SERVER_HOSTNAME; } - /** - * @return SymfonyProxy - */ - protected function getProxy() + protected function getProxy(): SymfonyProxy { - if (null === $this->proxy) { + if (!isset($this->proxy)) { $this->proxy = new SymfonyProxy(); } @@ -111,12 +97,10 @@ protected function getProxy() * We use a non-default method for PURGE because the built-in PHP webserver * does not allow arbitrary HTTP methods. * https://github.com/php/php-src/blob/PHP-5.4.1/sapi/cli/php_http_parser.c#L78-L102 - * - * @return Symfony */ - protected function getProxyClient() + protected function getProxyClient(): Symfony { - if (null === $this->proxyClient) { + if (!isset($this->proxyClient)) { $httpDispatcher = new HttpDispatcher( ['http://127.0.0.1:'.$this->getCachingProxyPort()], $this->getHostName().':'.$this->getCachingProxyPort() diff --git a/src/Test/VarnishTest.php b/src/Test/VarnishTest.php index 6dc5f7594..409378991 100644 --- a/src/Test/VarnishTest.php +++ b/src/Test/VarnishTest.php @@ -46,15 +46,9 @@ */ trait VarnishTest { - /** - * @var VarnishProxy - */ - protected $proxy; + protected VarnishProxy $proxy; - /** - * @var Varnish - */ - protected $proxyClient; + protected Varnish $proxyClient; /** * Start Varnish and discard any cached content. @@ -79,7 +73,7 @@ protected function tearDown(): void * * @throws \Exception */ - protected function getConfigFile() + protected function getConfigFile(): string { // @codeCoverageIgnoreStart if (!defined('VARNISH_FILE')) { @@ -93,58 +87,48 @@ protected function getConfigFile() } /** - * Get Varnish binary. - * - * @return string + * Get path to Varnish binary. */ - protected function getBinary() + protected function getBinary(): ?string { return defined('VARNISH_BINARY') ? VARNISH_BINARY : null; } /** * Get Varnish port. - * - * @return int */ - protected function getCachingProxyPort() + protected function getCachingProxyPort(): int { return defined('VARNISH_PORT') ? VARNISH_PORT : 6181; } /** * Get Varnish management port. - * - * @return int */ - protected function getVarnishMgmtPort() + protected function getVarnishMgmtPort(): ?int { return defined('VARNISH_MGMT_PORT') ? VARNISH_MGMT_PORT : null; } /** * Get Varnish cache directory. - * - * @return string */ - protected function getCacheDir() + protected function getCacheDir(): ?string { return defined('VARNISH_CACHE_DIR') ? VARNISH_CACHE_DIR : null; } /** * Defaults to 4. - * - * @return int */ - protected function getVarnishVersion() + protected function getVarnishVersion(): string { return getenv('VARNISH_VERSION') ?: '4.0'; } - protected function getProxy() + protected function getProxy(): VarnishProxy { - if (null === $this->proxy) { + if (!isset($this->proxy)) { $this->proxy = new VarnishProxy($this->getConfigFile()); if ($this->getBinary()) { $this->proxy->setBinary($this->getBinary()); @@ -166,14 +150,9 @@ protected function getProxy() return $this->proxy; } - /** - * Get Varnish proxy client. - * - * @return Varnish - */ - protected function getProxyClient() + protected function getProxyClient(): Varnish { - if (null === $this->proxyClient) { + if (!isset($this->proxyClient)) { $httpDispatcher = new HttpDispatcher( ['http://127.0.0.1:'.$this->getCachingProxyPort()], $this->getHostName().':'.$this->getCachingProxyPort() @@ -197,11 +176,9 @@ protected function getProxyClient() /** * Get the hostname where your application can be reached. * - * @return string - * * @throws \Exception */ - protected function getHostName() + protected function getHostName(): string { // @codeCoverageIgnoreStart if (!defined('WEB_SERVER_HOSTNAME')) { diff --git a/src/UserContext/AnonymousRequestMatcher.php b/src/UserContext/AnonymousRequestMatcher.php index 6eaffdff2..cc2e05995 100644 --- a/src/UserContext/AnonymousRequestMatcher.php +++ b/src/UserContext/AnonymousRequestMatcher.php @@ -20,10 +20,7 @@ */ class AnonymousRequestMatcher implements RequestMatcherInterface { - /** - * @var array - */ - private $options; + private array $options; /** * @param array $options Configuration for the matcher. All options are required because this matcher is usually @@ -56,7 +53,7 @@ public function matches(Request $request): bool if ($this->options['session_name_prefix']) { foreach ($request->cookies as $name => $value) { - if (0 === strpos($name, $this->options['session_name_prefix'])) { + if (str_starts_with($name, $this->options['session_name_prefix'])) { return false; } } diff --git a/src/UserContext/DefaultHashGenerator.php b/src/UserContext/DefaultHashGenerator.php index d9ba86133..edf013d35 100644 --- a/src/UserContext/DefaultHashGenerator.php +++ b/src/UserContext/DefaultHashGenerator.php @@ -21,7 +21,7 @@ class DefaultHashGenerator implements HashGenerator /** * @var ContextProvider[] */ - private $providers = []; + private array $providers = []; /** * Constructor. @@ -43,10 +43,8 @@ public function __construct(array $providers) /** * Collect UserContext parameters and generate a hash from that. - * - * @return string The hash generated */ - public function generateHash() + public function generateHash(): string { $userContext = new UserContext(); @@ -67,7 +65,7 @@ public function generateHash() * * @param ContextProvider $provider A context provider to be called to get context information about the current request */ - private function registerProvider(ContextProvider $provider) + private function registerProvider(ContextProvider $provider): void { $this->providers[] = $provider; } diff --git a/src/UserContext/HashGenerator.php b/src/UserContext/HashGenerator.php index 42c987074..de17235fc 100644 --- a/src/UserContext/HashGenerator.php +++ b/src/UserContext/HashGenerator.php @@ -12,12 +12,9 @@ namespace FOS\HttpCache\UserContext; /** - * Generate a hash. + * Generate a hash for distinguishing user contexts. */ interface HashGenerator { - /** - * @return string The hash generated - */ - public function generateHash(); + public function generateHash(): string; } diff --git a/src/UserContext/UserContext.php b/src/UserContext/UserContext.php index 0de3309aa..4b942e4c1 100644 --- a/src/UserContext/UserContext.php +++ b/src/UserContext/UserContext.php @@ -20,15 +20,17 @@ */ class UserContext implements \IteratorAggregate { - private $parameters = []; + /** + * @var array + */ + private array $parameters = []; /** * Set a parameter for this context. * - * @param string $key Parameter identifier - * @param mixed $value Parameter value (it should be serializable) + * @param mixed $value Parameter value (it should be serializable) */ - public function addParameter($key, $value) + public function addParameter(string $key, $value): void { $this->parameters[$key] = $value; } @@ -36,19 +38,15 @@ public function addParameter($key, $value) /** * Set all the parameters of this context. */ - public function setParameters(array $parameters) + public function setParameters(array $parameters): void { $this->parameters = $parameters; } /** * Determine whether a parameter exists. - * - * @param string $key - * - * @return bool */ - public function hasParameter($key) + public function hasParameter(string $key): bool { return array_key_exists($key, $this->parameters); } @@ -56,9 +54,9 @@ public function hasParameter($key) /** * Return all parameters of this context. * - * @return array + * @return array */ - public function getParameters() + public function getParameters(): array { return $this->parameters; } diff --git a/tests/Functional/Varnish/UserContextFailureTest.php b/tests/Functional/Varnish/UserContextFailureTest.php index 977d3e262..0108be76f 100644 --- a/tests/Functional/Varnish/UserContextFailureTest.php +++ b/tests/Functional/Varnish/UserContextFailureTest.php @@ -93,13 +93,11 @@ public function testHashRequestFailure(): void $this->assertEquals(503, $response->getStatusCode()); } - protected function getConfigFile(): ?string + protected function getConfigFile(): string { - switch ((int) $this->getVarnishVersion()) { - case 3: - return sprintf(dirname(__DIR__).'/Fixtures/varnish-3/user_context_%s.vcl', $this->mode); - default: - return sprintf(dirname(__DIR__).'/Fixtures/varnish/user_context_%s.vcl', $this->mode); - } + return match ((int) $this->getVarnishVersion()) { + 3 => sprintf(dirname(__DIR__).'/Fixtures/varnish-3/user_context_%s.vcl', $this->mode), + default => sprintf(dirname(__DIR__).'/Fixtures/varnish/user_context_%s.vcl', $this->mode), + }; } } diff --git a/tests/Functional/Varnish/UserContextNocacheTest.php b/tests/Functional/Varnish/UserContextNocacheTest.php index e93313856..4f7c613d5 100644 --- a/tests/Functional/Varnish/UserContextNocacheTest.php +++ b/tests/Functional/Varnish/UserContextNocacheTest.php @@ -17,14 +17,12 @@ */ class UserContextNocacheTest extends UserContextTestCase { - protected function getConfigFile(): ?string + protected function getConfigFile(): string { - switch ((int) $this->getVarnishVersion()) { - case 3: - return dirname(__DIR__).'/Fixtures/varnish-3/user_context_nocache.vcl'; - default: - return dirname(__DIR__).'/Fixtures/varnish/user_context_nocache.vcl'; - } + return match ((int) $this->getVarnishVersion()) { + 3 => dirname(__DIR__).'/Fixtures/varnish-3/user_context_nocache.vcl', + default => dirname(__DIR__).'/Fixtures/varnish/user_context_nocache.vcl', + }; } protected function assertContextCache(string $hashCache): void diff --git a/tests/Unit/ProxyClient/HttpDispatcherTest.php b/tests/Unit/ProxyClient/HttpDispatcherTest.php index 198082bfe..ce26f96c5 100644 --- a/tests/Unit/ProxyClient/HttpDispatcherTest.php +++ b/tests/Unit/ProxyClient/HttpDispatcherTest.php @@ -49,17 +49,6 @@ protected function setUp(): void $this->uriFactory = UriFactoryDiscovery::find(); } - public function testInstantiateWithNonUri(): void - { - $this->expectException(\InvalidArgumentException::class); - $this->expectExceptionMessage('URI parameter must be a string, object given'); - - new HttpDispatcher( - ['127.0.0.1:123'], - $this - ); - } - /** * @dataProvider exceptionProvider * diff --git a/tests/Unit/ResponseTaggerTest.php b/tests/Unit/ResponseTaggerTest.php index 59c83130e..d87537f24 100644 --- a/tests/Unit/ResponseTaggerTest.php +++ b/tests/Unit/ResponseTaggerTest.php @@ -23,13 +23,13 @@ class ResponseTaggerTest extends TestCase { use MockeryPHPUnitIntegration; - public function testDefaultFormatter() + public function testDefaultFormatter(): void { $tagger = new ResponseTagger(); $this->assertEquals('X-Cache-Tags', $tagger->getTagsHeaderName()); } - public function testGetTagsHeaderValue() + public function testGetTagsHeaderValue(): void { $headerFormatter = \Mockery::mock(TagHeaderFormatter::class) ->shouldReceive('getTagsHeaderValue') @@ -46,7 +46,7 @@ public function testGetTagsHeaderValue() $this->assertTrue($tagger->hasTags()); // getting the header does not clear the tags } - public function testTagResponseReplace() + public function testTagResponseReplace(): void { $headerFormatter = \Mockery::mock(TagHeaderFormatter::class) ->shouldReceive('getTagsHeaderValue') @@ -63,6 +63,7 @@ public function testTagResponseReplace() $response = \Mockery::mock(ResponseInterface::class) ->shouldReceive('withHeader') ->with('FOS-Tags', 'tag-1,tag-2') + ->andReturn($this->createMock(ResponseInterface::class)) ->getMock(); $tagger->addTags(['tag-1', 'tag-2']); @@ -70,7 +71,7 @@ public function testTagResponseReplace() $this->assertFalse($tagger->hasTags()); } - public function testTagResponseAdd() + public function testTagResponseAdd(): void { $headerFormatter = \Mockery::mock(TagHeaderFormatter::class) ->shouldReceive('getTagsHeaderValue') @@ -87,6 +88,7 @@ public function testTagResponseAdd() $response = \Mockery::mock(ResponseInterface::class) ->shouldReceive('withAddedHeader') ->with('FOS-Tags', 'tag-1,tag-2') + ->andReturn($this->createMock(ResponseInterface::class)) ->getMock(); $tagger->addTags(['tag-1', 'tag-2']); @@ -94,7 +96,7 @@ public function testTagResponseAdd() $this->assertFalse($tagger->hasTags()); } - public function testTagResponseNoTags() + public function testTagResponseNoTags(): void { /** @var TagHeaderFormatter $headerFormatter */ $headerFormatter = \Mockery::mock(TagHeaderFormatter::class) @@ -111,7 +113,7 @@ public function testTagResponseNoTags() $tagger->tagResponse($response, true); } - public function testStrictEmptyTag() + public function testStrictEmptyTag(): void { $headerFormatter = new CommaSeparatedTagHeaderFormatter('FOS-Tags'); @@ -121,7 +123,7 @@ public function testStrictEmptyTag() $tagHandler->addTags(['post-1', false]); } - public function testNonStrictEmptyTag() + public function testNonStrictEmptyTag(): void { $headerFormatter = \Mockery::mock(TagHeaderFormatter::class) ->shouldReceive('getTagsHeaderValue') @@ -136,7 +138,7 @@ public function testNonStrictEmptyTag() $this->assertEquals('post-1', $tagHandler->getTagsHeaderValue()); } - public function testUniqueTags() + public function testUniqueTags(): void { $headerFormatter = new CommaSeparatedTagHeaderFormatter('FOS-Tags'); @@ -148,7 +150,7 @@ public function testUniqueTags() $this->assertEquals('post-1,post-2,post-3', $tagHandler->getTagsHeaderValue()); } - public function testClear() + public function testClear(): void { $tagger = new ResponseTagger(); $this->assertFalse($tagger->hasTags()); diff --git a/tests/Unit/Test/Proxy/AbstractProxyTest.php b/tests/Unit/Test/Proxy/AbstractProxyTest.php index 083ac61d4..1366f91ef 100644 --- a/tests/Unit/Test/Proxy/AbstractProxyTest.php +++ b/tests/Unit/Test/Proxy/AbstractProxyTest.php @@ -16,7 +16,7 @@ class AbstractProxyTest extends TestCase { - public function testWaitTimeout() + public function testWaitTimeout(): void { $proxy = new ProxyPartial(); $this->expectException(\RuntimeException::class); @@ -24,7 +24,7 @@ public function testWaitTimeout() $proxy->start(); } - public function testRunFailure() + public function testRunFailure(): void { $proxy = new ProxyPartial(); $this->expectException(\RuntimeException::class); @@ -35,20 +35,20 @@ public function testRunFailure() class ProxyPartial extends AbstractProxy { - public function start() + public function start(): void { $this->waitUntil('localhost', 6666, 0); } - public function stop() + public function stop(): void { } - public function clear() + public function clear(): void { } - public function run() + public function run(): void { $this->runCommand('/path/to/not/exists', []); } diff --git a/tests/Unit/Test/Proxy/VarnishProxyTest.php b/tests/Unit/Test/Proxy/VarnishProxyTest.php index 2a1e85686..21467a1ac 100644 --- a/tests/Unit/Test/Proxy/VarnishProxyTest.php +++ b/tests/Unit/Test/Proxy/VarnishProxyTest.php @@ -16,7 +16,7 @@ class VarnishProxyTest extends TestCase { - public function testInvalidConfigFileThrowsException() + public function testInvalidConfigFileThrowsException(): void { $this->expectException(\InvalidArgumentException::class); $this->expectExceptionMessage('Cannot find config file: nope.vcl'); @@ -24,7 +24,7 @@ public function testInvalidConfigFileThrowsException() new VarnishProxy('nope.vcl'); } - public function allowInlineFlagProvider() + public function allowInlineFlagProvider(): array { return [[true], [false]]; } @@ -32,7 +32,7 @@ public function allowInlineFlagProvider() /** * @dataProvider allowInlineFlagProvider */ - public function testStart($inlineC) + public function testStart(bool $inlineC): void { $proxy = new VarnishProxyMock('config.vcl'); $proxy->setBinary('/usr/sbin/varnishd'); @@ -75,24 +75,24 @@ public function testWaitThrowsException() class VarnishProxyMock extends VarnishProxy { - public $command; + public string $command; - public $arguments; + public array $arguments; - public $wait = true; + public bool $wait = true; - public function setConfigFile($configFile) + public function setConfigFile(string $configFile): void { $this->configFile = $configFile; } - protected function runCommand($command, array $arguments) + protected function runCommand(string $command, array $arguments): void { $this->command = $command; $this->arguments = $arguments; } - protected function wait($timeout, $callback) + protected function wait($timeout, $callback): bool { return $this->wait; }