From 1aad2ca08f5c8a2b104b924de9d2e23256d6698c Mon Sep 17 00:00:00 2001 From: Sergei Predvoditelev Date: Fri, 13 Mar 2026 14:50:39 +0300 Subject: [PATCH 1/2] Add `QueueFactoryProvider` --- src/Provider/QueueFactoryProvider.php | 100 +++++++++++ .../Provider/QueueFactoryProviderTest.php | 156 ++++++++++++++++++ 2 files changed, 256 insertions(+) create mode 100644 src/Provider/QueueFactoryProvider.php create mode 100644 tests/Unit/Provider/QueueFactoryProviderTest.php diff --git a/src/Provider/QueueFactoryProvider.php b/src/Provider/QueueFactoryProvider.php new file mode 100644 index 00000000..b73abfb9 --- /dev/null +++ b/src/Provider/QueueFactoryProvider.php @@ -0,0 +1,100 @@ + + */ + private array $queues = []; + + private readonly StrictFactory $factory; + + /** + * @param array $definitions Queue definitions indexed by queue names. + * @param ContainerInterface|null $container Container to use for dependencies resolving. + * @param bool $validate If definitions should be validated when set. + * + * @psalm-param array $definitions + * + * @throws InvalidQueueConfigException + */ + public function __construct( + array $definitions, + ?ContainerInterface $container = null, + bool $validate = true, + ) { + try { + $this->factory = new StrictFactory($definitions, $container, $validate); + } catch (InvalidConfigException $exception) { + throw new InvalidQueueConfigException($exception->getMessage(), previous: $exception); + } + } + + public function get(string|BackedEnum $name): QueueInterface + { + $name = StringNormalizer::normalize($name); + + $queue = $this->getOrTryToCreate($name); + if ($queue === null) { + throw new QueueNotFoundException($name); + } + + return $queue; + } + + public function has(string|BackedEnum $name): bool + { + $name = StringNormalizer::normalize($name); + return $this->factory->has($name); + } + + /** + * @throws InvalidConfigException + */ + private function getOrTryToCreate(string $name): ?QueueInterface + { + if (array_key_exists($name, $this->queues)) { + return $this->queues[$name]; + } + + if (!$this->factory->has($name)) { + $this->queues[$name] = null; + return null; + } + + $queue = $this->factory->create($name); + if (!$queue instanceof QueueInterface) { + throw new InvalidQueueConfigException( + sprintf( + 'Queue must implement "%s". For queue "%s" got "%s" instead.', + QueueInterface::class, + $name, + get_debug_type($queue), + ), + ); + } + + $this->queues[$name] = $queue; + return $queue; + } +} diff --git a/tests/Unit/Provider/QueueFactoryProviderTest.php b/tests/Unit/Provider/QueueFactoryProviderTest.php new file mode 100644 index 00000000..488a901c --- /dev/null +++ b/tests/Unit/Provider/QueueFactoryProviderTest.php @@ -0,0 +1,156 @@ + StubQueue::class, + ], + ); + + $queue = $provider->get('queue1'); + + $this->assertInstanceOf(StubQueue::class, $queue); + $this->assertTrue($provider->has('queue1')); + $this->assertFalse($provider->has('not-exist-queue')); + } + + public function testGetTwice(): void + { + $provider = new QueueFactoryProvider( + [ + 'queue1' => StubQueue::class, + ], + ); + + $queue1 = $provider->get('queue1'); + $queue2 = $provider->get('queue1'); + + $this->assertSame($queue1, $queue2); + } + + public function testGetNotExistQueue(): void + { + $provider = new QueueFactoryProvider( + [ + 'queue1' => StubQueue::class, + ], + ); + + $this->expectException(QueueNotFoundException::class); + $this->expectExceptionMessage('Queue with name "not-exist-queue" not found.'); + $provider->get('not-exist-queue'); + } + + public function testInvalidQueueConfig(): void + { + $definitions = [ + 'queue1' => [ + 'class' => StubQueue::class, + '__construct()' => 'hello', + ], + ]; + + $this->expectException(InvalidQueueConfigException::class); + $this->expectExceptionMessage( + 'Invalid definition: incorrect constructor arguments. Expected array, got string.', + ); + new QueueFactoryProvider($definitions); + } + + public function testInvalidQueueConfigOnGet(): void + { + $provider = new QueueFactoryProvider( + [ + 'queue1' => StubLoop::class, + ], + ); + + $this->expectException(InvalidQueueConfigException::class); + $this->expectExceptionMessage( + sprintf( + 'Queue must implement "%s". For queue "%s" got "%s" instead.', + QueueInterface::class, + 'queue1', + StubLoop::class, + ), + ); + $provider->get('queue1'); + } + + public function testGetHasByStringEnum(): void + { + $provider = new QueueFactoryProvider( + [ + 'red' => StubQueue::class, + ], + ); + + $queue = $provider->get(StringEnum::RED); + + $this->assertInstanceOf(StubQueue::class, $queue); + $this->assertTrue($provider->has(StringEnum::RED)); + $this->assertFalse($provider->has(StringEnum::GREEN)); + } + + public function testWithContainer(): void + { + $adapter = new StubAdapter(); + $container = new SimpleContainer([ + AdapterInterface::class => $adapter, + ]); + + $provider = new QueueFactoryProvider( + [ + 'queue1' => [ + 'class' => StubQueue::class, + '__construct()' => [ + 'adapter' => Reference::to(AdapterInterface::class), + ], + ], + ], + $container, + ); + + $queue = $provider->get('queue1'); + + $this->assertInstanceOf(StubQueue::class, $queue); + $this->assertSame($adapter, $queue->getAdapter()); + } + + public function testValidateFalse(): void + { + $provider = new QueueFactoryProvider( + [ + 'queue1' => [ + 'class' => StubQueue::class, + '__construct()' => 'hello', + ], + ], + validate: false, + ); + + $this->assertTrue($provider->has('queue1')); + } +} From 8243b6e6debaed3cf2389a4f2a4907152e238b84 Mon Sep 17 00:00:00 2001 From: Sergei Predvoditelev Date: Fri, 13 Mar 2026 15:06:45 +0300 Subject: [PATCH 2/2] Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- src/Provider/QueueFactoryProvider.php | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/Provider/QueueFactoryProvider.php b/src/Provider/QueueFactoryProvider.php index b73abfb9..762cf554 100644 --- a/src/Provider/QueueFactoryProvider.php +++ b/src/Provider/QueueFactoryProvider.php @@ -69,7 +69,7 @@ public function has(string|BackedEnum $name): bool } /** - * @throws InvalidConfigException + * @throws InvalidQueueConfigException */ private function getOrTryToCreate(string $name): ?QueueInterface { @@ -82,7 +82,12 @@ private function getOrTryToCreate(string $name): ?QueueInterface return null; } - $queue = $this->factory->create($name); + try { + $queue = $this->factory->create($name); + } catch (InvalidConfigException $exception) { + throw new InvalidQueueConfigException($exception->getMessage(), previous: $exception); + } + if (!$queue instanceof QueueInterface) { throw new InvalidQueueConfigException( sprintf(