diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon index 3f9b554..8108008 100644 --- a/phpstan-baseline.neon +++ b/phpstan-baseline.neon @@ -6,30 +6,6 @@ parameters: count: 1 path: spec/EventSubscriber/HiddenLocationExceptionSubscriberSpec.php - - - message: '#^Call to an undefined method Ibexa\\Contracts\\Core\\Repository\\Values\\Content\\ContentInfo\:\:willReturn\(\)\.$#' - identifier: method.notFound - count: 1 - path: spec/EventSubscriber/HiddenLocationExceptionSubscriberSpec.php - - - - message: '#^Call to an undefined method Ibexa\\Contracts\\Core\\Repository\\Values\\Content\\Location\:\:shouldHaveBeenCalled\(\)\.$#' - identifier: method.notFound - count: 1 - path: spec/EventSubscriber/HiddenLocationExceptionSubscriberSpec.php - - - - message: '#^Call to an undefined method Ibexa\\Contracts\\Core\\Repository\\Values\\Content\\Location\:\:willReturn\(\)\.$#' - identifier: method.notFound - count: 1 - path: spec/EventSubscriber/HiddenLocationExceptionSubscriberSpec.php - - - - message: '#^Call to an undefined method Ibexa\\Core\\MVC\\Exception\\HiddenLocationException\:\:getWrappedObject\(\)\.$#' - identifier: method.notFound - count: 1 - path: spec/EventSubscriber/HiddenLocationExceptionSubscriberSpec.php - - message: '#^Call to an undefined method Symfony\\Component\\HttpFoundation\\Request\:\:getWrappedObject\(\)\.$#' identifier: method.notFound diff --git a/spec/EventSubscriber/HiddenLocationExceptionSubscriberSpec.php b/spec/EventSubscriber/HiddenLocationExceptionSubscriberSpec.php index 0a89df8..1ebacb3 100644 --- a/spec/EventSubscriber/HiddenLocationExceptionSubscriberSpec.php +++ b/spec/EventSubscriber/HiddenLocationExceptionSubscriberSpec.php @@ -7,61 +7,74 @@ namespace spec\Ibexa\HttpCache\EventSubscriber; -use Ibexa\Contracts\Core\Repository\Values\Content\ContentInfo; -use Ibexa\Contracts\Core\Repository\Values\Content\Location; +use FOS\HttpCache\ResponseTagger as FosResponseTagger; use Ibexa\Core\MVC\Exception\HiddenLocationException; +use Ibexa\Core\Repository\Values\Content\Location; +use Ibexa\Contracts\Core\Repository\Values\Content\ContentInfo; use Ibexa\HttpCache\ResponseTagger\Value\ContentInfoTagger; use Ibexa\HttpCache\ResponseTagger\Value\LocationTagger; +use PhpSpec\Exception\Example\FailureException; use PhpSpec\ObjectBehavior; -use Prophecy\Argument; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpKernel\Event\ExceptionEvent; use Symfony\Component\HttpKernel\HttpKernelInterface; class HiddenLocationExceptionSubscriberSpec extends ObjectBehavior { - public function let( - LocationTagger $locationTagger, - ContentInfoTagger $contentInfoTagger - ): void { - $this->beConstructedWith($locationTagger, $contentInfoTagger); - } - public function it_tags_on_hidden_location_exception( HttpKernelInterface $kernel, - Request $request, - LocationTagger $locationTagger, - ContentInfoTagger $contentInfoTagger, - Location $location, - ContentInfo $contentInfo, - HiddenLocationException $exception + Request $request ): void { - $exception->getLocation()->willReturn($location); - $location->getContentInfo()->willReturn($contentInfo); - $locationTagger->tag($location)->willReturn($locationTagger); - $contentInfoTagger->tag($contentInfo)->willReturn($contentInfoTagger); + $locationResponseTagger = new FosResponseTagger(); + $contentInfoResponseTagger = new FosResponseTagger(); + $this->beConstructedWith( + new LocationTagger($locationResponseTagger), + new ContentInfoTagger($contentInfoResponseTagger) + ); + + $contentInfo = new ContentInfo([ + 'id' => 321, + 'contentTypeId' => 987, + 'mainLocationId' => null, + ]); + $location = new Location([ + 'id' => 123, + 'parentLocationId' => 2, + 'pathString' => '/1/2/123/', + 'contentInfo' => $contentInfo, + ]); + $exception = new HiddenLocationException($location); $event = new ExceptionEvent( $kernel->getWrappedObject(), $request->getWrappedObject(), HttpKernelInterface::MAIN_REQUEST, - $exception->getWrappedObject() + $exception ); $this->tagHiddenLocationExceptionResponse($event); - $exception->getLocation()->shouldHaveBeenCalled(); - $locationTagger->tag(Argument::type(Location::class))->shouldHaveBeenCalled(); - $contentInfoTagger->tag(Argument::type(ContentInfo::class))->shouldHaveBeenCalled(); + if (!$locationResponseTagger->hasTags()) { + throw new FailureException('LocationTagger did not add any tags.'); + } + + if (!$contentInfoResponseTagger->hasTags()) { + throw new FailureException('ContentInfoTagger did not add any tags.'); + } } public function it_does_not_tag_on_other_exceptions( HttpKernelInterface $kernel, Request $request, - LocationTagger $locationTagger, - ContentInfoTagger $contentInfoTagger, \Exception $exception ): void { + $locationResponseTagger = new FosResponseTagger(); + $contentInfoResponseTagger = new FosResponseTagger(); + $this->beConstructedWith( + new LocationTagger($locationResponseTagger), + new ContentInfoTagger($contentInfoResponseTagger) + ); + $event = new ExceptionEvent( $kernel->getWrappedObject(), $request->getWrappedObject(), @@ -69,9 +82,14 @@ public function it_does_not_tag_on_other_exceptions( $exception->getWrappedObject() ); - $locationTagger->tag(Argument::type(Location::class))->shouldNotBeCalled(); - $contentInfoTagger->tag(Argument::type(ContentInfo::class))->shouldNotBeCalled(); - $this->tagHiddenLocationExceptionResponse($event); + + if ($locationResponseTagger->hasTags()) { + throw new FailureException('LocationTagger should not add tags for unrelated exceptions.'); + } + + if ($contentInfoResponseTagger->hasTags()) { + throw new FailureException('ContentInfoTagger should not add tags for unrelated exceptions.'); + } } } diff --git a/src/contracts/ResponseTagger/ResponseTagger.php b/src/contracts/ResponseTagger/ResponseTagger.php index dcda090..9562dbd 100644 --- a/src/contracts/ResponseTagger/ResponseTagger.php +++ b/src/contracts/ResponseTagger/ResponseTagger.php @@ -13,6 +13,8 @@ */ interface ResponseTagger { + public function supports(mixed $value): bool; + /** * Extracts tags from a value. * diff --git a/src/lib/ResponseTagger/Delegator/ContentValueViewTagger.php b/src/lib/ResponseTagger/Delegator/ContentValueViewTagger.php index 5461eb1..7910838 100644 --- a/src/lib/ResponseTagger/Delegator/ContentValueViewTagger.php +++ b/src/lib/ResponseTagger/Delegator/ContentValueViewTagger.php @@ -11,9 +11,8 @@ use Ibexa\Contracts\Core\Repository\Values\Content\Content; use Ibexa\Contracts\HttpCache\ResponseTagger\ResponseTagger; use Ibexa\Core\MVC\Symfony\View\ContentValueView; -use Ibexa\HttpCache\ResponseTagger\Value\AbstractValueTagger; -class ContentValueViewTagger extends AbstractValueTagger +final readonly class ContentValueViewTagger implements ResponseTagger { public function __construct(private readonly ResponseTagger $contentInfoTagger) { diff --git a/src/lib/ResponseTagger/Delegator/DispatcherTagger.php b/src/lib/ResponseTagger/Delegator/DispatcherTagger.php index 5bcd298..d6499c4 100644 --- a/src/lib/ResponseTagger/Delegator/DispatcherTagger.php +++ b/src/lib/ResponseTagger/Delegator/DispatcherTagger.php @@ -21,20 +21,15 @@ public function __construct(private iterable $taggers = []) { } + public function supports(mixed $value): bool + { + return true; + } + public function tag(mixed $value): void { foreach ($this->taggers as $tagger) { - if (method_exists($tagger, 'supports')) { - if ($tagger->supports($value)) { - $tagger->tag($value); - } - } else { - trigger_deprecation( - 'ibexa/http-cache', - '5.0.7', - '%s does not implement supports(). This will be required in 6.0, supports() will be a part of ResponseTagger interface', - get_debug_type($tagger), - ); + if ($tagger->supports($value)) { $tagger->tag($value); } } diff --git a/src/lib/ResponseTagger/Delegator/LocationValueViewTagger.php b/src/lib/ResponseTagger/Delegator/LocationValueViewTagger.php index 0ef8b3b..11bdfdb 100644 --- a/src/lib/ResponseTagger/Delegator/LocationValueViewTagger.php +++ b/src/lib/ResponseTagger/Delegator/LocationValueViewTagger.php @@ -11,9 +11,8 @@ use Ibexa\Contracts\Core\Repository\Values\Content\Location; use Ibexa\Contracts\HttpCache\ResponseTagger\ResponseTagger; use Ibexa\Core\MVC\Symfony\View\LocationValueView; -use Ibexa\HttpCache\ResponseTagger\Value\AbstractValueTagger; -class LocationValueViewTagger extends AbstractValueTagger +final readonly class LocationValueViewTagger implements ResponseTagger { public function __construct(private readonly ResponseTagger $locationTagger) { diff --git a/src/lib/ResponseTagger/Value/AbstractValueTagger.php b/src/lib/ResponseTagger/Value/AbstractValueTagger.php deleted file mode 100644 index 89b722b..0000000 --- a/src/lib/ResponseTagger/Value/AbstractValueTagger.php +++ /dev/null @@ -1,21 +0,0 @@ - 1, 'contentTypeId' => 2]); - $contentInfoTagger = $this->createMock(ContentInfoTagger::class); - $locationTagger = $this->createMock(LocationTagger::class); + $contentInfoTagger = $this->createMock(ResponseTagger::class); + $locationTagger = $this->createMock(ResponseTagger::class); $contentInfoTagger ->method('supports') @@ -55,8 +55,8 @@ public function testDoesNotCallTagWhenNoTaggerSupportsTheValue(): void { $location = new Location(['id' => 1]); - $contentInfoTagger = $this->createMock(ContentInfoTagger::class); - $locationTagger = $this->createMock(LocationTagger::class); + $contentInfoTagger = $this->createMock(ResponseTagger::class); + $locationTagger = $this->createMock(ResponseTagger::class); $contentInfoTagger ->expects(self::once()) @@ -82,11 +82,11 @@ public function testDoesNotCallTagWhenNoTaggerSupportsTheValue(): void $dispatcher->tag($location); } - public function testCustomResponseTaggerImplementationLackingSupportsMethodShouldTag(): void + public function testCallsCustomResponseTaggerWhenItSupportsTheValue(): void { $foo = new stdClass(); - $contentInfoTagger = $this->createMock(ContentInfoTagger::class); + $contentInfoTagger = $this->createMock(ResponseTagger::class); $contentInfoTagger ->expects(self::once()) ->method('supports') @@ -103,6 +103,11 @@ public function __construct(private bool &$wasCalled) { } + public function supports(mixed $value): bool + { + return true; + } + public function tag(mixed $value): void { $this->wasCalled = true; @@ -111,23 +116,8 @@ public function tag(mixed $value): void $dispatcher = new DispatcherTagger([$contentInfoTagger, $customTagger]); - $deprecation = null; - set_error_handler(static function (int $errorCode, string $errorString) use (&$deprecation): bool { - if ($errorCode === E_USER_DEPRECATED) { - $deprecation = $errorString; - } - - return true; - }); - - try { - $dispatcher->tag($foo); - } finally { - restore_error_handler(); - } - + $dispatcher->tag($foo); self::assertTrue($wasCalled, 'Custom ResponseTagger::tag() was not called by the dispatcher.'); - self::assertStringContainsString('does not implement supports()', $deprecation); } public function testToStringWithNoTaggers(): void