From 4e18f9be7600fc7a644721cb059d16221fa4b92f Mon Sep 17 00:00:00 2001 From: Sergei Predvoditelev Date: Sat, 21 Mar 2026 08:10:00 +0300 Subject: [PATCH 1/4] Introduce `QueueProviderInterface::getNames()` method --- config/di.php | 10 ----- src/Command/ListenAllCommand.php | 3 +- src/Command/RunCommand.php | 3 +- src/Debug/QueueProviderInterfaceProxy.php | 5 +++ src/Provider/AdapterFactoryQueueProvider.php | 12 ++++++ src/Provider/CompositeQueueProvider.php | 13 ++++++ src/Provider/PredefinedQueueProvider.php | 6 +++ src/Provider/QueueFactoryProvider.php | 12 ++++++ src/Provider/QueueProviderInterface.php | 9 ++++ .../Debug/QueueProviderInterfaceProxyTest.php | 10 +++++ .../AdapterFactoryQueueProviderTest.php | 23 +++++++++++ .../Provider/CompositeQueueProviderTest.php | 41 +++++++++++++++++++ .../Provider/PredefinedQueueProviderTest.php | 17 ++++++++ .../Provider/QueueFactoryProviderTest.php | 19 +++++++++ 14 files changed, 169 insertions(+), 14 deletions(-) diff --git a/config/di.php b/config/di.php index 273be5d1..292bdff2 100644 --- a/config/di.php +++ b/config/di.php @@ -59,14 +59,4 @@ '__construct()' => ['middlewareDefinitions' => $params['yiisoft/queue']['middlewares-fail']], ], MessageSerializerInterface::class => JsonMessageSerializer::class, - RunCommand::class => [ - '__construct()' => [ - 'queues' => array_keys($params['yiisoft/queue']['queues']), - ], - ], - ListenAllCommand::class => [ - '__construct()' => [ - 'queues' => array_keys($params['yiisoft/queue']['queues']), - ], - ], ]; diff --git a/src/Command/ListenAllCommand.php b/src/Command/ListenAllCommand.php index 66f88f7c..d3bf3218 100644 --- a/src/Command/ListenAllCommand.php +++ b/src/Command/ListenAllCommand.php @@ -25,7 +25,6 @@ final class ListenAllCommand extends Command public function __construct( private readonly QueueProviderInterface $queueProvider, private readonly LoopInterface $loop, - private readonly array $queues, ) { parent::__construct(); } @@ -39,7 +38,7 @@ public function configure(): void 'queue', InputArgument::OPTIONAL | InputArgument::IS_ARRAY, 'Queue name list to connect to', - $this->queues, + $this->queueProvider->getNames(), ) ->addOption( 'pause', diff --git a/src/Command/RunCommand.php b/src/Command/RunCommand.php index 7f1aeab7..2f2440f9 100644 --- a/src/Command/RunCommand.php +++ b/src/Command/RunCommand.php @@ -20,7 +20,6 @@ final class RunCommand extends Command { public function __construct( private readonly QueueProviderInterface $queueProvider, - private readonly array $queues, ) { parent::__construct(); } @@ -31,7 +30,7 @@ public function configure(): void 'queue', InputArgument::OPTIONAL | InputArgument::IS_ARRAY, 'Queue name list to connect to.', - $this->queues, + $this->queueProvider->getNames(), ) ->addOption( 'maximum', diff --git a/src/Debug/QueueProviderInterfaceProxy.php b/src/Debug/QueueProviderInterfaceProxy.php index b9d40bde..c28d1b20 100644 --- a/src/Debug/QueueProviderInterfaceProxy.php +++ b/src/Debug/QueueProviderInterfaceProxy.php @@ -26,4 +26,9 @@ public function has(string|BackedEnum $name): bool { return $this->queueProvider->has($name); } + + public function getNames(): array + { + return $this->queueProvider->getNames(); + } } diff --git a/src/Provider/AdapterFactoryQueueProvider.php b/src/Provider/AdapterFactoryQueueProvider.php index 9b95475d..11a187fe 100644 --- a/src/Provider/AdapterFactoryQueueProvider.php +++ b/src/Provider/AdapterFactoryQueueProvider.php @@ -13,6 +13,7 @@ use Yiisoft\Queue\QueueInterface; use function array_key_exists; +use function array_keys; use function sprintf; /** @@ -30,6 +31,11 @@ final class AdapterFactoryQueueProvider implements QueueProviderInterface private readonly StrictFactory $factory; + /** + * @psalm-var list + */ + private readonly array $names; + /** * @param QueueInterface $baseQueue Base queue for queues creation. * @param array $definitions Adapter definitions indexed by queue names. @@ -45,6 +51,7 @@ public function __construct( ?ContainerInterface $container = null, bool $validate = true, ) { + $this->names = array_keys($definitions); try { $this->factory = new StrictFactory($definitions, $container, $validate); } catch (InvalidConfigException $exception) { @@ -70,6 +77,11 @@ public function has(string|BackedEnum $name): bool return $this->factory->has($name); } + public function getNames(): array + { + return $this->names; + } + /** * @throws InvalidQueueConfigException */ diff --git a/src/Provider/CompositeQueueProvider.php b/src/Provider/CompositeQueueProvider.php index 8948964e..f46cd0b5 100644 --- a/src/Provider/CompositeQueueProvider.php +++ b/src/Provider/CompositeQueueProvider.php @@ -7,6 +7,10 @@ use BackedEnum; use Yiisoft\Queue\QueueInterface; +use function array_merge; +use function array_unique; +use function array_values; + /** * Composite queue provider. */ @@ -45,4 +49,13 @@ public function has(string|BackedEnum $name): bool } return false; } + + public function getNames(): array + { + $names = []; + foreach ($this->providers as $provider) { + $names[] = $provider->getNames(); + } + return array_values(array_unique(array_merge(...$names))); + } } diff --git a/src/Provider/PredefinedQueueProvider.php b/src/Provider/PredefinedQueueProvider.php index 91f26acc..b11dbed4 100644 --- a/src/Provider/PredefinedQueueProvider.php +++ b/src/Provider/PredefinedQueueProvider.php @@ -9,6 +9,7 @@ use Yiisoft\Queue\StringNormalizer; use function array_key_exists; +use function array_keys; use function get_debug_type; use function sprintf; @@ -62,4 +63,9 @@ public function has(string|BackedEnum $name): bool $name = StringNormalizer::normalize($name); return array_key_exists($name, $this->queues); } + + public function getNames(): array + { + return array_keys($this->queues); + } } diff --git a/src/Provider/QueueFactoryProvider.php b/src/Provider/QueueFactoryProvider.php index 762cf554..554c2b64 100644 --- a/src/Provider/QueueFactoryProvider.php +++ b/src/Provider/QueueFactoryProvider.php @@ -12,6 +12,7 @@ use Yiisoft\Queue\StringNormalizer; use function array_key_exists; +use function array_keys; use function sprintf; /** @@ -29,6 +30,11 @@ final class QueueFactoryProvider implements QueueProviderInterface private readonly StrictFactory $factory; + /** + * @psalm-var list + */ + private readonly array $names; + /** * @param array $definitions Queue definitions indexed by queue names. * @param ContainerInterface|null $container Container to use for dependencies resolving. @@ -43,6 +49,7 @@ public function __construct( ?ContainerInterface $container = null, bool $validate = true, ) { + $this->names = array_keys($definitions); try { $this->factory = new StrictFactory($definitions, $container, $validate); } catch (InvalidConfigException $exception) { @@ -68,6 +75,11 @@ public function has(string|BackedEnum $name): bool return $this->factory->has($name); } + public function getNames(): array + { + return $this->names; + } + /** * @throws InvalidQueueConfigException */ diff --git a/src/Provider/QueueProviderInterface.php b/src/Provider/QueueProviderInterface.php index e3d35c1a..e3c25929 100644 --- a/src/Provider/QueueProviderInterface.php +++ b/src/Provider/QueueProviderInterface.php @@ -35,4 +35,13 @@ public function get(string|BackedEnum $name): QueueInterface; * @return bool Whether the queue exists. */ public function has(string|BackedEnum $name): bool; + + /** + * Returns a list of queue names. + * + * @return string[] Queue names. + * + * @psalm-return list + */ + public function getNames(): array; } diff --git a/tests/Unit/Debug/QueueProviderInterfaceProxyTest.php b/tests/Unit/Debug/QueueProviderInterfaceProxyTest.php index 8c404857..ffc7b852 100644 --- a/tests/Unit/Debug/QueueProviderInterfaceProxyTest.php +++ b/tests/Unit/Debug/QueueProviderInterfaceProxyTest.php @@ -33,4 +33,14 @@ public function testHas(): void $this->assertTrue($factory->has('test')); } + + public function testGetNames(): void + { + $queueFactory = $this->createMock(QueueProviderInterface::class); + $queueFactory->expects($this->once())->method('getNames')->willReturn(['queue1', 'queue2']); + $collector = new QueueCollector(); + $factory = new QueueProviderInterfaceProxy($queueFactory, $collector); + + $this->assertSame(['queue1', 'queue2'], $factory->getNames()); + } } diff --git a/tests/Unit/Provider/AdapterFactoryQueueProviderTest.php b/tests/Unit/Provider/AdapterFactoryQueueProviderTest.php index b5ac52c0..d2a7521d 100644 --- a/tests/Unit/Provider/AdapterFactoryQueueProviderTest.php +++ b/tests/Unit/Provider/AdapterFactoryQueueProviderTest.php @@ -143,4 +143,27 @@ public function testQueueNameAndAdapterConfiguration(): void $this->assertSame('log-queue', $logQueue->getName()); $this->assertInstanceOf(StubAdapter::class, $logQueue->getAdapter()); } + + public function testGetNames(): void + { + $provider = new AdapterFactoryQueueProvider( + new StubQueue(), + [ + 'queue1' => StubAdapter::class, + 'queue2' => StubAdapter::class, + ], + ); + + $this->assertSame(['queue1', 'queue2'], $provider->getNames()); + } + + public function testGetNamesEmpty(): void + { + $provider = new AdapterFactoryQueueProvider( + new StubQueue(), + [], + ); + + $this->assertSame([], $provider->getNames()); + } } diff --git a/tests/Unit/Provider/CompositeQueueProviderTest.php b/tests/Unit/Provider/CompositeQueueProviderTest.php index d115ddd2..59a4c456 100644 --- a/tests/Unit/Provider/CompositeQueueProviderTest.php +++ b/tests/Unit/Provider/CompositeQueueProviderTest.php @@ -42,4 +42,45 @@ public function testNotFound(): void $this->expectExceptionMessage('Queue with name "not-exists" not found.'); $provider->get('not-exists'); } + + public function testGetNames(): void + { + $provider = new CompositeQueueProvider( + new PredefinedQueueProvider([ + 'queue1' => new StubQueue(new StubAdapter()), + 'queue2' => new StubQueue(new StubAdapter()), + ]), + new PredefinedQueueProvider([ + 'queue3' => new StubQueue(new StubAdapter()), + ]), + ); + + $names = $provider->getNames(); + + $this->assertSame(['queue1', 'queue2', 'queue3'], $names); + } + + public function testGetNamesWithDuplicates(): void + { + $provider = new CompositeQueueProvider( + new PredefinedQueueProvider([ + 'queue1' => new StubQueue(new StubAdapter()), + ]), + new PredefinedQueueProvider([ + 'queue1' => new StubQueue(new StubAdapter()), + 'queue2' => new StubQueue(new StubAdapter()), + ]), + ); + + $names = $provider->getNames(); + + $this->assertSame(['queue1', 'queue2'], $names); + } + + public function testGetNamesEmpty(): void + { + $provider = new CompositeQueueProvider(); + + $this->assertSame([], $provider->getNames()); + } } diff --git a/tests/Unit/Provider/PredefinedQueueProviderTest.php b/tests/Unit/Provider/PredefinedQueueProviderTest.php index db836d91..08be260b 100644 --- a/tests/Unit/Provider/PredefinedQueueProviderTest.php +++ b/tests/Unit/Provider/PredefinedQueueProviderTest.php @@ -88,4 +88,21 @@ public function testEmpty(): void $this->assertFalse($provider->has('any')); } + + public function testGetNames(): void + { + $provider = new PredefinedQueueProvider([ + 'queue1' => new StubQueue(), + 'queue2' => new StubQueue(), + ]); + + $this->assertSame(['queue1', 'queue2'], $provider->getNames()); + } + + public function testGetNamesEmpty(): void + { + $provider = new PredefinedQueueProvider([]); + + $this->assertSame([], $provider->getNames()); + } } diff --git a/tests/Unit/Provider/QueueFactoryProviderTest.php b/tests/Unit/Provider/QueueFactoryProviderTest.php index 488a901c..4bc92987 100644 --- a/tests/Unit/Provider/QueueFactoryProviderTest.php +++ b/tests/Unit/Provider/QueueFactoryProviderTest.php @@ -153,4 +153,23 @@ public function testValidateFalse(): void $this->assertTrue($provider->has('queue1')); } + + public function testGetNames(): void + { + $provider = new QueueFactoryProvider( + [ + 'queue1' => StubQueue::class, + 'queue2' => StubQueue::class, + ], + ); + + $this->assertSame(['queue1', 'queue2'], $provider->getNames()); + } + + public function testGetNamesEmpty(): void + { + $provider = new QueueFactoryProvider([]); + + $this->assertSame([], $provider->getNames()); + } } From 937ff96dd3e9e63ea650d07e8597030a479ad76d Mon Sep 17 00:00:00 2001 From: vjik <525501+vjik@users.noreply.github.com> Date: Sat, 21 Mar 2026 05:23:42 +0000 Subject: [PATCH 2/4] Apply PHP CS Fixer and Rector changes (CI) --- config/di.php | 2 -- 1 file changed, 2 deletions(-) diff --git a/config/di.php b/config/di.php index 292bdff2..9cc29df1 100644 --- a/config/di.php +++ b/config/di.php @@ -6,8 +6,6 @@ use Yiisoft\Queue\Cli\LoopInterface; use Yiisoft\Queue\Cli\SignalLoop; use Yiisoft\Queue\Cli\SimpleLoop; -use Yiisoft\Queue\Command\ListenAllCommand; -use Yiisoft\Queue\Command\RunCommand; use Yiisoft\Queue\Message\JsonMessageSerializer; use Yiisoft\Queue\Message\MessageSerializerInterface; use Yiisoft\Queue\Middleware\Consume\ConsumeMiddlewareDispatcher; From 54965819ab0d539e110c5358a9d746367af8ef90 Mon Sep 17 00:00:00 2001 From: Sergei Predvoditelev Date: Sat, 21 Mar 2026 08:28:24 +0300 Subject: [PATCH 3/4] fix tests --- tests/Unit/Command/ListenAllCommandTest.php | 9 +++++---- tests/Unit/Command/RunCommandTest.php | 13 ++++++------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/tests/Unit/Command/ListenAllCommandTest.php b/tests/Unit/Command/ListenAllCommandTest.php index 55f21330..24175f58 100644 --- a/tests/Unit/Command/ListenAllCommandTest.php +++ b/tests/Unit/Command/ListenAllCommandTest.php @@ -9,7 +9,7 @@ use Symfony\Component\Console\Output\OutputInterface; use Yiisoft\Queue\Cli\LoopInterface; use Yiisoft\Queue\Command\ListenAllCommand; -use Yiisoft\Queue\Provider\QueueProviderInterface; +use Yiisoft\Queue\Provider\PredefinedQueueProvider; use Yiisoft\Queue\QueueInterface; final class ListenAllCommandTest extends TestCase @@ -21,8 +21,10 @@ public function testExecute(): void $queue2 = $this->createMock(QueueInterface::class); $queue2->expects($this->once())->method('run'); - $queueFactory = $this->createMock(QueueProviderInterface::class); - $queueFactory->method('get')->willReturn($queue1, $queue2); + $queueFactory = new PredefinedQueueProvider([ + 'queue1' => $queue1, + 'queue2' => $queue2, + ]); $loop = $this->createMock(LoopInterface::class); $loop->method('canContinue')->willReturn(true, false); @@ -30,7 +32,6 @@ public function testExecute(): void $command = new ListenAllCommand( $queueFactory, $loop, - ['channel1', 'channel2'], ); $input = new ArrayInput([], $command->getNativeDefinition()); $input->setOption('pause', 0); diff --git a/tests/Unit/Command/RunCommandTest.php b/tests/Unit/Command/RunCommandTest.php index 672db54e..6b7e5bcc 100644 --- a/tests/Unit/Command/RunCommandTest.php +++ b/tests/Unit/Command/RunCommandTest.php @@ -8,6 +8,7 @@ use Symfony\Component\Console\Input\StringInput; use Symfony\Component\Console\Output\OutputInterface; use Yiisoft\Queue\Command\RunCommand; +use Yiisoft\Queue\Provider\PredefinedQueueProvider; use Yiisoft\Queue\Provider\QueueProviderInterface; use Yiisoft\Queue\QueueInterface; @@ -111,22 +112,20 @@ public function testExecuteWithDefaultQueues(): void ->with($this->equalTo(0)) ->willReturn(2); - $queueProvider = $this->createMock(QueueProviderInterface::class); - $queueProvider->expects($this->once()) - ->method('get') - ->with($this->equalTo('default-queue')) - ->willReturn($queue); + $queueProvider = new PredefinedQueueProvider([ + QueueProviderInterface::DEFAULT_QUEUE => $queue, + ]); $input = new StringInput(''); $output = $this->createMock(OutputInterface::class); $output->expects($this->once()) ->method('write') - ->with($this->equalTo('Processing queue default-queue... ')); + ->with($this->equalTo('Processing queue ' . QueueProviderInterface::DEFAULT_QUEUE . '... ')); $output->expects($this->once()) ->method('writeln') ->with($this->equalTo('Messages processed: 2.')); - $command = new RunCommand($queueProvider, ['default-queue']); + $command = new RunCommand($queueProvider); $exitCode = $command->run($input, $output); $this->assertEquals(0, $exitCode); From 4abbad51304e4bc748be4bb3154bbc5ea7d1b2b4 Mon Sep 17 00:00:00 2001 From: Sergei Predvoditelev Date: Sat, 21 Mar 2026 08:40:31 +0300 Subject: [PATCH 4/4] fix tests --- tests/Unit/Command/RunCommandTest.php | 30 ++++++++++++--------------- 1 file changed, 13 insertions(+), 17 deletions(-) diff --git a/tests/Unit/Command/RunCommandTest.php b/tests/Unit/Command/RunCommandTest.php index 6b7e5bcc..8c1978f0 100644 --- a/tests/Unit/Command/RunCommandTest.php +++ b/tests/Unit/Command/RunCommandTest.php @@ -22,11 +22,9 @@ public function testExecuteWithSingleQueue(): void ->with($this->equalTo(0)) ->willReturn(5); - $queueProvider = $this->createMock(QueueProviderInterface::class); - $queueProvider->expects($this->once()) - ->method('get') - ->with($this->equalTo('test-queue')) - ->willReturn($queue); + $queueProvider = new PredefinedQueueProvider([ + 'test-queue' => $queue, + ]); $input = new StringInput('test-queue'); $output = $this->createMock(OutputInterface::class); @@ -37,7 +35,7 @@ public function testExecuteWithSingleQueue(): void ->method('writeln') ->with($this->equalTo('Messages processed: 5.')); - $command = new RunCommand($queueProvider, []); + $command = new RunCommand($queueProvider); $exitCode = $command->run($input, $output); $this->assertEquals(0, $exitCode); @@ -57,10 +55,10 @@ public function testExecuteWithMultipleQueues(): void ->with($this->equalTo(0)) ->willReturn(7); - $queueProvider = $this->createMock(QueueProviderInterface::class); - $queueProvider->expects($this->exactly(2)) - ->method('get') - ->willReturnOnConsecutiveCalls($queue1, $queue2); + $queueProvider = new PredefinedQueueProvider([ + 'queue1' => $queue1, + 'queue2' => $queue2, + ]); $output = $this->createMock(OutputInterface::class); $output->expects($this->exactly(2)) @@ -69,7 +67,7 @@ public function testExecuteWithMultipleQueues(): void ->method('writeln'); $input = new StringInput('queue1 queue2'); - $command = new RunCommand($queueProvider, []); + $command = new RunCommand($queueProvider); $exitCode = $command->run($input, $output); $this->assertEquals(0, $exitCode); @@ -83,11 +81,9 @@ public function testExecuteWithMaximumOption(): void ->with($this->equalTo(100)) ->willReturn(10); - $queueProvider = $this->createMock(QueueProviderInterface::class); - $queueProvider->expects($this->once()) - ->method('get') - ->with($this->equalTo('test-queue')) - ->willReturn($queue); + $queueProvider = new PredefinedQueueProvider([ + 'test-queue' => $queue, + ]); $input = new StringInput('test-queue --maximum=100'); $output = $this->createMock(OutputInterface::class); @@ -98,7 +94,7 @@ public function testExecuteWithMaximumOption(): void ->method('writeln') ->with($this->equalTo('Messages processed: 10.')); - $command = new RunCommand($queueProvider, []); + $command = new RunCommand($queueProvider); $exitCode = $command->run($input, $output); $this->assertEquals(0, $exitCode);