diff --git a/.github/workflows/php.yml b/.github/workflows/php.yml index 6c0087db..3396f8a9 100644 --- a/.github/workflows/php.yml +++ b/.github/workflows/php.yml @@ -17,25 +17,18 @@ jobs: matrix: include: # Test the latest stable release - - php-version: '7.3' - - php-version: '7.4' - - php-version: '8.0' - php-version: '8.1' dependencies: 'jean-beru/fos-http-cache-cloudfront' - - php-version: '7.4' - symfony-version: '4.*' - - php-version: '7.4' - symfony-version: '5.*' - - php-version: '8.0' - symfony-version: '6.*' + - php-version: '8.1' + symfony-version: '6.4' + - php-version: '8.2' + symfony-version: '7.*' + - php-version: '8.2' + symfony-version: '6.4' # Minimum supported dependencies with the oldest PHP version - - php-version: '7.3' + - php-version: '8.1' composer-flag: '--prefer-stable --prefer-lowest' - symfony-version: '4.4' - # Test latest unreleased versions - - php-version: '8.0' - symfony-version: '6.*' - stability: 'dev' + symfony-version: '6.4' name: PHP ${{ matrix.php-version }} Test on Symfony ${{ matrix.symfony-version }} ${{ matrix.dependencies}} ${{ matrix.stability }} ${{ matrix.composer-flag }} steps: diff --git a/composer.json b/composer.json index 85e279b8..cfa79564 100644 --- a/composer.json +++ b/composer.json @@ -21,11 +21,11 @@ } ], "require": { - "php": "^7.3 || ^8.0", - "friendsofsymfony/http-cache": "^2.15", - "symfony/framework-bundle": "^4.4.0 || ^5.0 || ^6.0", - "symfony/http-foundation": "^4.4.0 || ^5.0 || ^6.0", - "symfony/http-kernel": "^4.4.0 || ^5.0 || ^6.0" + "php": ">= 8.1", + "friendsofsymfony/http-cache": "^3.x-dev", + "symfony/framework-bundle": "^6.4 || ^7.0", + "symfony/http-foundation": "^6.4 || ^7.0", + "symfony/http-kernel": "^6.4 || ^7.0" }, "require-dev": { "php-http/guzzle7-adapter": "^0.1.1", @@ -35,20 +35,19 @@ "guzzlehttp/guzzle": "^7.2", "mockery/mockery": "^1.3.2", "monolog/monolog": "*", - "sensio/framework-extra-bundle": "^4.0 || ^5.5.1 || ^6.0", "doctrine/annotations": "^1.11", - "symfony/browser-kit": "^4.4 || ^5.0 || ^6.0", - "symfony/console": "^4.4 || ^5.0 || ^6.0", - "symfony/finder": "^4.4 || ^5.0 || ^6.0", - "symfony/phpunit-bridge": "v5.3.7", - "symfony/security-bundle": "^4.4 || ^5.0 || ^6.0", - "symfony/twig-bundle": "^4.4 || ^5.0 || ^6.0", - "twig/twig": "^2.13", - "symfony/yaml": "^4.4 || ^5.0 || ^6.0", - "symfony/css-selector": "^4.4 || ^5.0 || ^6.0", - "symfony/expression-language": "^4.4 || ^5.0 || ^6.0", + "symfony/browser-kit": "^6.4 || ^7.0", + "symfony/console": "^6.4 || ^7.0", + "symfony/finder": "^6.4 || ^7.0", + "symfony/phpunit-bridge": "^7.0", + "symfony/security-bundle": "^6.4 || ^7.0", + "symfony/twig-bundle": "^6.4 || ^7.0", + "twig/twig": "^v3.8", + "symfony/yaml": "^6.4 || ^7.0", + "symfony/css-selector": "^6.4 || ^7.0", + "symfony/expression-language": "^6.4 || ^7.0", "symfony/monolog-bundle": "^3.0", - "symfony/routing": "^4.4 || ^5.0 || ^6.0", + "symfony/routing": "^6.4 || ^7.0", "matthiasnoback/symfony-dependency-injection-test": "^4.0", "sebastian/exporter": "^2.0" }, @@ -74,5 +73,10 @@ "classmap": [ "tests/Functional/Fixtures/app/AppKernel.php" ] + }, + "config": { + "allow-plugins": { + "php-http/discovery": true + } } } diff --git a/src/Configuration/ConfigurationInterface.php b/src/Configuration/ConfigurationInterface.php new file mode 100644 index 00000000..1fd02f0b --- /dev/null +++ b/src/Configuration/ConfigurationInterface.php @@ -0,0 +1,34 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace FOS\HttpCacheBundle\Configuration; + +/** + * ConfigurationInterface. + * + * @author Fabien Potencier + */ +interface ConfigurationInterface +{ + /** + * Returns the alias name for an annotated configuration. + * + * @return string + */ + public function getAliasName(): string; + + /** + * Returns whether multiple annotations of this type are allowed. + * + * @return bool + */ + public function allowArray(): bool; +} diff --git a/src/Configuration/InvalidatePath.php b/src/Configuration/InvalidatePath.php index f9ad55d2..976c9992 100644 --- a/src/Configuration/InvalidatePath.php +++ b/src/Configuration/InvalidatePath.php @@ -11,13 +11,11 @@ namespace FOS\HttpCacheBundle\Configuration; -use Sensio\Bundle\FrameworkExtraBundle\Configuration\ConfigurationAnnotation; - /** * @Annotation */ #[\Attribute(\Attribute::IS_REPEATABLE | \Attribute::TARGET_CLASS | \Attribute::TARGET_METHOD)] -class InvalidatePath extends ConfigurationAnnotation +class InvalidatePath implements ConfigurationInterface { /** * @var array @@ -34,7 +32,13 @@ public function __construct( $values = $data; } - parent::__construct($values); + foreach ($values as $k => $v) { + if (!method_exists($this, $name = 'set'.$k)) { + throw new \RuntimeException(sprintf('Unknown key "%s" for annotation "@%s".', $k, static::class)); + } + + $this->$name($v); + } } /** diff --git a/src/Configuration/InvalidateRoute.php b/src/Configuration/InvalidateRoute.php index fc74abc6..f39138de 100644 --- a/src/Configuration/InvalidateRoute.php +++ b/src/Configuration/InvalidateRoute.php @@ -11,7 +11,6 @@ namespace FOS\HttpCacheBundle\Configuration; -use Sensio\Bundle\FrameworkExtraBundle\Configuration\ConfigurationAnnotation; use Symfony\Component\Config\Definition\Exception\InvalidConfigurationException; use Symfony\Component\ExpressionLanguage\ExpressionLanguage; @@ -19,7 +18,7 @@ * @Annotation */ #[\Attribute(\Attribute::IS_REPEATABLE | \Attribute::TARGET_CLASS | \Attribute::TARGET_METHOD)] -class InvalidateRoute extends ConfigurationAnnotation +class InvalidateRoute implements ConfigurationInterface { /** * @var string @@ -44,7 +43,13 @@ public function __construct( $values['params'] = $values['params'] ?? $params; - parent::__construct($values); + foreach ($values as $k => $v) { + if (!method_exists($this, $name = 'set'.$k)) { + throw new \RuntimeException(sprintf('Unknown key "%s" for annotation "@%s".', $k, static::class)); + } + + $this->$name($v); + } } /** diff --git a/src/Configuration/Tag.php b/src/Configuration/Tag.php index fadd3e81..833d98e5 100644 --- a/src/Configuration/Tag.php +++ b/src/Configuration/Tag.php @@ -12,7 +12,6 @@ namespace FOS\HttpCacheBundle\Configuration; use FOS\HttpCacheBundle\Exception\InvalidTagException; -use Sensio\Bundle\FrameworkExtraBundle\Configuration\ConfigurationAnnotation; use Symfony\Component\Config\Definition\Exception\InvalidConfigurationException; use Symfony\Component\ExpressionLanguage\ExpressionLanguage; @@ -20,7 +19,7 @@ * @Annotation */ #[\Attribute(\Attribute::IS_REPEATABLE | \Attribute::TARGET_CLASS | \Attribute::TARGET_METHOD)] -class Tag extends ConfigurationAnnotation +class Tag implements ConfigurationInterface { private $tags; @@ -39,7 +38,13 @@ public function __construct( $values['expression'] = $values['expression'] ?? $expression; - parent::__construct($values); + foreach ($values as $k => $v) { + if (!method_exists($this, $name = 'set'.$k)) { + throw new \RuntimeException(sprintf('Unknown key "%s" for annotation "@%s".', $k, static::class)); + } + + $this->$name($v); + } } /** diff --git a/src/DependencyInjection/Compiler/TagListenerPass.php b/src/DependencyInjection/Compiler/TagListenerPass.php deleted file mode 100644 index 4098178f..00000000 --- a/src/DependencyInjection/Compiler/TagListenerPass.php +++ /dev/null @@ -1,45 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace FOS\HttpCacheBundle\DependencyInjection\Compiler; - -use Sensio\Bundle\FrameworkExtraBundle\EventListener\ControllerListener; -use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface; -use Symfony\Component\DependencyInjection\ContainerBuilder; - -/** - * Check for required ControllerListener if TagListener is enabled. - */ -class TagListenerPass implements CompilerPassInterface -{ - /** - * {@inheritdoc} - */ - public function process(ContainerBuilder $container): void - { - if (true === $container->getParameter('fos_http_cache.compiler_pass.tag_annotations') - && !$this->hasControllerListener($container) - ) { - throw new \RuntimeException( - 'Tag annotations are enabled by default because otherwise things could silently not work.' - .' The annotations require the SensioFrameworkExtraBundle ControllerListener. If you do not use' - .' annotations for tags, set "fos_http_cache.tags.annotations.enabled: false". Otherwise install' - .' sensio/framework-extra-bundle and enabled it in your kernel.' - ); - } - } - - private function hasControllerListener(ContainerBuilder $container): bool - { - return $container->has('sensio_framework_extra.controller.listener') || - $container->has(ControllerListener::class); - } -} diff --git a/src/EventListener/InvalidationListener.php b/src/EventListener/InvalidationListener.php index 9a67400b..fc31df0f 100644 --- a/src/EventListener/InvalidationListener.php +++ b/src/EventListener/InvalidationListener.php @@ -211,6 +211,7 @@ private function invalidateRoutes(array $routes, Request $request) $values['request'] = $request; foreach ($routes as $route) { + $params = []; if (null !== $route->getParams()) { @@ -223,7 +224,6 @@ private function invalidateRoutes(array $routes, Request $request) $params[$key] = $value; } } - $this->cacheManager->invalidateRoute($route->getName(), $params); } } diff --git a/src/EventListener/Php8AttributesListener.php b/src/EventListener/Php8AttributesListener.php index 00b7af67..7affeb74 100644 --- a/src/EventListener/Php8AttributesListener.php +++ b/src/EventListener/Php8AttributesListener.php @@ -2,7 +2,7 @@ namespace FOS\HttpCacheBundle\EventListener; -use Sensio\Bundle\FrameworkExtraBundle\Configuration\ConfigurationInterface; +use FOS\HttpCacheBundle\Configuration\ConfigurationInterface; use Symfony\Component\EventDispatcher\EventSubscriberInterface; use Symfony\Component\HttpKernel\Controller\ControllerResolverInterface; use Symfony\Component\HttpKernel\Event\GetResponseEvent; diff --git a/src/EventListener/UserContextListener.php b/src/EventListener/UserContextListener.php index ee987381..66c1e327 100644 --- a/src/EventListener/UserContextListener.php +++ b/src/EventListener/UserContextListener.php @@ -195,7 +195,7 @@ private function isAnonymous(Request $request) */ public function onKernelResponse(UserContextResponseEvent $event) { - if (HttpKernelInterface::MASTER_REQUEST != $event->getRequestType()) { + if (HttpKernelInterface::MAIN_REQUEST != $event->getRequestType()) { return; } diff --git a/src/FOSHttpCacheBundle.php b/src/FOSHttpCacheBundle.php index dc1dbfa1..d94b7dd4 100644 --- a/src/FOSHttpCacheBundle.php +++ b/src/FOSHttpCacheBundle.php @@ -15,7 +15,6 @@ use FOS\HttpCacheBundle\DependencyInjection\Compiler\HashGeneratorPass; use FOS\HttpCacheBundle\DependencyInjection\Compiler\LoggerPass; use FOS\HttpCacheBundle\DependencyInjection\Compiler\SessionListenerPass; -use FOS\HttpCacheBundle\DependencyInjection\Compiler\TagListenerPass; use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\HttpKernel\Bundle\Bundle; @@ -27,7 +26,6 @@ class FOSHttpCacheBundle extends Bundle public function build(ContainerBuilder $container): void { $container->addCompilerPass(new LoggerPass()); - $container->addCompilerPass(new TagListenerPass()); $container->addCompilerPass(new HashGeneratorPass()); $container->addCompilerPass(new SessionListenerPass()); diff --git a/src/Http/RequestMatcher/QuerystringRequestMatcher.php b/src/Http/RequestMatcher/QuerystringRequestMatcher.php index 7e86534c..241abd62 100644 --- a/src/Http/RequestMatcher/QuerystringRequestMatcher.php +++ b/src/Http/RequestMatcher/QuerystringRequestMatcher.php @@ -12,18 +12,23 @@ namespace FOS\HttpCacheBundle\Http\RequestMatcher; use Symfony\Component\HttpFoundation\Request; -use Symfony\Component\HttpFoundation\RequestMatcher as SymfonyRequestMatcher; +use Symfony\Component\HttpFoundation\RequestMatcherInterface; /** * Extend the Symfony RequestMatcher class to support query string matching. */ -class QuerystringRequestMatcher extends SymfonyRequestMatcher +class QuerystringRequestMatcher implements RequestMatcherInterface { /** * @var string Regular expression to match the query string part of the request url */ private $queryString; + public function __construct($queryString = null) + { + $this->queryString = $queryString; + } + /** * @param string $queryString */ @@ -37,10 +42,6 @@ public function setQueryString($queryString) */ public function matches(Request $request): bool { - if (!parent::matches($request)) { - return false; - } - if (null === $this->queryString) { return true; } diff --git a/src/Http/ResponseMatcher/ExpressionResponseMatcher.php b/src/Http/ResponseMatcher/ExpressionResponseMatcher.php index 072cd5c4..393f3813 100644 --- a/src/Http/ResponseMatcher/ExpressionResponseMatcher.php +++ b/src/Http/ResponseMatcher/ExpressionResponseMatcher.php @@ -11,7 +11,7 @@ namespace FOS\HttpCacheBundle\Http\ResponseMatcher; -use Sensio\Bundle\FrameworkExtraBundle\Security\ExpressionLanguage as SecurityExpressionLanguage; +use FOS\HttpCacheBundle\Security\ExpressionLanguage as SecurityExpressionLanguage; use Symfony\Component\ExpressionLanguage\ExpressionLanguage; use Symfony\Component\HttpFoundation\Response; diff --git a/src/Security/ExpressionLanguage.php b/src/Security/ExpressionLanguage.php new file mode 100644 index 00000000..55a9105b --- /dev/null +++ b/src/Security/ExpressionLanguage.php @@ -0,0 +1,33 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace FOS\HttpCacheBundle\Security; + +use Symfony\Component\Security\Core\Authorization\ExpressionLanguage as BaseExpressionLanguage; + +/** + * Adds some function to the default Symfony Security ExpressionLanguage. + * + * @author Fabien Potencier + */ +class ExpressionLanguage extends BaseExpressionLanguage +{ + protected function registerFunctions() + { + parent::registerFunctions(); + + $this->register('is_granted', function ($attributes, $object = 'null') { + return sprintf('$auth_checker->isGranted(%s, %s)', $attributes, $object); + }, function (array $variables, $attributes, $object = null) { + return $variables['auth_checker']->isGranted($attributes, $object); + }); + } +} diff --git a/tests/Functional/EventListener/InvalidationListenerTest.php b/tests/Functional/EventListener/InvalidationListenerTest.php index 13b7e5fd..2f6e95ee 100644 --- a/tests/Functional/EventListener/InvalidationListenerTest.php +++ b/tests/Functional/EventListener/InvalidationListenerTest.php @@ -19,83 +19,6 @@ class InvalidationListenerTest extends WebTestCase { use MockeryPHPUnitIntegration; - public function testInvalidateRoute() - { - $client = static::createClient(); - - $mock = \Mockery::mock(CacheManager::class); - $mock->shouldReceive('supports') - ->zeroOrMoreTimes() - ->andReturnTrue() - ; - $mock->shouldReceive('invalidateRoute') - ->once() - ->with('test_noncached', []) - ; - $mock->shouldReceive('invalidateRoute') - ->once() - ->with('test_cached', ['id' => 'myhardcodedid']) - ; - $mock->shouldReceive('invalidateRoute') - ->once() - ->with('tag_one', ['id' => 42]) - ; - $mock->shouldReceive('flush') - ->once() - ->andReturn(3) - ; - $client->getContainer()->set('fos_http_cache.cache_manager', $mock); - - $client->request('POST', '/invalidate/route/42'); - } - - /** - * @dataProvider getStatusCodesThatTriggerInvalidation - */ - public function testInvalidatePath($statusCode) - { - $client = static::createClient(); - - $mock = \Mockery::mock(CacheManager::class); - $mock->shouldReceive('supports') - ->zeroOrMoreTimes() - ->andReturnTrue() - ; - $mock->shouldReceive('invalidatePath') - ->once() - ->with('/cached') - ; - $mock->shouldReceive('invalidatePath') - ->once() - ->with(sprintf('/invalidate/path/%s', $statusCode)) - ; - $mock->shouldReceive('flush') - ->once() - ->andReturn(2) - ; - $client->getContainer()->set('fos_http_cache.cache_manager', $mock); - - $client->request('POST', sprintf('/invalidate/path/%s', $statusCode)); - } - - public function testErrorIsNotInvalidated() - { - $client = static::createClient(); - - $mock = \Mockery::mock(CacheManager::class); - $mock->shouldReceive('supports') - ->zeroOrMoreTimes() - ->andReturnTrue() - ; - $mock->shouldReceive('flush') - ->once() - ->andReturn(0) - ; - $client->getContainer()->set('fos_http_cache.cache_manager', $mock); - - $client->request('POST', '/invalidate/error'); - } - /** * @requires PHP 8.0 */ diff --git a/tests/Functional/EventListener/TagListenerTest.php b/tests/Functional/EventListener/TagListenerTest.php deleted file mode 100644 index a5781fee..00000000 --- a/tests/Functional/EventListener/TagListenerTest.php +++ /dev/null @@ -1,307 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace FOS\HttpCacheBundle\Tests\Functional\EventListener; - -use FOS\HttpCacheBundle\CacheManager; -use FOS\HttpCacheBundle\Configuration\Tag; -use FOS\HttpCacheBundle\EventListener\TagListener; -use Mockery\Adapter\Phpunit\MockeryPHPUnitIntegration; -use Symfony\Bundle\FrameworkBundle\Test\WebTestCase; -use Symfony\Component\HttpFoundation\Request; -use Symfony\Component\HttpFoundation\Response; -use Symfony\Component\HttpKernel\Event\FilterResponseEvent; -use Symfony\Component\HttpKernel\Event\ResponseEvent; -use Symfony\Component\HttpKernel\HttpKernelInterface; -use Symfony\Component\HttpKernel\Kernel; -use Symfony\Component\HttpKernel\KernelInterface; - -if (Kernel::MAJOR_VERSION >= 5) { - class_alias(ResponseEvent::class, 'FOS\HttpCacheBundle\Tests\Functional\EventListener\TagResponseEvent'); -} else { - class_alias(FilterResponseEvent::class, 'FOS\HttpCacheBundle\Tests\Functional\EventListener\TagResponseEvent'); -} - -class TagListenerTest extends WebTestCase -{ - use MockeryPHPUnitIntegration; - private static $overrideService = false; - - public function testAnnotationTagsAreSet() - { - $client = static::createClient(); - - $client->request('GET', '/tag/list'); - $response = $client->getResponse(); - $this->assertEquals('all-items,item-123', $response->headers->get('X-Cache-Tags')); - - $client->request('GET', '/tag/123'); - $response = $client->getResponse(); - $this->assertEquals(200, $response->getStatusCode(), $response->getContent()); - $this->assertEquals('item-123', $response->headers->get('X-Cache-Tags')); - } - - /** - * @requires PHP 8.0 - */ - public function testAttributeTagsAreSet() - { - $client = static::createClient(); - - $client->request('GET', '/php8/tag/list'); - $response = $client->getResponse(); - $this->assertEquals('all-items,item-123', $response->headers->get('X-Cache-Tags')); - - $client->request('GET', '/php8/tag/123'); - $response = $client->getResponse(); - $this->assertEquals(200, $response->getStatusCode(), $response->getContent()); - $this->assertEquals('item-123', $response->headers->get('X-Cache-Tags')); - } - - public function testAnnotationTagsAreInvalidated() - { - self::$overrideService = true; - $client = static::createClient(); - - $mock = \Mockery::mock(CacheManager::class); - $mock->shouldReceive('supports') - ->zeroOrMoreTimes() - ->andReturnTrue() - ; - $mock->shouldReceive('invalidateTags') - ->once() - ->with(['all-items']) - ; - $mock->shouldReceive('invalidateTags') - ->once() - ->with(['item-123']) - ; - $mock->shouldReceive('flush') - ->once() - ->andReturn(2) - ; - $client->getContainer()->set('fos_http_cache.cache_manager', $mock); - - $client->request('POST', '/tag/123'); - $response = $client->getResponse(); - $this->assertEquals(200, $response->getStatusCode(), $response->getContent()); - } - - public function testErrorIsNotInvalidated() - { - self::$overrideService = true; - $client = static::createClient(); - - $mock = \Mockery::mock(CacheManager::class); - $mock->shouldReceive('supports') - ->zeroOrMoreTimes() - ->andReturnTrue() - ; - $mock->shouldReceive('flush') - ->once() - ->andReturn(0) - ; - $client->getContainer()->set('fos_http_cache.cache_manager', $mock); - - $client->request('POST', '/tag/error'); - } - - public function testConfigurationTagsAreSet() - { - $client = static::createClient(); - - $client->request('GET', '/cached/51'); - $response = $client->getResponse(); - $this->assertEquals(200, $response->getStatusCode(), $response->getContent()); - $this->assertEquals('area,area-51', $response->headers->get('X-Cache-Tags')); - } - - public function testConfigurationTagsAreInvalidated() - { - self::$overrideService = true; - $client = static::createClient(); - - $mock = \Mockery::mock(CacheManager::class); - $mock->shouldReceive('supports') - ->zeroOrMoreTimes() - ->andReturnTrue() - ; - $mock->shouldReceive('invalidateTags') - ->once() - ->with(['area', 'area-51']) - ; - $mock->shouldReceive('flush') - ->once() - ->andReturn(1) - ; - $client->getContainer()->set('fos_http_cache.cache_manager', $mock); - - $client->request('PUT', '/cached/51'); - } - - public function testManualTagging() - { - $client = static::createClient(); - - $client->request('GET', '/tag_manual'); - $response = $client->getResponse(); - $this->assertEquals(200, $response->getStatusCode(), $response->getContent()); - $this->assertEquals('manual-tag,sub-tag,sub-items,manual-items', $response->headers->get('X-Cache-Tags')); - } - - public function testTwigExtension() - { - $client = static::createClient(); - - $client->request('GET', '/tag_twig'); - $response = $client->getResponse(); - $this->assertEquals(200, $response->getStatusCode(), $response->getContent()); - $this->assertEquals('tag-from-twig', $response->headers->get('X-Cache-Tags')); - } - - /** - * @dataProvider cacheableRequestResponseCombinations - */ - public function testTagsAreSetWhenCacheable(Request $request, Response $response) - { - self::$overrideService = true; - $request->attributes->set('_tag', [new Tag(['value' => ['cacheable-is-tagged']])]); - $client = static::createClient(); - - $event = new TagResponseEvent( - $client->getKernel(), - $request, - HttpKernelInterface::MASTER_REQUEST, - $response - ); - - // No invalidation - $mock = \Mockery::mock(CacheManager::class); - $mock->shouldReceive('supports') - ->zeroOrMoreTimes() - ->andReturnTrue() - ; - $client->getContainer()->set('fos_http_cache.cache_manager', $mock); - - /** @var TagListener $tagListener */ - $tagListener = $client->getContainer()->get('fos_http_cache.event_listener.tag'); - $tagListener->onKernelResponse($event); - - $headers = $event->getResponse()->headers; - $this->assertEquals('cacheable-is-tagged', $headers->get('X-Cache-Tags')); - } - - /** - * @dataProvider mustInvalidateRequestResponseCombinations - */ - public function testTagsAreInvalidated(Request $request, Response $response) - { - self::$overrideService = true; - $request->attributes->set('_tag', [new Tag(['value' => ['invalidated']])]); - $client = static::createClient(); - - $event = new TagResponseEvent( - $client->getKernel(), - $request, - HttpKernelInterface::MASTER_REQUEST, - $response - ); - $mock = \Mockery::mock(CacheManager::class); - $mock->shouldReceive('supports') - ->zeroOrMoreTimes() - ->andReturnTrue() - ; - $mock->shouldReceive('invalidateTags') - ->once() - ->with(['invalidated']) - ; - $client->getContainer()->set('fos_http_cache.cache_manager', $mock); - - /** @var TagListener $tagListener */ - $tagListener = $client->getContainer()->get('fos_http_cache.event_listener.tag'); - $tagListener->onKernelResponse($event); - - $headers = $event->getResponse()->headers; - - // No cache tags set - $this->assertFalse($headers->has('X-Cache-Tags')); - } - - /** - * @dataProvider mustNotInvalidateRequestResponseCombinations - */ - public function testTagsAreNotInvalidated(Request $request, Response $response) - { - self::$overrideService = true; - $request->attributes->set('_tag', [new Tag(['value' => ['not-invalidated']])]); - $client = static::createClient(); - - $event = new TagResponseEvent( - $client->getKernel(), - $request, - HttpKernelInterface::MASTER_REQUEST, - $response - ); - - // No invalidation - $mock = \Mockery::mock(CacheManager::class); - $mock->shouldReceive('supports') - ->zeroOrMoreTimes() - ->andReturnTrue() - ; - $client->getContainer()->set('fos_http_cache.cache_manager', $mock); - - $tagListener = $client->getContainer()->get('fos_http_cache.event_listener.tag'); - $tagListener->onKernelResponse($event); - - $headers = $event->getResponse()->headers; - - // No cache tags set - $this->assertFalse($headers->has('X-Cache-Tags')); - } - - public function cacheableRequestResponseCombinations() - { - return [ - [Request::create('', 'GET'), new Response('', 200)], - [Request::create('', 'HEAD'), new Response('', 200)], - // https://github.com/FriendsOfSymfony/FOSHttpCacheBundle/issues/286 - [Request::create('', 'GET'), new Response('', 301)], - ]; - } - - public function mustInvalidateRequestResponseCombinations() - { - return [ - // https://github.com/FriendsOfSymfony/FOSHttpCacheBundle/issues/241 - [Request::create('', 'POST'), new Response('', 201)], - ]; - } - - public function mustNotInvalidateRequestResponseCombinations() - { - return [ - // https://github.com/FriendsOfSymfony/FOSHttpCacheBundle/issues/279 - [Request::create('', 'OPTIONS'), new Response('', 200)], - ]; - } - - protected static function createKernel(array $options = []): KernelInterface - { - $kernel = parent::createKernel($options); - \assert($kernel instanceof \AppKernel); - if (static::$overrideService) { - $kernel->addServiceOverride('override_cache_manager.yml'); - } - - return $kernel; - } -} diff --git a/tests/Functional/Fixtures/app/AppKernel.php b/tests/Functional/Fixtures/app/AppKernel.php index b511118a..f122661e 100644 --- a/tests/Functional/Fixtures/app/AppKernel.php +++ b/tests/Functional/Fixtures/app/AppKernel.php @@ -47,7 +47,6 @@ public function registerBundles(): iterable { return [ new \Symfony\Bundle\FrameworkBundle\FrameworkBundle(), - new \Sensio\Bundle\FrameworkExtraBundle\SensioFrameworkExtraBundle(), new \Symfony\Bundle\MonologBundle\MonologBundle(), new \Symfony\Bundle\SecurityBundle\SecurityBundle(), new \Symfony\Bundle\TwigBundle\TwigBundle(), diff --git a/tests/Functional/Fixtures/app/config/config.yml b/tests/Functional/Fixtures/app/config/config.yml index 86ddcc3d..48e6853e 100644 --- a/tests/Functional/Fixtures/app/config/config.yml +++ b/tests/Functional/Fixtures/app/config/config.yml @@ -2,7 +2,6 @@ framework: secret: fos router: resource: "%kernel.project_dir%/tests/Functional/Fixtures/app/config/routing.yml" - annotations: ~ test: ~ fos_http_cache: diff --git a/tests/Functional/Fixtures/app/config/config_servers_from_env.yml b/tests/Functional/Fixtures/app/config/config_servers_from_env.yml index 1d6b1ebb..966f6587 100644 --- a/tests/Functional/Fixtures/app/config/config_servers_from_env.yml +++ b/tests/Functional/Fixtures/app/config/config_servers_from_env.yml @@ -2,7 +2,6 @@ framework: secret: fos router: resource: "%kernel.project_dir%/tests/Functional/Fixtures/app/config/routing.yml" - annotations: ~ test: ~ fos_http_cache: diff --git a/tests/Functional/Fixtures/app/config/routing.yml b/tests/Functional/Fixtures/app/config/routing.yml index 589c088c..a7974171 100644 --- a/tests/Functional/Fixtures/app/config/routing.yml +++ b/tests/Functional/Fixtures/app/config/routing.yml @@ -23,8 +23,8 @@ php8_tag_one: methods: [GET,POST] tag_manual: - path: /tag_manual - controller: tag_controller::manualAction + path: /php8/tag_manual + defaults: { _controller: tag_attribute_controller::manualAction } tag_twig: path: /tag_twig diff --git a/tests/Unit/DependencyInjection/Compiler/TagListenerPassTest.php b/tests/Unit/DependencyInjection/Compiler/TagListenerPassTest.php deleted file mode 100644 index 918cea80..00000000 --- a/tests/Unit/DependencyInjection/Compiler/TagListenerPassTest.php +++ /dev/null @@ -1,63 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace FOS\HttpCacheBundle\Tests\Unit\DependencyInjection\Compiler; - -use FOS\HttpCacheBundle\DependencyInjection\Compiler\TagListenerPass; -use FOS\HttpCacheBundle\DependencyInjection\FOSHttpCacheExtension; -use Mockery\Adapter\Phpunit\MockeryPHPUnitIntegration; -use PHPUnit\Framework\TestCase; -use Symfony\Component\DependencyInjection\ContainerBuilder; -use Symfony\Component\DependencyInjection\ParameterBag\ParameterBag; - -class TagListenerPassTest extends TestCase -{ - use MockeryPHPUnitIntegration; - - public function testNoFrameworkBundle() - { - $this->expectException(\RuntimeException::class); - $this->expectExceptionMessage('require the SensioFrameworkExtraBundle'); - - $extension = new FOSHttpCacheExtension(); - $tagListenerPass = new TagListenerPass(); - $container = $this->createContainer(); - $config = $this->getConfig(); - $extension->load([$config], $container); - $tagListenerPass->process($container); - } - - protected function createContainer() - { - return new ContainerBuilder(new ParameterBag([ - 'kernel.debug' => false, - ])); - } - - protected function getConfig() - { - return [ - 'proxy_client' => [ - 'varnish' => [ - 'http' => [ - 'base_url' => 'my_hostname', - 'servers' => [ - '127.0.0.1', - ], - ], - ], - ], - 'tags' => [ - 'enabled' => true, - ], - ]; - } -} diff --git a/tests/Unit/EventListener/CacheControlListenerTest.php b/tests/Unit/EventListener/CacheControlListenerTest.php index e50534f5..d1078fed 100755 --- a/tests/Unit/EventListener/CacheControlListenerTest.php +++ b/tests/Unit/EventListener/CacheControlListenerTest.php @@ -425,7 +425,7 @@ protected function buildEvent(string $method = 'GET'): CacheControlResponseEvent $request = new Request(); $request->setMethod($method); - return new CacheControlResponseEvent($kernel, $request, HttpKernelInterface::MASTER_REQUEST, $response); + return new CacheControlResponseEvent($kernel, $request, HttpKernelInterface::MAIN_REQUEST, $response); } /** diff --git a/tests/Unit/EventListener/InvalidationListenerTest.php b/tests/Unit/EventListener/InvalidationListenerTest.php index f245ee29..0623bb80 100644 --- a/tests/Unit/EventListener/InvalidationListenerTest.php +++ b/tests/Unit/EventListener/InvalidationListenerTest.php @@ -22,7 +22,7 @@ use Symfony\Component\Console\Event\ConsoleEvent; use Symfony\Component\Console\Output\OutputInterface; use Symfony\Component\HttpFoundation\Request; -use Symfony\Component\HttpFoundation\RequestMatcher; +use Symfony\Component\HttpFoundation\RequestMatcher\AttributesRequestMatcher; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpKernel\Event\PostResponseEvent; use Symfony\Component\HttpKernel\Event\TerminateEvent; @@ -116,11 +116,7 @@ public function testOnKernelTerminate() ->andReturn('/retrieve/something/123/bla') ->getMock(); - $requestMatcher = new RequestMatcher( - null, - null, - null, - null, + $requestMatcher = new AttributesRequestMatcher( ['_route' => 'route_invalidator'] ); diff --git a/tests/Unit/EventListener/TagListenerTest.php b/tests/Unit/EventListener/TagListenerTest.php index 47d33afa..af623a69 100644 --- a/tests/Unit/EventListener/TagListenerTest.php +++ b/tests/Unit/EventListener/TagListenerTest.php @@ -210,7 +210,7 @@ private function getEvent(Request $request, Response $response = null): TagRespo return new TagResponseEvent( \Mockery::mock(HttpKernelInterface::class), $request, - HttpKernelInterface::MASTER_REQUEST, + HttpKernelInterface::MAIN_REQUEST, $response ?: new Response() ); } diff --git a/tests/Unit/EventListener/UserContextListenerTest.php b/tests/Unit/EventListener/UserContextListenerTest.php index 041322bf..e25b036e 100644 --- a/tests/Unit/EventListener/UserContextListenerTest.php +++ b/tests/Unit/EventListener/UserContextListenerTest.php @@ -565,7 +565,7 @@ public function testFullRequestHashChanged() $this->assertEquals('max-age=0, no-cache, no-store, private, s-maxage=0', $event->getResponse()->headers->get('Cache-Control')); } - protected function getKernelRequestEvent(Request $request, $type = HttpKernelInterface::MASTER_REQUEST): UserContextRequestEvent + protected function getKernelRequestEvent(Request $request, $type = HttpKernelInterface::MAIN_REQUEST): UserContextRequestEvent { return new UserContextRequestEvent( \Mockery::mock(HttpKernelInterface::class), @@ -574,7 +574,7 @@ protected function getKernelRequestEvent(Request $request, $type = HttpKernelInt ); } - protected function getKernelResponseEvent(Request $request, Response $response = null, $type = HttpKernelInterface::MASTER_REQUEST): UserContextResponseEvent + protected function getKernelResponseEvent(Request $request, Response $response = null, $type = HttpKernelInterface::MAIN_REQUEST): UserContextResponseEvent { return new UserContextResponseEvent( \Mockery::mock(HttpKernelInterface::class), diff --git a/tests/Unit/Http/RuleMatcherTest.php b/tests/Unit/Http/RuleMatcherTest.php index 4bd49a5b..29923f8f 100644 --- a/tests/Unit/Http/RuleMatcherTest.php +++ b/tests/Unit/Http/RuleMatcherTest.php @@ -15,14 +15,15 @@ use FOS\HttpCacheBundle\Http\RuleMatcher; use PHPUnit\Framework\TestCase; use Symfony\Component\HttpFoundation\Request; -use Symfony\Component\HttpFoundation\RequestMatcher; +use Symfony\Component\HttpFoundation\RequestMatcher\AttributesRequestMatcher; +use Symfony\Component\HttpFoundation\RequestMatcherInterface; use Symfony\Component\HttpFoundation\Response; class RuleMatcherTest extends TestCase { public function testRequestMatcherCalled() { - $requestMatcher = new RequestMatcher(null, null, null, null, ['_controller' => '^AcmeBundle:Default:index$']); + $requestMatcher = new AttributesRequestMatcher(['_controller' => '^AcmeBundle:Default:index$']); $ruleMatcher = new RuleMatcher($requestMatcher); $request = new Request(); @@ -33,7 +34,7 @@ public function testRequestMatcherCalled() public function testAdditionalCacheableStatus() { - $ruleMatcher = new RuleMatcher(new RequestMatcher(), new CacheableResponseMatcher([400, 500])); + $ruleMatcher = new RuleMatcher(new AttributesRequestMatcher([]), new CacheableResponseMatcher([400, 500])); $this->assertFalse($ruleMatcher->matches(new Request(), new Response('', 504))); $this->assertTrue($ruleMatcher->matches(new Request(), new Response('', 500)));