FailureMiddlewareDispatcher   A
last analyzed

Complexity

Total Complexity 10

Size/Duplication

Total Lines 96
Duplicated Lines 0 %

Test Coverage

Coverage 100%

Importance

Changes 0
Metric Value
eloc 25
dl 0
loc 96
ccs 27
cts 27
cp 1
rs 10
c 0
b 0
f 0
wmc 10

5 Methods

Rating   Name   Duplication   Size   Complexity  
A withMiddlewares() 0 12 1
A dispatch() 0 15 4
A init() 0 4 2
A __construct() 0 5 1
A buildMiddlewares() 0 11 2
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Yiisoft\Queue\Middleware\FailureHandling;
6
7
use Closure;
8
9
final class FailureMiddlewareDispatcher
10
{
11
    public const DEFAULT_PIPELINE = 'failure-pipeline-default';
12
13
    /**
14
     * Contains a middleware pipeline handler.
15
     *
16
     * @var MiddlewareFailureStack[] The middleware stack.
17
     */
18
    private array $stack = [];
19
20
    /**
21
     * @param array[][]|callable[][]|MiddlewareFailureInterface[][]|string[][] $middlewareDefinitions
22
     */
23 33
    public function __construct(
24
        private MiddlewareFactoryFailureInterface $middlewareFactory,
25
        private array $middlewareDefinitions,
26
    ) {
27 33
        $this->init();
28
    }
29
30
    /**
31
     * Dispatch request through middleware to get response.
32
     *
33
     * @param FailureHandlingRequest $request Request to pass to middleware.
34
     * @param MessageFailureHandlerInterface $finishHandler Handler to use in case no middleware produced response.
35
     */
36 8
    public function dispatch(
37
        FailureHandlingRequest $request,
38
        MessageFailureHandlerInterface $finishHandler
39
    ): FailureHandlingRequest {
40 8
        $channelName = $request->getQueue()->getChannelName();
41 8
        if (!isset($this->middlewareDefinitions[$channelName]) || $this->middlewareDefinitions[$channelName] === []) {
42 7
            $channelName = self::DEFAULT_PIPELINE;
43
        }
44 8
        $definitions = array_reverse($this->middlewareDefinitions[$channelName]);
45
46 8
        if (!isset($this->stack[$channelName])) {
47 8
            $this->stack[$channelName] = new MiddlewareFailureStack($this->buildMiddlewares(...$definitions), $finishHandler);
48
        }
49
50 8
        return $this->stack[$channelName]->handleFailure($request);
51
    }
52
53
    /**
54
     * Returns new instance with middleware handlers replaced with the ones provided.
55
     * Last specified handler will be executed first.
56
     *
57
     * @param array[][]|callable[][]|MiddlewareFailureInterface[][]|string[][] $middlewareDefinitions Each array element is:
58
     *
59
     * - A name of a middleware class. The middleware instance will be obtained from container executed.
60
     * - A callable with `function(ServerRequestInterface $request, RequestHandlerInterface $handler):
61
     *     ResponseInterface` signature.
62
     * - A "callable-like" array in format `[FooMiddleware::class, 'index']`. `FooMiddleware` instance will
63
     *   be created and `index()` method will be executed.
64
     * - A function returning a middleware. The middleware returned will be executed.
65
     *
66
     * For callables typed parameters are automatically injected using dependency injection container.
67
     *
68
     * @return self New instance of the {@see FailureMiddlewareDispatcher}
69
     */
70 7
    public function withMiddlewares(array $middlewareDefinitions): self
71
    {
72 7
        $instance = clone $this;
73 7
        $instance->middlewareDefinitions = $middlewareDefinitions;
74
75
        // Fixes a memory leak.
76 7
        unset($instance->stack);
77 7
        $instance->stack = [];
78
79 7
        $instance->init();
80
81 7
        return $instance;
82
    }
83
84 33
    private function init(): void
85
    {
86 33
        if (!isset($this->middlewareDefinitions[self::DEFAULT_PIPELINE])) {
87 33
            $this->middlewareDefinitions[self::DEFAULT_PIPELINE] = [];
88
        }
89
    }
90
91
    /**
92
     * @return Closure[]
93
     */
94 8
    private function buildMiddlewares(array|callable|string|MiddlewareFailureInterface ...$definitions): array
95
    {
96 8
        $middlewares = [];
97 8
        $factory = $this->middlewareFactory;
98
99 8
        foreach ($definitions as $middlewareDefinition) {
100 7
            $middlewares[] = static fn (): MiddlewareFailureInterface =>
101 7
                $factory->createFailureMiddleware($middlewareDefinition);
102
        }
103
104 8
        return $middlewares;
105
    }
106
}
107