From 03aaaecf3faaad75e33a2d046a33410e27ab2cef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Orlando=20Th=C3=B6ny?= Date: Tue, 18 Nov 2025 15:22:54 +0100 Subject: [PATCH] refactor: add types, misc minor refactoring/cleanup --- Attribute/RateLimit.php | 39 ++++++--- DependencyInjection/Configuration.php | 8 +- EventListener/BaseListener.php | 15 +--- EventListener/HeaderModificationListener.php | 11 +-- EventListener/RateLimitAnnotationListener.php | 29 +++---- Service/Storage/DoctrineCache.php | 2 +- Service/Storage/Memcache.php | 2 +- Service/Storage/PhpRedisCluster.php | 2 - Service/Storage/PsrCache.php | 2 +- Service/Storage/SimpleCache.php | 2 +- Tests/Attribute/RateLimitTest.php | 4 +- .../DependencyInjection/ConfigurationTest.php | 13 +-- .../NoxlogicRateLimitExtensionTest.php | 49 ++++++------ Tests/EventListener/MockStorage.php | 28 ++----- Tests/Service/Storage/DoctrineCacheTest.php | 37 ++++----- Tests/Service/Storage/PsrCacheTest.php | 42 ++++++---- Tests/Service/Storage/RedisTest.php | 27 ++++--- Tests/Service/Storage/SimpleCacheTest.php | 22 ++--- phpstan-baseline.neon | 80 +------------------ phpstan.dist.neon | 2 + phpunit.xml.dist | 53 ++++++------ 21 files changed, 191 insertions(+), 278 deletions(-) diff --git a/Attribute/RateLimit.php b/Attribute/RateLimit.php index a4cf08a..b2f9775 100644 --- a/Attribute/RateLimit.php +++ b/Attribute/RateLimit.php @@ -2,24 +2,25 @@ namespace Noxlogic\RateLimitBundle\Attribute; +use Symfony\Component\HttpFoundation\Request; + #[\Attribute(\Attribute::IS_REPEATABLE |\Attribute::TARGET_CLASS | \Attribute::TARGET_METHOD)] final class RateLimit { - /** - * @var array HTTP Methods protected by this attribute. Defaults to all method - */ - public array $methods = []; - public function __construct( - $methods = [], + /** + * @var array $methods HTTP Methods protected by this attribute. Defaults to all methods + * Passing strings is allowed for backward-compatibility but deprecated. Pass an array instead + */ + public array|string $methods = [], /** - * @var int Number of calls per period + * @var int<-1, max> Number of calls per period */ public int $limit = -1, /** - * @var int Number of seconds of the time period in which the calls can be made + * @var positive-int Number of seconds of the time period in which the calls can be made */ public int $period = 3600, @@ -31,36 +32,52 @@ public function __construct( // @RateLimit annotation used to support single method passed as string, keep that for retrocompatibility if (!is_array($methods)) { $this->methods = [$methods]; - } else { - $this->methods = $methods; } } + /** + * @return int<-1, max> + */ public function getLimit(): int { return $this->limit; } + /** + * @param int<-1, max> $limit + */ public function setLimit(int $limit): void { $this->limit = $limit; } + /** + * @return array + */ public function getMethods(): array { return $this->methods; } - public function setMethods($methods): void + /** + * @param array $methods Passing strings is allowed for backward-compatibility but deprecated. Pass an array instead + */ + public function setMethods(array|string $methods): void { $this->methods = (array) $methods; } + /** + * @return positive-int + */ public function getPeriod(): int { return $this->period; } + /** + * @param positive-int $period + */ public function setPeriod(int $period): void { $this->period = $period; diff --git a/DependencyInjection/Configuration.php b/DependencyInjection/Configuration.php index b16a16e..fd6bda3 100755 --- a/DependencyInjection/Configuration.php +++ b/DependencyInjection/Configuration.php @@ -2,13 +2,13 @@ namespace Noxlogic\RateLimitBundle\DependencyInjection; +use Symfony\Component\Config\Definition\Builder\ArrayNodeDefinition; use Symfony\Component\Config\Definition\Builder\TreeBuilder; use Symfony\Component\Config\Definition\ConfigurationInterface; use Symfony\Component\Config\Definition\Exception\InvalidConfigurationException; /** * This is the class that validates and merges configuration from your app/config files - * */ class Configuration implements ConfigurationInterface { @@ -22,7 +22,11 @@ public function getConfigTreeBuilder(): TreeBuilder $treeBuilder = new TreeBuilder('noxlogic_rate_limit'); $rootNode = $treeBuilder->getRootNode(); - $rootNode // @phpstan-ignore method.notFound + if (!$rootNode instanceof ArrayNodeDefinition) { + throw new \InvalidArgumentException('The "noxlogic_rate_limit" config root node must be an array'); + } + + $rootNode // @phpstan-ignore-line ->canBeDisabled() ->children() ->enumNode('storage_engine') diff --git a/EventListener/BaseListener.php b/EventListener/BaseListener.php index 272fe16..b961859 100644 --- a/EventListener/BaseListener.php +++ b/EventListener/BaseListener.php @@ -10,22 +10,13 @@ abstract class BaseListener */ protected $parameters; - /** - * @param $name - * @param $value - */ - public function setParameter($name, $value) + public function setParameter(string $name, mixed $value): void { $this->parameters[$name] = $value; } - /** - * @param $name - * @param mixed $default - * @return mixed - */ - public function getParameter($name, $default = null) + public function getParameter(string $name, mixed $default = null): mixed { - return isset($this->parameters[$name]) ? $this->parameters[$name] : $default; + return $this->parameters[$name] ?? $default; } } diff --git a/EventListener/HeaderModificationListener.php b/EventListener/HeaderModificationListener.php index 11f3523..997e92e 100644 --- a/EventListener/HeaderModificationListener.php +++ b/EventListener/HeaderModificationListener.php @@ -7,19 +7,12 @@ class HeaderModificationListener extends BaseListener { - - /** - * @param array $defaultParameters - */ - public function __construct($defaultParameters = array()) + public function __construct(array $defaultParameters = []) { $this->parameters = $defaultParameters; } - /** - * @param ResponseEvent $event - */ - public function onKernelResponse($event) + public function onKernelResponse(ResponseEvent $event): void { $request = $event->getRequest(); diff --git a/EventListener/RateLimitAnnotationListener.php b/EventListener/RateLimitAnnotationListener.php index 7ea8440..a7f20c6 100644 --- a/EventListener/RateLimitAnnotationListener.php +++ b/EventListener/RateLimitAnnotationListener.php @@ -17,26 +17,17 @@ class RateLimitAnnotationListener extends BaseListener { - protected EventDispatcherInterface $eventDispatcher; - - protected RateLimitService $rateLimitService; - - protected PathLimitProcessor $pathLimitProcessor; - public function __construct( - EventDispatcherInterface $eventDispatcher, - RateLimitService $rateLimitService, - PathLimitProcessor $pathLimitProcessor + protected EventDispatcherInterface $eventDispatcher, + protected RateLimitService $rateLimitService, + protected PathLimitProcessor $pathLimitProcessor ) { - $this->eventDispatcher = $eventDispatcher; - $this->rateLimitService = $rateLimitService; - $this->pathLimitProcessor = $pathLimitProcessor; } public function onKernelController(ControllerEvent $event): void { // Skip if the bundle isn't enabled (for instance in test environment) - if( ! $this->getParameter('enabled', true)) { + if(! $this->getParameter('enabled', true)) { return; } @@ -120,10 +111,8 @@ public function onKernelController(ControllerEvent $event): void }); $event->stopPropagation(); } - } - /** * @param RateLimit[] $rateLimits */ @@ -134,19 +123,19 @@ protected function findBestMethodMatch(Request $request, array $rateLimits): ?Ra return $this->pathLimitProcessor->getRateLimit($request); } - $best_match = null; + $bestMatch = null; foreach ($rateLimits as $rateLimit) { if (in_array($request->getMethod(), $rateLimit->getMethods(), true)) { - $best_match = $rateLimit; + $bestMatch = $rateLimit; } // Only match "default" annotation when we don't have a best match - if ($best_match === null && count($rateLimit->methods) === 0) { - $best_match = $rateLimit; + if ($bestMatch === null && count($rateLimit->methods) === 0) { + $bestMatch = $rateLimit; } } - return $best_match; + return $bestMatch; } /** @param RateLimit[] $rateLimits */ diff --git a/Service/Storage/DoctrineCache.php b/Service/Storage/DoctrineCache.php index 3adf5f3..db20915 100644 --- a/Service/Storage/DoctrineCache.php +++ b/Service/Storage/DoctrineCache.php @@ -62,7 +62,7 @@ public function resetRate($key) return true; } - private function createRateInfo(array $info) + private function createRateInfo(array $info): RateLimitInfo { $rateLimitInfo = new RateLimitInfo(); $rateLimitInfo->setLimit($info['limit']); diff --git a/Service/Storage/Memcache.php b/Service/Storage/Memcache.php index 707fd30..c41766f 100644 --- a/Service/Storage/Memcache.php +++ b/Service/Storage/Memcache.php @@ -64,7 +64,7 @@ public function resetRate($key) return true; } - private function createRateInfo(array $info) + private function createRateInfo(array $info): RateLimitInfo { $rateLimitInfo = new RateLimitInfo(); $rateLimitInfo->setLimit($info['limit']); diff --git a/Service/Storage/PhpRedisCluster.php b/Service/Storage/PhpRedisCluster.php index bda4bc6..5af88c4 100755 --- a/Service/Storage/PhpRedisCluster.php +++ b/Service/Storage/PhpRedisCluster.php @@ -1,9 +1,7 @@ setLimit($info['limit']); diff --git a/Service/Storage/SimpleCache.php b/Service/Storage/SimpleCache.php index 7821633..c3840d5 100644 --- a/Service/Storage/SimpleCache.php +++ b/Service/Storage/SimpleCache.php @@ -61,7 +61,7 @@ public function resetRate($key) return true; } - private function createRateInfo(array $info) + private function createRateInfo(array $info): RateLimitInfo { $rateLimitInfo = new RateLimitInfo(); $rateLimitInfo->setLimit($info['limit']); diff --git a/Tests/Attribute/RateLimitTest.php b/Tests/Attribute/RateLimitTest.php index ddda5fd..4597e4f 100644 --- a/Tests/Attribute/RateLimitTest.php +++ b/Tests/Attribute/RateLimitTest.php @@ -43,7 +43,7 @@ public function testConstructionWithMethods(): void 1234, 1000 ); - $this->assertCount(2, $attribute->methods); + self::assertCount(2, $attribute->methods); } public function testConstructWithStringAsMethods(): void @@ -53,6 +53,6 @@ public function testConstructWithStringAsMethods(): void 1234, 1000 ); - $this->assertEquals(['POST'], $attribute->methods); + self::assertSame(['POST'], $attribute->methods); } } diff --git a/Tests/DependencyInjection/ConfigurationTest.php b/Tests/DependencyInjection/ConfigurationTest.php index b881ce4..fb36139 100644 --- a/Tests/DependencyInjection/ConfigurationTest.php +++ b/Tests/DependencyInjection/ConfigurationTest.php @@ -25,9 +25,9 @@ private function getConfigs(array $configArray): array public function testUnconfiguredConfiguration(): void { - $configuration = $this->getConfigs(array()); + $configuration = $this->getConfigs([]); - $this->assertSame(array( + $this->assertSame([ 'enabled' => true, 'storage_engine' => 'redis', 'redis_client' => 'default_client', @@ -43,14 +43,14 @@ public function testUnconfiguredConfiguration(): void 'rate_response_exception' => null, 'rate_response_message' => 'You exceeded the rate limit', 'display_headers' => true, - 'headers' => array( + 'headers' => [ 'limit' => 'X-RateLimit-Limit', 'remaining' => 'X-RateLimit-Remaining', 'reset' => 'X-RateLimit-Reset', - ), - 'path_limits' => array(), + ], + 'path_limits' => [], 'fos_oauth_key_listener' => true - ), $configuration); + ], $configuration); } public function testDisabledConfiguration(): void @@ -134,6 +134,7 @@ public function testDefaultPathLimitMethods(): void public function testMustBeBasedOnExceptionClass(): void { $this->expectException(InvalidConfigurationException::class); + $this->getConfigs(array('rate_response_exception' => '\StdClass')); } diff --git a/Tests/DependencyInjection/NoxlogicRateLimitExtensionTest.php b/Tests/DependencyInjection/NoxlogicRateLimitExtensionTest.php index c55e94e..9f92e77 100644 --- a/Tests/DependencyInjection/NoxlogicRateLimitExtensionTest.php +++ b/Tests/DependencyInjection/NoxlogicRateLimitExtensionTest.php @@ -11,12 +11,9 @@ use Symfony\Component\DependencyInjection\ParameterBag\ParameterBag; use Symfony\Component\DependencyInjection\Reference; -/** - * ConfigurationTest - */ class NoxlogicRateLimitExtensionTest extends WebTestCase { - public function testAreParametersSet() + public function testAreParametersSet(): void { $extension = new NoxlogicRateLimitExtension(); $containerBuilder = new ContainerBuilder(new ParameterBag()); @@ -28,59 +25,59 @@ public function testAreParametersSet() $this->assertEquals($containerBuilder->getParameter('noxlogic_rate_limit.headers.reset.name'), 'X-RateLimit-Reset'); } - public function testStorageEngineParameterProvider() + public function testStorageEngineParameterProvider(): void { $extension = new NoxlogicRateLimitExtension(); $containerBuilder = new ContainerBuilder(new ParameterBag()); - $extension->load(array( - 'noxlogic_rate_limit' => array( + $extension->load([ + 'noxlogic_rate_limit' => [ 'storage_engine' => 'doctrine', 'doctrine_provider' => 'redis_cache', - ) - ), $containerBuilder); + ] + ], $containerBuilder); - $this->assertEquals('Noxlogic\RateLimitBundle\Service\Storage\DoctrineCache', $containerBuilder->getParameter('noxlogic_rate_limit.storage.class')); + self::assertSame(DoctrineCache::class, $containerBuilder->getParameter('noxlogic_rate_limit.storage.class')); $storageDef = $containerBuilder->getDefinition('noxlogic_rate_limit.storage'); - $this->assertEquals('doctrine_cache.providers.redis_cache', (string)($storageDef->getArgument(0))); + self::assertSame('doctrine_cache.providers.redis_cache', (string)($storageDef->getArgument(0))); } - public function testStorageEngineParameterService() + public function testStorageEngineParameterService(): void { $extension = new NoxlogicRateLimitExtension(); $containerBuilder = new ContainerBuilder(new ParameterBag()); - $extension->load(array( - 'noxlogic_rate_limit' => array( + $extension->load([ + 'noxlogic_rate_limit' => [ 'storage_engine' => 'doctrine', 'doctrine_service' => 'my.redis_cache', - ) - ), $containerBuilder); + ] + ], $containerBuilder); - $this->assertEquals('Noxlogic\RateLimitBundle\Service\Storage\DoctrineCache', $containerBuilder->getParameter('noxlogic_rate_limit.storage.class')); + self::assertSame(DoctrineCache::class, $containerBuilder->getParameter('noxlogic_rate_limit.storage.class')); $storageDef = $containerBuilder->getDefinition('noxlogic_rate_limit.storage'); - $this->assertEquals('my.redis_cache', (string)($storageDef->getArgument(0))); + self::assertSame('my.redis_cache', (string)($storageDef->getArgument(0))); } public function testParametersWhenDisabled() { $extension = new NoxlogicRateLimitExtension(); $containerBuilder = new ContainerBuilder(new ParameterBag()); - $extension->load(array('enabled' => false), $containerBuilder); + $extension->load(['enabled' => false], $containerBuilder); - $this->assertEquals(429, $containerBuilder->getParameter('noxlogic_rate_limit.rate_response_code')); + self::assertSame(429, $containerBuilder->getParameter('noxlogic_rate_limit.rate_response_code')); } - public function testPathLimitsParameter() + public function testPathLimitsParameter(): void { - $pathLimits = array( - 'api' => array( + $pathLimits = [ + 'api' => [ 'path' => 'api/', - 'methods' => array('GET'), + 'methods' => ['GET'], 'limit' => 100, 'period' => 60 - ) - ); + ] + ]; $extension = new NoxlogicRateLimitExtension(); $containerBuilder = new ContainerBuilder(new ParameterBag()); diff --git a/Tests/EventListener/MockStorage.php b/Tests/EventListener/MockStorage.php index 56d8a92..80658cf 100644 --- a/Tests/EventListener/MockStorage.php +++ b/Tests/EventListener/MockStorage.php @@ -7,15 +7,9 @@ class MockStorage implements StorageInterface { - protected $rates; + private array $rates; - /** - * Get information about the current rate - * - * @param string $key - * @return RateLimitInfo Rate limit information - */ - public function getRateInfo($key) + public function getRateInfo($key): RateLimitInfo { $info = $this->rates[$key]; @@ -26,13 +20,7 @@ public function getRateInfo($key) return $rateLimitInfo; } - /** - * Limit the rate by one - * - * @param string $key - * @return RateLimitInfo Rate limit info - */ - public function limitRate($key) + public function limitRate($key): ?RateLimitInfo { if (! isset($this->rates[$key])) { return null; @@ -48,20 +36,14 @@ public function limitRate($key) * @param string $key * @param integer $limit * @param integer $period - * @return \Noxlogic\RateLimitBundle\Service\RateLimitInfo */ - public function createRate($key, $limit, $period) + public function createRate($key, $limit, $period): RateLimitInfo { $this->rates[$key] = array('calls' => 1, 'limit' => $limit, 'reset' => (time() + $period)); return $this->getRateInfo($key); } - /** - * Reset the rating - * - * @param $key - */ - public function resetRate($key) + public function resetRate($key): void { unset($this->rates[$key]); } diff --git a/Tests/Service/Storage/DoctrineCacheTest.php b/Tests/Service/Storage/DoctrineCacheTest.php index d326c91..c6548a7 100644 --- a/Tests/Service/Storage/DoctrineCacheTest.php +++ b/Tests/Service/Storage/DoctrineCacheTest.php @@ -3,31 +3,35 @@ namespace Noxlogic\RateLimitBundle\Tests\Service\Storage; +use Noxlogic\RateLimitBundle\Service\RateLimitInfo; use Noxlogic\RateLimitBundle\Service\Storage\DoctrineCache; use Noxlogic\RateLimitBundle\Tests\TestCase; +use Doctrine\Common\Cache\Cache; class DoctrineCacheTest extends TestCase { - public function testGetRateInfo() + public function testGetRateInfo(): void { - $client = $this->getMockBuilder('Doctrine\\Common\\Cache\\Cache') + $client = $this->getMockBuilder(Cache::class) ->getMock(); $client->expects($this->once()) ->method('fetch') ->with('foo') - ->will($this->returnValue(array('limit' => 100, 'calls' => 50, 'reset' => 1234))); + ->willReturn(['limit' => 100, 'calls' => 50, 'reset' => 1234]); $storage = new DoctrineCache($client); + $rli = $storage->getRateInfo('foo'); - $this->assertInstanceOf('Noxlogic\\RateLimitBundle\\Service\\RateLimitInfo', $rli); + + $this->assertInstanceOf(RateLimitInfo::class, $rli); $this->assertEquals(100, $rli->getLimit()); $this->assertEquals(50, $rli->getCalls()); $this->assertEquals(1234, $rli->getResetTimestamp()); } - public function testCreateRate() + public function testGetRateInfo_exception(): void { - $client = $this->getMockBuilder('Doctrine\\Common\\Cache\\Cache') + $client = $this->getMockBuilder(Cache::class) ->getMock(); $client->expects($this->once()) ->method('save'); @@ -36,33 +40,32 @@ public function testCreateRate() $storage->createRate('foo', 100, 123); } - - public function testLimitRateNoKey() + public function testCreateRate_exception(): void { - $client = $this->getMockBuilder('Doctrine\\Common\\Cache\\Cache') + $client = $this->getMockBuilder(Cache::class) ->getMock(); $client->expects($this->once()) ->method('fetch') ->with('foo') - ->will($this->returnValue(false)); + ->willReturn(false); $storage = new DoctrineCache($client); $this->assertFalse($storage->limitRate('foo')); } - public function testLimitRateWithKey() + public function testLimitRateWithKey(): void { - $client = $this->getMockBuilder('Doctrine\\Common\\Cache\\Cache') + $client = $this->getMockBuilder(Cache::class) ->getMock(); $info['limit'] = 100; $info['calls'] = 50; $info['reset'] = 1234; - $client->expects($this->exactly(1)) + $client->expects($this->once()) ->method('fetch') ->with('foo') - ->will($this->returnValue($info)); + ->willReturn($info); $client->expects($this->once()) ->method('save'); @@ -70,11 +73,9 @@ public function testLimitRateWithKey() $storage->limitRate('foo'); } - - - public function testResetRate() + public function testLimitRate_exception(): void { - $client = $this->getMockBuilder('Doctrine\\Common\\Cache\\Cache') + $client = $this->getMockBuilder(Cache::class) ->getMock(); $client->expects($this->once()) ->method('delete') diff --git a/Tests/Service/Storage/PsrCacheTest.php b/Tests/Service/Storage/PsrCacheTest.php index b97d33b..e4f0eef 100644 --- a/Tests/Service/Storage/PsrCacheTest.php +++ b/Tests/Service/Storage/PsrCacheTest.php @@ -1,15 +1,21 @@ getMockBuilder('Psr\\Cache\\CacheItemInterface') + $item = $this->getMockBuilder(CacheItemInterface::class) ->getMock(); $item->expects($this->once()) ->method('isHit') @@ -18,22 +24,24 @@ public function testGetRateInfo() ->method('get') ->willReturn(array('limit' => 100, 'calls' => 50, 'reset' => 1234)); - $client = $this->getMockBuilder('Psr\\Cache\\CacheItemPoolInterface') + $client = $this->getMockBuilder(CacheItemPoolInterface::class) ->getMock(); $client->expects($this->once()) ->method('getItem') ->with('foo') - ->will($this->returnValue($item)); + ->willReturn($item); $storage = new PsrCache($client); + $rli = $storage->getRateInfo('foo'); - $this->assertInstanceOf('Noxlogic\\RateLimitBundle\\Service\\RateLimitInfo', $rli); + + $this->assertInstanceOf(RateLimitInfo::class, $rli); $this->assertEquals(100, $rli->getLimit()); $this->assertEquals(50, $rli->getCalls()); $this->assertEquals(1234, $rli->getResetTimestamp()); } - public function testCreateRate() + public function testGetRateInfo_exception(): void { $item = $this->getMockBuilder('Psr\\Cache\\CacheItemInterface') ->getMock(); @@ -42,7 +50,7 @@ public function testCreateRate() * psr/cache 3.0 changed the return type of set() and expiresAfter() to return self. * @TODO NEXT_MAJOR: Remove this check and the first conditional block when psr/cache <3 support is dropped. */ - $psrCacheVersion = \Composer\InstalledVersions::getVersion('psr/cache'); + $psrCacheVersion = InstalledVersions::getVersion('psr/cache'); if (version_compare($psrCacheVersion, '3.0', '<')) { $item->expects($this->once()) ->method('set') @@ -59,12 +67,12 @@ public function testCreateRate() ->willReturnSelf(); } - $client = $this->getMockBuilder('Psr\\Cache\\CacheItemPoolInterface') + $client = $this->getMockBuilder(CacheItemPoolInterface::class) ->getMock(); $client->expects($this->once()) ->method('getItem') ->with('foo') - ->will($this->returnValue($item)); + ->willReturn($item); $client->expects($this->once()) ->method('save') ->with($item) @@ -77,24 +85,24 @@ public function testCreateRate() public function testLimitRateNoKey() { - $item = $this->getMockBuilder('Psr\\Cache\\CacheItemInterface') + $item = $this->getMockBuilder(CacheItemInterface::class) ->getMock(); $item->expects($this->once()) ->method('isHit') ->willReturn(false); - $client = $this->getMockBuilder('Psr\\Cache\\CacheItemPoolInterface') + $client = $this->getMockBuilder(CacheItemPoolInterface::class) ->getMock(); $client->expects($this->once()) ->method('getItem') ->with('foo') - ->will($this->returnValue($item)); + ->willReturn($item); $storage = new PsrCache($client); $this->assertFalse($storage->limitRate('foo')); } - public function testLimitRateWithKey() + public function testLimitRate_exception(): void { $item = $this->getMockBuilder('Psr\\Cache\\CacheItemInterface') ->getMock(); @@ -109,12 +117,12 @@ public function testLimitRateWithKey() $item->expects($this->once()) ->method('expiresAfter'); - $client = $this->getMockBuilder('Psr\\Cache\\CacheItemPoolInterface') + $client = $this->getMockBuilder(CacheItemPoolInterface::class) ->getMock(); $client->expects($this->once()) ->method('getItem') ->with('foo') - ->will($this->returnValue($item)); + ->willReturn($item); $client->expects($this->once()) ->method('save') ->with($item) @@ -124,9 +132,9 @@ public function testLimitRateWithKey() $storage->limitRate('foo'); } - public function testResetRate() + public function testResetRate(): void { - $client = $this->getMockBuilder('Psr\\Cache\\CacheItemPoolInterface') + $client = $this->getMockBuilder(CacheItemPoolInterface::class) ->getMock(); $client->expects($this->once()) ->method('deleteItem') diff --git a/Tests/Service/Storage/RedisTest.php b/Tests/Service/Storage/RedisTest.php index acbdb9a..3fb2bef 100644 --- a/Tests/Service/Storage/RedisTest.php +++ b/Tests/Service/Storage/RedisTest.php @@ -1,31 +1,35 @@ getMockBuilder('Predis\\Client') - ->setMethods(array('hgetall')) + $client = $this->getMockBuilder(Client::class) + ->addMethods(['hgetall']) ->getMock(); $client->expects($this->once()) ->method('hgetall') ->with('foo') - ->will($this->returnValue(array('limit' => 100, 'calls' => 50, 'reset' => 1234))); + ->willReturn(['limit' => 100, 'calls' => 50, 'reset' => 1234]); $storage = new Redis($client); $rli = $storage->getRateInfo('foo'); - $this->assertInstanceOf('Noxlogic\\RateLimitBundle\\Service\\RateLimitInfo', $rli); + $this->assertInstanceOf(RateLimitInfo::class, $rli); $this->assertEquals(100, $rli->getLimit()); $this->assertEquals(50, $rli->getCalls()); $this->assertEquals(1234, $rli->getResetTimestamp()); } - public function testcreateRate() + public function testGetRateInfo_exception(): void { $client = $this->getMockBuilder('Predis\\Client') ->setMethods(array('hset', 'expire', 'hgetall')) @@ -45,8 +49,7 @@ public function testcreateRate() $storage->createRate('foo', 100, 123); } - - public function testLimitRateNoKey() + public function testCreateRate_exception(): void { $client = $this->getMockBuilder('Predis\\Client') ->setMethods(array('hgetall')) @@ -54,7 +57,7 @@ public function testLimitRateNoKey() $client->expects($this->once()) ->method('hgetall') ->with('foo') - ->will($this->returnValue([])); + ->willReturn([]); $storage = new Redis($client); $this->assertFalse($storage->limitRate('foo')); @@ -84,10 +87,10 @@ public function testLimitRateWithKey() - public function testresetRate() + public function testResetRate(): void { - $client = $this->getMockBuilder('Predis\\Client') - ->setMethods(array('del')) + $client = $this->getMockBuilder(Client::class) + ->addMethods(array('del')) ->getMock(); $client->expects($this->once()) ->method('del') diff --git a/Tests/Service/Storage/SimpleCacheTest.php b/Tests/Service/Storage/SimpleCacheTest.php index 1e2ae9d..e97b563 100644 --- a/Tests/Service/Storage/SimpleCacheTest.php +++ b/Tests/Service/Storage/SimpleCacheTest.php @@ -1,24 +1,28 @@ getMockBuilder('Psr\\SimpleCache\\CacheInterface') + $client = $this->getMockBuilder(CacheInterface::class) ->getMock(); $client->expects($this->once()) ->method('get') ->with('foo') - ->will($this->returnValue(array('limit' => 100, 'calls' => 50, 'reset' => 1234))); + ->willReturn(['limit' => 100, 'calls' => 50, 'reset' => 1234]); $storage = new SimpleCache($client); $rli = $storage->getRateInfo('foo'); - $this->assertInstanceOf('Noxlogic\\RateLimitBundle\\Service\\RateLimitInfo', $rli); + $this->assertInstanceOf(RateLimitInfo::class, $rli); $this->assertEquals(100, $rli->getLimit()); $this->assertEquals(50, $rli->getCalls()); $this->assertEquals(1234, $rli->getResetTimestamp()); @@ -43,7 +47,7 @@ public function testLimitRateNoKey() $client->expects($this->once()) ->method('get') ->with('foo') - ->will($this->returnValue(null)); + ->willReturn(null); $storage = new SimpleCache($client); $this->assertFalse($storage->limitRate('foo')); @@ -58,10 +62,10 @@ public function testLimitRateWithKey() $info['calls'] = 50; $info['reset'] = 1234; - $client->expects($this->exactly(1)) + $client->expects($this->once()) ->method('get') ->with('foo') - ->will($this->returnValue($info)); + ->willReturn($info); $client->expects($this->once()) ->method('set'); @@ -69,9 +73,9 @@ public function testLimitRateWithKey() $storage->limitRate('foo'); } - public function testResetRate() + public function testResetRate(): void { - $client = $this->getMockBuilder('Psr\\SimpleCache\\CacheInterface') + $client = $this->getMockBuilder(CacheInterface::class) ->getMock(); $client->expects($this->once()) ->method('delete') diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon index 34a01ef..4ccfbba 100644 --- a/phpstan-baseline.neon +++ b/phpstan-baseline.neon @@ -1,59 +1,11 @@ parameters: ignoreErrors: - - - message: '#^Method Noxlogic\\RateLimitBundle\\Attribute\\RateLimit\:\:__construct\(\) has parameter \$methods with no type specified\.$#' - identifier: missingType.parameter - count: 1 - path: Attribute/RateLimit.php - - - - message: '#^Method Noxlogic\\RateLimitBundle\\Attribute\\RateLimit\:\:getMethods\(\) return type has no value type specified in iterable type array\.$#' - identifier: missingType.iterableValue - count: 1 - path: Attribute/RateLimit.php - - - - message: '#^Method Noxlogic\\RateLimitBundle\\Attribute\\RateLimit\:\:setMethods\(\) has parameter \$methods with no type specified\.$#' - identifier: missingType.parameter - count: 1 - path: Attribute/RateLimit.php - - - - message: '#^Property Noxlogic\\RateLimitBundle\\Attribute\\RateLimit\:\:\$methods type has no value type specified in iterable type array\.$#' - identifier: missingType.iterableValue - count: 1 - path: Attribute/RateLimit.php - - message: '#^Method Noxlogic\\RateLimitBundle\\DependencyInjection\\NoxlogicRateLimitExtension\:\:loadServices\(\) has parameter \$config with no value type specified in iterable type array\.$#' identifier: missingType.iterableValue count: 1 path: DependencyInjection/NoxlogicRateLimitExtension.php - - - message: '#^Method Noxlogic\\RateLimitBundle\\EventListener\\BaseListener\:\:getParameter\(\) has parameter \$name with no type specified\.$#' - identifier: missingType.parameter - count: 1 - path: EventListener/BaseListener.php - - - - message: '#^Method Noxlogic\\RateLimitBundle\\EventListener\\BaseListener\:\:setParameter\(\) has no return type specified\.$#' - identifier: missingType.return - count: 1 - path: EventListener/BaseListener.php - - - - message: '#^Method Noxlogic\\RateLimitBundle\\EventListener\\BaseListener\:\:setParameter\(\) has parameter \$name with no type specified\.$#' - identifier: missingType.parameter - count: 1 - path: EventListener/BaseListener.php - - - - message: '#^Method Noxlogic\\RateLimitBundle\\EventListener\\BaseListener\:\:setParameter\(\) has parameter \$value with no type specified\.$#' - identifier: missingType.parameter - count: 1 - path: EventListener/BaseListener.php - - message: '#^Property Noxlogic\\RateLimitBundle\\EventListener\\BaseListener\:\:\$parameters type has no value type specified in iterable type array\.$#' identifier: missingType.iterableValue @@ -66,12 +18,6 @@ parameters: count: 1 path: EventListener/HeaderModificationListener.php - - - message: '#^Method Noxlogic\\RateLimitBundle\\EventListener\\HeaderModificationListener\:\:onKernelResponse\(\) has no return type specified\.$#' - identifier: missingType.return - count: 1 - path: EventListener/HeaderModificationListener.php - - message: '#^Method Noxlogic\\RateLimitBundle\\EventListener\\RateLimitAnnotationListener\:\:getRateLimitsFromAttributes\(\) has parameter \$controller with no value type specified in iterable type array\.$#' identifier: missingType.iterableValue @@ -204,12 +150,6 @@ parameters: count: 1 path: Service/Storage/DoctrineCache.php - - - message: '#^Method Noxlogic\\RateLimitBundle\\Service\\Storage\\DoctrineCache\:\:createRateInfo\(\) has no return type specified\.$#' - identifier: missingType.return - count: 1 - path: Service/Storage/DoctrineCache.php - - message: '#^Method Noxlogic\\RateLimitBundle\\Service\\Storage\\DoctrineCache\:\:createRateInfo\(\) has parameter \$info with no value type specified in iterable type array\.$#' identifier: missingType.iterableValue @@ -234,12 +174,6 @@ parameters: count: 1 path: Service/Storage/Memcache.php - - - message: '#^Method Noxlogic\\RateLimitBundle\\Service\\Storage\\Memcache\:\:createRateInfo\(\) has no return type specified\.$#' - identifier: missingType.return - count: 1 - path: Service/Storage/Memcache.php - - message: '#^Method Noxlogic\\RateLimitBundle\\Service\\Storage\\Memcache\:\:createRateInfo\(\) has parameter \$info with no value type specified in iterable type array\.$#' identifier: missingType.iterableValue @@ -288,12 +222,6 @@ parameters: count: 1 path: Service/Storage/PsrCache.php - - - message: '#^Method Noxlogic\\RateLimitBundle\\Service\\Storage\\PsrCache\:\:createRateInfo\(\) has no return type specified\.$#' - identifier: missingType.return - count: 1 - path: Service/Storage/PsrCache.php - - message: '#^Method Noxlogic\\RateLimitBundle\\Service\\Storage\\PsrCache\:\:createRateInfo\(\) has parameter \$info with no value type specified in iterable type array\.$#' identifier: missingType.iterableValue @@ -342,12 +270,6 @@ parameters: count: 1 path: Service/Storage/SimpleCache.php - - - message: '#^Method Noxlogic\\RateLimitBundle\\Service\\Storage\\SimpleCache\:\:createRateInfo\(\) has no return type specified\.$#' - identifier: missingType.return - count: 1 - path: Service/Storage/SimpleCache.php - - message: '#^Method Noxlogic\\RateLimitBundle\\Service\\Storage\\SimpleCache\:\:createRateInfo\(\) has parameter \$info with no value type specified in iterable type array\.$#' identifier: missingType.iterableValue @@ -424,4 +346,4 @@ parameters: message: '#^Method Noxlogic\\RateLimitBundle\\Util\\PathLimitProcessor\:\:requestMatched\(\) has parameter \$pathLimit with no type specified\.$#' identifier: missingType.parameter count: 1 - path: Util/PathLimitProcessor.php + path: Util/PathLimitProcessor.php \ No newline at end of file diff --git a/phpstan.dist.neon b/phpstan.dist.neon index 8704079..5d2d7d4 100644 --- a/phpstan.dist.neon +++ b/phpstan.dist.neon @@ -1,5 +1,7 @@ parameters: level: 6 + treatPhpDocTypesAsCertain: false + reportUnmatchedIgnoredErrors: false paths: - Attribute/ - DependencyInjection/ diff --git a/phpunit.xml.dist b/phpunit.xml.dist index d703cee..36cf199 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -1,29 +1,30 @@ - - - - Tests - - - - - - . - - Resources - Tests - vendor - - - + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + backupGlobals="false" + backupStaticAttributes="false" + colors="true" + convertErrorsToExceptions="true" + convertNoticesToExceptions="true" + convertWarningsToExceptions="true" + processIsolation="false" + stopOnFailure="false" + bootstrap="Tests/bootstrap.php" + xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/9.3/phpunit.xsd" +> + + + . + + + Resources + Tests + vendor + + + + + Tests + +