diff --git a/psalm.xml b/psalm.xml
index 21cba6bd..849e4c85 100644
--- a/psalm.xml
+++ b/psalm.xml
@@ -11,8 +11,17 @@
>
+
+
+
+
+
+
+
+
+
diff --git a/src/Debug/QueueDecorator.php b/src/Debug/QueueDecorator.php
index 908ad064..8bbafca2 100644
--- a/src/Debug/QueueDecorator.php
+++ b/src/Debug/QueueDecorator.php
@@ -6,6 +6,7 @@
use Yiisoft\Queue\MessageStatus;
use Yiisoft\Queue\Message\MessageInterface;
+use Yiisoft\Queue\Middleware\Push\MiddlewarePushInterface;
use Yiisoft\Queue\QueueInterface;
final class QueueDecorator implements QueueInterface
@@ -44,4 +45,14 @@ public function getName(): string
{
return $this->queue->getName();
}
+
+ public function withMiddlewares(MiddlewarePushInterface|callable|array|string ...$middlewareDefinitions): self
+ {
+ return new self($this->queue->withMiddlewares(...$middlewareDefinitions), $this->collector);
+ }
+
+ public function withMiddlewaresAdded(MiddlewarePushInterface|callable|array|string ...$middlewareDefinitions): self
+ {
+ return new self($this->queue->withMiddlewaresAdded(...$middlewareDefinitions), $this->collector);
+ }
}
diff --git a/src/Queue.php b/src/Queue.php
index 3b4b39db..20d80d89 100644
--- a/src/Queue.php
+++ b/src/Queue.php
@@ -45,9 +45,12 @@ public function __construct(
) {
$this->name = StringNormalizer::normalize($name);
$this->middlewareDefinitions = $middlewareDefinitions;
- $this->finalPushHandler = $this->isSynchronous()
- ? new SynchronousPushHandler($worker, $this)
- : new AdapterPushHandler($this->adapter);
+ $this->finalPushHandler = $this->createFinalPushHandler();
+ }
+
+ public function __clone()
+ {
+ $this->finalPushHandler = $this->createFinalPushHandler();
}
public function getName(): string
@@ -189,6 +192,13 @@ public function handlePush(MessageInterface $message): MessageInterface
};
}
+ private function createFinalPushHandler(): MessageHandlerPushInterface
+ {
+ return $this->isSynchronous()
+ ? new SynchronousPushHandler($this->worker, $this)
+ : new AdapterPushHandler($this->adapter);
+ }
+
/**
* @psalm-assert-if-false !null $this->adapter
*/
diff --git a/src/QueueInterface.php b/src/QueueInterface.php
index b4ac11e3..781723b1 100644
--- a/src/QueueInterface.php
+++ b/src/QueueInterface.php
@@ -5,6 +5,7 @@
namespace Yiisoft\Queue;
use Yiisoft\Queue\Message\MessageInterface;
+use Yiisoft\Queue\Middleware\Push\MiddlewarePushInterface;
interface QueueInterface
{
@@ -40,4 +41,18 @@ public function status(string|int $id): MessageStatus;
* Returns the logical name of the queue.
*/
public function getName(): string;
+
+ /**
+ * Creates a new instance with the specified middlewares. All the existing middlewares are replaced.
+ *
+ * @param MiddlewarePushInterface|callable|array|string ...$middlewareDefinitions The middleware definitions.
+ */
+ public function withMiddlewares(MiddlewarePushInterface|callable|array|string ...$middlewareDefinitions): self;
+
+ /**
+ * Creates a new instance with the specified middlewares added after the existing ones.
+ *
+ * @param MiddlewarePushInterface|callable|array|string ...$middlewareDefinitions The middleware definitions.
+ */
+ public function withMiddlewaresAdded(MiddlewarePushInterface|callable|array|string ...$middlewareDefinitions): self;
}
diff --git a/stubs/StubQueue.php b/stubs/StubQueue.php
index f34c6d11..353946c8 100644
--- a/stubs/StubQueue.php
+++ b/stubs/StubQueue.php
@@ -6,6 +6,7 @@
use Yiisoft\Queue\MessageStatus;
use Yiisoft\Queue\Message\MessageInterface;
+use Yiisoft\Queue\Middleware\Push\MiddlewarePushInterface;
use Yiisoft\Queue\QueueInterface;
/**
@@ -38,4 +39,14 @@ public function getName(): string
{
return $this->name;
}
+
+ public function withMiddlewares(MiddlewarePushInterface|callable|array|string ...$middlewareDefinitions): self
+ {
+ return $this;
+ }
+
+ public function withMiddlewaresAdded(MiddlewarePushInterface|callable|array|string ...$middlewareDefinitions): self
+ {
+ return $this;
+ }
}
diff --git a/tests/App/DummyQueue.php b/tests/App/DummyQueue.php
index 325ae3c0..3871243e 100644
--- a/tests/App/DummyQueue.php
+++ b/tests/App/DummyQueue.php
@@ -7,6 +7,7 @@
use Exception;
use Yiisoft\Queue\MessageStatus;
use Yiisoft\Queue\Message\MessageInterface;
+use Yiisoft\Queue\Middleware\Push\MiddlewarePushInterface;
use Yiisoft\Queue\QueueInterface;
final class DummyQueue implements QueueInterface
@@ -36,4 +37,14 @@ public function getName(): string
{
return $this->name;
}
+
+ public function withMiddlewares(MiddlewarePushInterface|callable|array|string ...$middlewareDefinitions): self
+ {
+ throw new Exception('`withMiddlewares()` method is not implemented yet.');
+ }
+
+ public function withMiddlewaresAdded(MiddlewarePushInterface|callable|array|string ...$middlewareDefinitions): self
+ {
+ throw new Exception('`withMiddlewaresAdded()` method is not implemented yet.');
+ }
}
diff --git a/tests/App/FakeAdapter.php b/tests/App/FakeAdapter.php
index 46a987d7..683cd47d 100644
--- a/tests/App/FakeAdapter.php
+++ b/tests/App/FakeAdapter.php
@@ -5,6 +5,7 @@
namespace Yiisoft\Queue\Tests\App;
use BackedEnum;
+use Exception;
use Yiisoft\Queue\Adapter\AdapterInterface;
use Yiisoft\Queue\StringNormalizer;
use Yiisoft\Queue\MessageStatus;
@@ -24,23 +25,24 @@ public function push(MessageInterface $message): MessageInterface
public function runExisting(callable $handlerCallback): void
{
- //skip
+ throw new Exception('`runExisting()` method is not implemented yet.');
}
public function status(string|int $id): MessageStatus
{
- //skip
+ throw new Exception('`status()` method is not implemented yet.');
}
public function subscribe(callable $handlerCallback): void
{
- //skip
+ throw new Exception('`subscribe()` method is not implemented yet.');
}
public function withChannel(string|BackedEnum $channel): self
{
$new = clone $this;
$new->channel = StringNormalizer::normalize($channel);
+
return $new;
}
}
diff --git a/tests/App/StaticMessageHandler.php b/tests/App/StaticMessageHandler.php
index 3825836a..b9dd6e0e 100644
--- a/tests/App/StaticMessageHandler.php
+++ b/tests/App/StaticMessageHandler.php
@@ -4,7 +4,7 @@
namespace Yiisoft\Queue\Tests\App;
-class StaticMessageHandler
+final class StaticMessageHandler
{
public static bool $wasHandled = false;
diff --git a/tests/Benchmark/MetadataBench.php b/tests/Benchmark/MetadataBench.php
index 12300a7d..e60565f6 100644
--- a/tests/Benchmark/MetadataBench.php
+++ b/tests/Benchmark/MetadataBench.php
@@ -6,7 +6,6 @@
use Generator;
use PhpBench\Attributes\ParamProviders;
-use PhpBench\Model\Tag;
use Yiisoft\Queue\Message\IdEnvelope;
use Yiisoft\Queue\Message\Message;
use Yiisoft\Queue\Message\MessageInterface;
@@ -17,7 +16,6 @@ final class MetadataBench
/**
* Create metadata as an array and read its value from an array.
*/
- #[Tag('metadata_read')]
public function benchArrayRead(): void
{
$message = new Message('foo', 'bar', ['id' => 1]);
@@ -27,7 +25,6 @@ public function benchArrayRead(): void
/**
* Create metadata as an object and read its value immediately.
*/
- #[Tag('metadata_read')]
public function benchEnvelopeRead(): void
{
$message = new IdEnvelope(new Message('foo', 'bar'), 1);
@@ -37,7 +34,6 @@ public function benchEnvelopeRead(): void
/**
* Create metadata as an array and read its value from an envelope object.
*/
- #[Tag('metadata_read')]
public function benchEnvelopeReadRestored(): void
{
$message = IdEnvelope::fromMessage(new Message('foo', 'bar', ['id' => 1]));
@@ -63,7 +59,6 @@ public function provideEnvelopeStack(): Generator
* @psalm-param array{message: MessageInterface} $params
*/
#[ParamProviders('provideEnvelopeStack')]
- #[Tag('metadata_read')]
public function benchEnvelopeReadFromStack(array $params): void
{
$id = IdEnvelope::fromMessage($params['message'])->getId();
@@ -82,7 +77,6 @@ public function provideEnvelopeStackCounts(): Generator
* @psalm-param array{0: int} $params
*/
#[ParamProviders('provideEnvelopeStackCounts')]
- #[Tag('metadata_create')]
public function benchEnvelopeStackCreation(array $params): void
{
$message = new Message('foo', 'bar');
@@ -97,7 +91,6 @@ public function benchEnvelopeStackCreation(array $params): void
* @psalm-param array{0: int} $params
*/
#[ParamProviders('provideEnvelopeStackCounts')]
- #[Tag('metadata_create')]
public function benchMetadataArrayCreation(array $params): void
{
$metadata = ['failure-meta' => []];
diff --git a/tests/Benchmark/QueueBench.php b/tests/Benchmark/QueueBench.php
index 0f2e73ab..1b79a475 100644
--- a/tests/Benchmark/QueueBench.php
+++ b/tests/Benchmark/QueueBench.php
@@ -6,7 +6,6 @@
use Generator;
use PhpBench\Attributes\ParamProviders;
-use PhpBench\Model\Tag;
use Psr\Log\NullLogger;
use Yiisoft\Injector\Injector;
use Yiisoft\Queue\Cli\SimpleLoop;
@@ -80,7 +79,6 @@ public function providePush(): Generator
}
#[ParamProviders('providePush')]
- #[Tag('queue_push')]
public function benchPush(array $params): void
{
$this->queue->push($params['message']);
@@ -103,7 +101,6 @@ public function provideConsume(): Generator
}
#[ParamProviders('provideConsume')]
- #[Tag('queue_consume')]
public function benchConsume(array $params): void
{
$this->adapter->message = $params['message'];
diff --git a/tests/Unit/Cli/SignalLoopTest.php b/tests/Unit/Cli/SignalLoopTest.php
index 1b542405..ebf06971 100644
--- a/tests/Unit/Cli/SignalLoopTest.php
+++ b/tests/Unit/Cli/SignalLoopTest.php
@@ -16,6 +16,10 @@
use const SIGTERM;
use const SIGTSTP;
+/**
+ * @psalm-suppress UndefinedConstant
+ * @psalm-suppress PossiblyFalseArgument
+ */
#[RequiresPhpExtension('pcntl')]
final class SignalLoopTest extends TestCase
{
diff --git a/tests/Unit/Debug/QueueCollectorTest.php b/tests/Unit/Debug/QueueCollectorTest.php
index fe554ea3..5ed42be8 100644
--- a/tests/Unit/Debug/QueueCollectorTest.php
+++ b/tests/Unit/Debug/QueueCollectorTest.php
@@ -22,7 +22,8 @@ protected function setUp(): void
}
/**
- * @param CollectorInterface|QueueCollector $collector
+ * @param QueueCollector $collector
+ * @psalm-suppress MoreSpecificImplementedParamType
*/
protected function collectTestData(CollectorInterface $collector): void
{
diff --git a/tests/Unit/Debug/QueueDecoratorTest.php b/tests/Unit/Debug/QueueDecoratorTest.php
index ab7a73d0..9d0169c6 100644
--- a/tests/Unit/Debug/QueueDecoratorTest.php
+++ b/tests/Unit/Debug/QueueDecoratorTest.php
@@ -11,7 +11,7 @@
use Yiisoft\Queue\Message\MessageInterface;
use Yiisoft\Queue\QueueInterface;
-class QueueDecoratorTest extends TestCase
+final class QueueDecoratorTest extends TestCase
{
public function testStatus(): void
{
diff --git a/tests/Unit/Debug/QueueProviderInterfaceProxyTest.php b/tests/Unit/Debug/QueueProviderInterfaceProxyTest.php
index ffc7b852..2ba2ae42 100644
--- a/tests/Unit/Debug/QueueProviderInterfaceProxyTest.php
+++ b/tests/Unit/Debug/QueueProviderInterfaceProxyTest.php
@@ -11,7 +11,7 @@
use Yiisoft\Queue\Provider\QueueProviderInterface;
use Yiisoft\Queue\QueueInterface;
-class QueueProviderInterfaceProxyTest extends TestCase
+final class QueueProviderInterfaceProxyTest extends TestCase
{
public function testGet(): void
{
diff --git a/tests/Unit/Message/EnvelopeTest.php b/tests/Unit/Message/EnvelopeTest.php
index 111b863d..93fdefce 100644
--- a/tests/Unit/Message/EnvelopeTest.php
+++ b/tests/Unit/Message/EnvelopeTest.php
@@ -29,7 +29,7 @@ public function testFromData(): void
public function testNonArrayStackIsNormalized(): void
{
$base = new Message('handler', 'data', [EnvelopeInterface::ENVELOPE_STACK_KEY => 'oops']);
- $wrapped = new DummyEnvelope($base, 'id-1');
+ $wrapped = new DummyEnvelope($base);
$meta = $wrapped->getMetadata();
self::assertIsArray($meta[EnvelopeInterface::ENVELOPE_STACK_KEY]);
diff --git a/tests/Unit/Message/JsonMessageSerializerTest.php b/tests/Unit/Message/JsonMessageSerializerTest.php
index e0f2616c..ed511681 100644
--- a/tests/Unit/Message/JsonMessageSerializerTest.php
+++ b/tests/Unit/Message/JsonMessageSerializerTest.php
@@ -15,6 +15,8 @@
use function sprintf;
+use const JSON_THROW_ON_ERROR;
+
/**
* Testing message serialization options
*/
@@ -31,7 +33,7 @@ public function testTypeFormat(mixed $type): void
$this->expectExceptionMessage(sprintf('Message type must be a string. Got %s.', get_debug_type($type)));
$this->expectException(InvalidArgumentException::class);
- $serializer->unserialize(json_encode($payload));
+ $serializer->unserialize(json_encode($payload, JSON_THROW_ON_ERROR));
}
public static function dataUnsupportedTypeFormat(): iterable
@@ -53,7 +55,7 @@ public function testDefaultMessageClassFallbackWrongClass(): void
],
];
- $message = $serializer->unserialize(json_encode($payload));
+ $message = $serializer->unserialize(json_encode($payload, JSON_THROW_ON_ERROR));
$this->assertInstanceOf(Message::class, $message);
}
@@ -65,7 +67,7 @@ public function testDefaultMessageClassFallbackClassNotSet(): void
'data' => 'test',
'meta' => [],
];
- $message = $serializer->unserialize(json_encode($payload));
+ $message = $serializer->unserialize(json_encode($payload, JSON_THROW_ON_ERROR));
$this->assertInstanceOf(Message::class, $message);
}
@@ -76,7 +78,7 @@ public function testPayloadFormat(mixed $payload): void
$this->expectExceptionMessage(sprintf('Payload must be array. Got %s.', get_debug_type($payload)));
$this->expectException(InvalidArgumentException::class);
- $serializer->unserialize(json_encode($payload));
+ $serializer->unserialize(json_encode($payload, JSON_THROW_ON_ERROR));
}
public static function dataUnsupportedPayloadFormat(): iterable
@@ -95,7 +97,7 @@ public function testMetadataFormat(mixed $meta): void
$this->expectExceptionMessage(sprintf('Metadata must be an array. Got %s.', get_debug_type($meta)));
$this->expectException(InvalidArgumentException::class);
- $serializer->unserialize(json_encode($payload));
+ $serializer->unserialize(json_encode($payload, JSON_THROW_ON_ERROR));
}
public static function dataUnsupportedMetadataFormat(): iterable
@@ -110,7 +112,7 @@ public function testUnserializeFromData(): void
$payload = ['type' => 'handler', 'data' => 'test'];
$serializer = $this->createSerializer();
- $message = $serializer->unserialize(json_encode($payload));
+ $message = $serializer->unserialize(json_encode($payload, JSON_THROW_ON_ERROR));
$this->assertEquals($payload['data'], $message->getData());
$this->assertEquals([EnvelopeInterface::ENVELOPE_STACK_KEY => []], $message->getMetadata());
@@ -121,7 +123,7 @@ public function testUnserializeWithMetadata(): void
$payload = ['type' => 'handler', 'data' => 'test', 'meta' => ['int' => 1, 'str' => 'string', 'bool' => true]];
$serializer = $this->createSerializer();
- $message = $serializer->unserialize(json_encode($payload));
+ $message = $serializer->unserialize(json_encode($payload, JSON_THROW_ON_ERROR));
$this->assertEquals($payload['data'], $message->getData());
$this->assertEquals(['int' => 1, 'str' => 'string', 'bool' => true, EnvelopeInterface::ENVELOPE_STACK_KEY => []], $message->getMetadata());
@@ -141,7 +143,7 @@ public function testUnserializeEnvelopeStack(): void
$serializer = $this->createSerializer();
/** @var IdEnvelope $message */
- $message = $serializer->unserialize(json_encode($payload));
+ $message = $serializer->unserialize(json_encode($payload, JSON_THROW_ON_ERROR));
$this->assertEquals($payload['data'], $message->getData());
$this->assertEquals([IdEnvelope::class], $message->getMetadata()[EnvelopeInterface::ENVELOPE_STACK_KEY]);
diff --git a/tests/Unit/Middleware/CallableFactoryTest.php b/tests/Unit/Middleware/CallableFactoryTest.php
index 3275278c..f270543b 100644
--- a/tests/Unit/Middleware/CallableFactoryTest.php
+++ b/tests/Unit/Middleware/CallableFactoryTest.php
@@ -19,6 +19,7 @@ public function testCreatePositive(mixed $definition, array $arguments, mixed $e
$factory = new CallableFactory($container);
$callable = $factory->create($definition);
+ /** @psalm-suppress RedundantCondition */
self::assertIsCallable($callable);
self::assertSame($expectedResult, $callable(...$arguments));
}
diff --git a/tests/Unit/Middleware/FailureHandling/Implementation/ExponentialDelayMiddlewareTest.php b/tests/Unit/Middleware/FailureHandling/Implementation/ExponentialDelayMiddlewareTest.php
index 949646a9..c3ce5b50 100644
--- a/tests/Unit/Middleware/FailureHandling/Implementation/ExponentialDelayMiddlewareTest.php
+++ b/tests/Unit/Middleware/FailureHandling/Implementation/ExponentialDelayMiddlewareTest.php
@@ -18,7 +18,7 @@
use const PHP_INT_MAX;
-class ExponentialDelayMiddlewareTest extends TestCase
+final class ExponentialDelayMiddlewareTest extends TestCase
{
public static function constructorRequirementsProvider(): array
{
diff --git a/tests/Unit/Middleware/FailureHandling/Implementation/SendAgainMiddlewareTest.php b/tests/Unit/Middleware/FailureHandling/Implementation/SendAgainMiddlewareTest.php
index 7641ea88..6c1529bf 100644
--- a/tests/Unit/Middleware/FailureHandling/Implementation/SendAgainMiddlewareTest.php
+++ b/tests/Unit/Middleware/FailureHandling/Implementation/SendAgainMiddlewareTest.php
@@ -20,7 +20,7 @@
use Yiisoft\Queue\Stubs\StubDelayMiddleware;
use Yiisoft\Queue\Tests\TestCase;
-class SendAgainMiddlewareTest extends TestCase
+final class SendAgainMiddlewareTest extends TestCase
{
final public const KEY_EXPONENTIAL_ATTEMPTS = ExponentialDelayMiddleware::META_KEY_ATTEMPTS . '-test';
final public const KEY_EXPONENTIAL_DELAY = ExponentialDelayMiddleware::META_KEY_DELAY . '-test';
diff --git a/tests/Unit/Provider/PredefinedQueueProviderTest.php b/tests/Unit/Provider/PredefinedQueueProviderTest.php
index 08be260b..83ff06cb 100644
--- a/tests/Unit/Provider/PredefinedQueueProviderTest.php
+++ b/tests/Unit/Provider/PredefinedQueueProviderTest.php
@@ -65,6 +65,8 @@ public function testInvalidQueueConfig(): void
'stdClass',
),
);
+
+ /** @psalm-suppress InvalidArgument */
new PredefinedQueueProvider([
'queue1' => new stdClass(),
]);
diff --git a/tests/Unit/Stubs/StubAdapterTest.php b/tests/Unit/Stubs/StubAdapterTest.php
index dcbd24d8..8f455c6e 100644
--- a/tests/Unit/Stubs/StubAdapterTest.php
+++ b/tests/Unit/Stubs/StubAdapterTest.php
@@ -7,6 +7,7 @@
use PHPUnit\Framework\TestCase;
use Yiisoft\Queue\MessageStatus;
use Yiisoft\Queue\Message\Message;
+use Yiisoft\Queue\Message\MessageInterface;
use Yiisoft\Queue\Stubs\StubAdapter;
final class StubAdapterTest extends TestCase
@@ -18,7 +19,7 @@ public function testBase(): void
$this->assertSame($message, $adapter->push($message));
$this->assertSame(MessageStatus::DONE, $adapter->status('test'));
- $adapter->runExisting(static fn() => null);
- $adapter->subscribe(static fn() => null);
+ $adapter->runExisting(static fn(MessageInterface $message): bool => true);
+ $adapter->subscribe(static fn(MessageInterface $message): bool => true);
}
}
diff --git a/tests/Unit/WorkerTest.php b/tests/Unit/WorkerTest.php
index e8991c2e..22f9aae4 100644
--- a/tests/Unit/WorkerTest.php
+++ b/tests/Unit/WorkerTest.php
@@ -33,7 +33,7 @@
final class WorkerTest extends TestCase
{
#[DataProvider('messageHandledDataProvider')]
- public function testMessageHandled($handler, array $containerServices): void
+ public function testMessageHandled(mixed $handler, array $containerServices): void
{
$message = new Message('simple', ['test-data']);
$logger = new SimpleLogger();