diff --git a/CHANGELOG.md b/CHANGELOG.md index 8e67085d..bfad835a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -21,6 +21,8 @@ * fix [Flasher] Add error handling for invalid regex patterns in ResponseExtension::isPathExcluded() * fix [Flasher] Fix ContentSecurityPolicyHandler parsing of CSP headers with trailing semicolons creating empty directive keys * fix [Flasher] Add reset() method to ContentSecurityPolicyHandler to fix CSP state leak in long-running processes (Octane, FrankenPHP) +* fix [Flasher] Fix FilterEvent::setFilter() type inconsistency - now accepts FilterInterface instead of concrete Filter class +* fix [Flasher] Remove redundant callable check in FlasherContainer::getContainer() ## [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/Container/FlasherContainer.php b/src/Prime/Container/FlasherContainer.php index ab2cbcd8..63ef6464 100644 --- a/src/Prime/Container/FlasherContainer.php +++ b/src/Prime/Container/FlasherContainer.php @@ -61,7 +61,7 @@ final class FlasherContainer { $container = self::getInstance()->container; - $resolved = $container instanceof \Closure || \is_callable($container) ? $container() : $container; + $resolved = $container instanceof \Closure ? $container() : $container; if (!$resolved instanceof ContainerInterface) { throw new \InvalidArgumentException(\sprintf('Expected an instance of "%s", got "%s".', ContainerInterface::class, get_debug_type($resolved))); diff --git a/src/Prime/EventDispatcher/Event/FilterEvent.php b/src/Prime/EventDispatcher/Event/FilterEvent.php index 7b7b5fcf..4e7ec0ac 100644 --- a/src/Prime/EventDispatcher/Event/FilterEvent.php +++ b/src/Prime/EventDispatcher/Event/FilterEvent.php @@ -5,7 +5,6 @@ declare(strict_types=1); namespace Flasher\Prime\EventDispatcher\Event; use Flasher\Prime\Notification\Envelope; -use Flasher\Prime\Storage\Filter\Filter; use Flasher\Prime\Storage\Filter\FilterInterface; final class FilterEvent @@ -26,7 +25,7 @@ final class FilterEvent return $this->filter; } - public function setFilter(Filter $filter): void + public function setFilter(FilterInterface $filter): void { $this->filter = $filter; } diff --git a/tests/Prime/Container/FlasherContainerTest.php b/tests/Prime/Container/FlasherContainerTest.php index 123487ca..4087fdb5 100644 --- a/tests/Prime/Container/FlasherContainerTest.php +++ b/tests/Prime/Container/FlasherContainerTest.php @@ -71,4 +71,49 @@ final class FlasherContainerTest extends TestCase FlasherContainer::create('flasher'); } + + public function testFromWithClosureResolvesContainer(): void + { + $flasher = $this->createMock(FlasherInterface::class); + + $container = $this->createMock(ContainerInterface::class); + $container->method('has')->willReturn(true); + $container->method('get')->willReturn($flasher); + + // Pass a closure that returns the container + FlasherContainer::from(fn () => $container); + + $this->assertInstanceOf(FlasherInterface::class, FlasherContainer::create('flasher')); + } + + public function testFromWithClosureReturningInvalidTypeThrowsException(): void + { + // Pass a closure that returns something other than ContainerInterface + FlasherContainer::from(fn () => 'not a container'); + + $this->expectException(\InvalidArgumentException::class); + $this->expectExceptionMessage('Expected an instance of "Psr\Container\ContainerInterface"'); + + FlasherContainer::getContainer(); + } + + public function testHasReturnsTrueForExistingService(): void + { + $container = $this->createMock(ContainerInterface::class); + $container->method('has')->with('flasher')->willReturn(true); + + FlasherContainer::from($container); + + $this->assertTrue(FlasherContainer::has('flasher')); + } + + public function testHasReturnsFalseForNonExistingService(): void + { + $container = $this->createMock(ContainerInterface::class); + $container->method('has')->with('nonexistent')->willReturn(false); + + FlasherContainer::from($container); + + $this->assertFalse(FlasherContainer::has('nonexistent')); + } } diff --git a/tests/Prime/EventDispatcher/Event/FilterEventTest.php b/tests/Prime/EventDispatcher/Event/FilterEventTest.php index adf25620..4bb168db 100644 --- a/tests/Prime/EventDispatcher/Event/FilterEventTest.php +++ b/tests/Prime/EventDispatcher/Event/FilterEventTest.php @@ -8,6 +8,7 @@ use Flasher\Prime\EventDispatcher\Event\FilterEvent; use Flasher\Prime\Notification\Envelope; use Flasher\Prime\Notification\Notification; use Flasher\Prime\Storage\Filter\Filter; +use Flasher\Prime\Storage\Filter\FilterInterface; use PHPUnit\Framework\TestCase; final class FilterEventTest extends TestCase @@ -141,4 +142,31 @@ final class FilterEventTest extends TestCase $this->assertSame('Second', $retrievedEnvelopes[1]->getMessage()); $this->assertSame('Third', $retrievedEnvelopes[2]->getMessage()); } + + public function testSetFilterAcceptsFilterInterface(): void + { + $originalFilter = new Filter(); + $event = new FilterEvent($originalFilter, [], []); + + // Create a mock that implements FilterInterface + $mockFilter = $this->createMock(FilterInterface::class); + + // setFilter should accept any FilterInterface implementation + $event->setFilter($mockFilter); + + $this->assertSame($mockFilter, $event->getFilter()); + } + + public function testConstructorAcceptsFilterInterface(): void + { + $mockFilter = $this->createMock(FilterInterface::class); + $envelopes = [new Envelope(new Notification())]; + $criteria = ['limit' => 5]; + + $event = new FilterEvent($mockFilter, $envelopes, $criteria); + + $this->assertSame($mockFilter, $event->getFilter()); + $this->assertSame($envelopes, $event->getEnvelopes()); + $this->assertSame($criteria, $event->getCriteria()); + } }