Test Failed
Pull Request — master (#97)
by Dmitriy
06:31 queued 02:24
created

DelayMiddleware::process()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 22
Code Lines 15

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 15
c 1
b 0
f 0
dl 0
loc 22
rs 9.7666
cc 2
nc 2
nop 2
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Yiisoft\Queue\AMQP\Middleware;
6
7
use InvalidArgumentException;
8
use PhpAmqpLib\Exchange\AMQPExchangeType;
9
use PhpAmqpLib\Message\AMQPMessage;
10
use Yiisoft\Queue\AMQP\Adapter;
11
use Yiisoft\Queue\AMQP\QueueProviderInterface;
12
use Yiisoft\Queue\AMQP\Settings\ExchangeSettingsInterface;
13
use Yiisoft\Queue\AMQP\Settings\QueueSettingsInterface;
14
use Yiisoft\Queue\Middleware\MessageHandlerInterface;
0 ignored issues
show
Bug introduced by
The type Yiisoft\Queue\Middleware\MessageHandlerInterface was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
15
use Yiisoft\Queue\Middleware\MiddlewareInterface;
0 ignored issues
show
Bug introduced by
The type Yiisoft\Queue\Middleware\MiddlewareInterface was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
16
use Yiisoft\Queue\Middleware\Push\Implementation\DelayMiddlewareInterface;
17
use Yiisoft\Queue\Middleware\Request;
0 ignored issues
show
Bug introduced by
The type Yiisoft\Queue\Middleware\Request was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
18
19
final class DelayMiddleware implements MiddlewareInterface, DelayMiddlewareInterface
20
{
21
    public function __construct(private float $delayInSeconds, private bool $forcePersistentMessages = true)
22
    {
23
    }
24
25
    /**
26
     * @param float $seconds
27
     *
28
     * @return $this
29
     */
30
    public function withDelay(float $seconds): self
31
    {
32
        $new = clone $this;
33
        $new->delayInSeconds = $seconds;
34
35
        return $new;
36
    }
37
38
    public function getDelay(): float
39
    {
40
        return $this->delayInSeconds;
41
    }
42
43
    public function process(Request $request, MessageHandlerInterface $handler): Request
44
    {
45
        $adapter = $request->getAdapter();
46
        if (!$adapter instanceof Adapter) {
47
            $type = get_debug_type($adapter);
48
            $class = Adapter::class;
49
            throw new InvalidArgumentException(
50
                "This middleware works only with the $class. $type given."
51
            );
52
        }
53
54
        $queueProvider = $adapter->getQueueProvider();
55
        $exchangeSettings = $this->getExchangeSettings($queueProvider->getExchangeSettings());
56
        $queueSettings = $this->getQueueSettings($queueProvider->getQueueSettings(), $queueProvider->getExchangeSettings());
57
        $adapter = $adapter->withQueueProvider(
58
            $queueProvider
59
                ->withMessageProperties($this->getMessageProperties($queueProvider))
60
                ->withExchangeSettings($exchangeSettings)
61
                ->withQueueSettings($queueSettings)
62
        );
63
64
        return $handler->handle($request->withAdapter($adapter));
65
    }
66
67
    /**
68
     * @psalm-return array{expiration: int|float, delivery_mode?: int}&array
69
     */
70
    private function getMessageProperties(QueueProviderInterface $queueProvider): array
71
    {
72
        $messageProperties = ['expiration' => $this->delayInSeconds * 1000];
73
        if ($this->forcePersistentMessages === true) {
74
            $messageProperties['delivery_mode'] = AMQPMessage::DELIVERY_MODE_PERSISTENT;
75
        }
76
77
        return array_merge($queueProvider->getMessageProperties(), $messageProperties);
78
    }
79
80
    private function getQueueSettings(
81
        QueueSettingsInterface $queueSettings,
82
        ?ExchangeSettingsInterface $exchangeSettings
83
    ): QueueSettingsInterface {
84
        $deliveryTime = time() + $this->delayInSeconds;
85
86
        return $queueSettings
87
            ->withName("{$queueSettings->getName()}.dlx.$deliveryTime")
88
            ->withAutoDeletable(true)
89
            ->withArguments(
90
                [
91
                    'x-dead-letter-exchange' => ['S', $exchangeSettings?->getName() ?? ''],
92
                    'x-expires' => ['I', $this->delayInSeconds * 1000 + 30000],
93
                    'x-message-ttl' => ['I', $this->delayInSeconds * 1000],
94
                ]
95
            );
96
    }
97
98
    /**
99
     * @see https://github.com/vimeo/psalm/issues/9454
100
     *
101
     * @psalm-suppress LessSpecificReturnType
102
     */
103
    private function getExchangeSettings(?ExchangeSettingsInterface $exchangeSettings): ?ExchangeSettingsInterface
104
    {
105
        /** @noinspection NullPointerExceptionInspection */
106
        return $exchangeSettings
107
            ?->withName("{$exchangeSettings->getName()}.dlx")
0 ignored issues
show
Bug introduced by
The method getName() does not exist on null. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

107
            ?->withName("{$exchangeSettings->/** @scrutinizer ignore-call */ getName()}.dlx")

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
108
            ->withAutoDelete(true)
109
            ->withType(AMQPExchangeType::TOPIC);
110
    }
111
}
112