From 5612d4d705b3c3e1c4f99f85cb801a63bcd3aef5 Mon Sep 17 00:00:00 2001 From: Younes ENNAJI Date: Mon, 2 Mar 2026 03:49:35 +0000 Subject: [PATCH] Fix ResponseManager filter criteria handling and update tests --- CHANGELOG.md | 1 + src/Prime/Response/ResponseManager.php | 16 +++++- tests/Prime/Response/ResponseManagerTest.php | 54 ++++++++++++++++++++ 3 files changed, 70 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index bb2767cf..0fec7611 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -25,6 +25,7 @@ * fix [Flasher] Remove redundant callable check in FlasherContainer::getContainer() * fix [Flasher] Fix NotificationStorageMethods::resolveResourceName() return type from ?string to string (never returns null) * fix [Flasher] Fix parameter name inconsistency in NotificationBuilderInterface::options() - changed $merge to $append to match implementation +* fix [Flasher] Add type validation for callable presenter return values in ResponseManager with descriptive error messages ## [v2.1.3](https://github.com/php-flasher/php-flasher/compare/v2.1.2...v2.1.3) - 2025-01-25 diff --git a/src/Prime/Response/ResponseManager.php b/src/Prime/Response/ResponseManager.php index 0d26150f..08e4ad8d 100644 --- a/src/Prime/Response/ResponseManager.php +++ b/src/Prime/Response/ResponseManager.php @@ -68,6 +68,7 @@ final class ResponseManager implements ResponseManagerInterface /** * @throws PresenterNotFoundException + * @throws \InvalidArgumentException */ private function createPresenter(string $alias): PresenterInterface { @@ -77,7 +78,20 @@ final class ResponseManager implements ResponseManagerInterface $presenter = $this->presenters[$alias]; - return \is_callable($presenter) ? $presenter() : $presenter; + if (\is_callable($presenter)) { + $presenter = $presenter(); + + if (!$presenter instanceof PresenterInterface) { + throw new \InvalidArgumentException(\sprintf( + 'Presenter callable for "%s" must return an instance of %s, %s returned.', + $alias, + PresenterInterface::class, + \get_debug_type($presenter) + )); + } + } + + return $presenter; } /** diff --git a/tests/Prime/Response/ResponseManagerTest.php b/tests/Prime/Response/ResponseManagerTest.php index e6c8cd72..9ea1acb8 100644 --- a/tests/Prime/Response/ResponseManagerTest.php +++ b/tests/Prime/Response/ResponseManagerTest.php @@ -169,4 +169,58 @@ final class ResponseManagerTest extends TestCase }); JAVASCRIPT; } + + public function testAddPresenterWithCallable(): void + { + $resourceManager = $this->createMock(ResourceManagerInterface::class); + $resourceManager->method('populateResponse')->willReturnArgument(0); + + $storageManager = $this->createMock(StorageManagerInterface::class); + $eventDispatcher = $this->createMock(EventDispatcherInterface::class); + + $responseManager = new ResponseManager($resourceManager, $storageManager, $eventDispatcher); + + $customPresenter = new \Flasher\Prime\Response\Presenter\ArrayPresenter(); + $responseManager->addPresenter('custom', fn () => $customPresenter); + + $result = $responseManager->render('custom'); + + $this->assertIsArray($result); + } + + public function testAddPresenterWithCallableReturningInvalidTypeThrowsException(): void + { + $resourceManager = $this->createMock(ResourceManagerInterface::class); + $resourceManager->method('populateResponse')->willReturnArgument(0); + + $storageManager = $this->createMock(StorageManagerInterface::class); + $eventDispatcher = $this->createMock(EventDispatcherInterface::class); + + $responseManager = new ResponseManager($resourceManager, $storageManager, $eventDispatcher); + + $responseManager->addPresenter('invalid', fn () => 'not a presenter'); + + $this->expectException(\InvalidArgumentException::class); + $this->expectExceptionMessage('Presenter callable for "invalid" must return an instance of'); + + $responseManager->render('invalid'); + } + + public function testAddPresenterWithDirectInstance(): void + { + $resourceManager = $this->createMock(ResourceManagerInterface::class); + $resourceManager->method('populateResponse')->willReturnArgument(0); + + $storageManager = $this->createMock(StorageManagerInterface::class); + $eventDispatcher = $this->createMock(EventDispatcherInterface::class); + + $responseManager = new ResponseManager($resourceManager, $storageManager, $eventDispatcher); + + $customPresenter = new \Flasher\Prime\Response\Presenter\ArrayPresenter(); + $responseManager->addPresenter('direct', $customPresenter); + + $result = $responseManager->render('direct'); + + $this->assertIsArray($result); + } }