-
-
Notifications
You must be signed in to change notification settings - Fork 29
Expand file tree
/
Copy pathMiddlewareFactoryPush.php
More file actions
158 lines (136 loc) · 5.79 KB
/
MiddlewareFactoryPush.php
File metadata and controls
158 lines (136 loc) · 5.79 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
<?php
declare(strict_types=1);
namespace Yiisoft\Queue\Middleware\Push;
use Closure;
use Psr\Container\ContainerInterface;
use Yiisoft\Definitions\ArrayDefinition;
use Yiisoft\Definitions\Exception\InvalidConfigException;
use Yiisoft\Definitions\Helpers\DefinitionValidator;
use Yiisoft\Injector\Injector;
use Yiisoft\Queue\Message\MessageInterface;
use Yiisoft\Queue\Middleware\CallableFactory;
use Yiisoft\Queue\Middleware\InvalidCallableConfigurationException;
use Yiisoft\Queue\Middleware\InvalidMiddlewareDefinitionException;
use function is_string;
use function is_array;
/**
* Creates a middleware based on the definition provided.
*/
final class MiddlewareFactoryPush implements MiddlewareFactoryPushInterface
{
/**
* @param ContainerInterface $container Container to use for resolving definitions.
*/
public function __construct(
private readonly ContainerInterface $container,
private readonly CallableFactory $callableFactory,
) {}
/**
* @param array|callable|MiddlewarePushInterface|string $middlewareDefinition Middleware definition in one of
* the following formats:
*
* - A middleware object.
* - A name of a middleware class. The middleware instance will be obtained from container and executed.
* - A callable with `function(MessageInterface $message, MessageHandlerPushInterface $handler):
* MessageInterface` signature.
* - A controller handler action in format `[TestController::class, 'index']`. `TestController` instance will
* be created and `index()` method will be executed.
* - A function returning a middleware. The middleware returned will be executed.
*
* For handler action and callable
* typed parameters are automatically injected using dependency injection container.
* Current message and handler could be obtained by type-hinting for {@see MessageInterface}
* and {@see MessageHandlerPushInterface}.
*
* @throws InvalidMiddlewareDefinitionException
*
* @return MiddlewarePushInterface
*/
public function createPushMiddleware(
MiddlewarePushInterface|callable|array|string $middlewareDefinition,
): MiddlewarePushInterface {
if ($middlewareDefinition instanceof MiddlewarePushInterface) {
return $middlewareDefinition;
}
if (is_string($middlewareDefinition)) {
return $this->getFromContainer($middlewareDefinition);
}
return $this->tryGetFromCallable($middlewareDefinition)
?? $this->tryGetFromArrayDefinition($middlewareDefinition)
?? throw new InvalidMiddlewareDefinitionException($middlewareDefinition);
}
private function getFromContainer(string $middlewareDefinition): MiddlewarePushInterface
{
if (class_exists($middlewareDefinition)) {
if (is_subclass_of($middlewareDefinition, MiddlewarePushInterface::class)) {
/** @var MiddlewarePushInterface */
return $this->container->get($middlewareDefinition);
}
} elseif ($this->container->has($middlewareDefinition)) {
$middleware = $this->container->get($middlewareDefinition);
if ($middleware instanceof MiddlewarePushInterface) {
return $middleware;
}
}
throw new InvalidMiddlewareDefinitionException($middlewareDefinition);
}
private function wrapCallable(callable $callback): MiddlewarePushInterface
{
return new class ($callback, $this->container) implements MiddlewarePushInterface {
private $callback;
public function __construct(
callable $callback,
private readonly ContainerInterface $container,
) {
$this->callback = $callback;
}
public function processPush(MessageInterface $message, MessageHandlerPushInterface $handler): MessageInterface
{
$response = (new Injector($this->container))->invoke($this->callback, [$message, $handler]);
if ($response instanceof MessageInterface) {
return $response;
}
if ($response instanceof MiddlewarePushInterface) {
return $response->processPush($message, $handler);
}
throw new InvalidMiddlewareDefinitionException($this->callback);
}
};
}
private function tryGetFromCallable(
callable|MiddlewarePushInterface|array|string $definition,
): ?MiddlewarePushInterface {
if ($definition instanceof Closure) {
return $this->wrapCallable($definition);
}
if (
is_array($definition)
&& array_keys($definition) === [0, 1]
) {
try {
return $this->wrapCallable($this->callableFactory->create($definition));
} catch (InvalidCallableConfigurationException $exception) {
throw new InvalidMiddlewareDefinitionException($definition, previous: $exception);
}
} else {
return null;
}
}
private function tryGetFromArrayDefinition(
callable|MiddlewarePushInterface|array|string $definition,
): ?MiddlewarePushInterface {
if (!is_array($definition)) {
return null;
}
try {
DefinitionValidator::validateArrayDefinition($definition);
$middleware = ArrayDefinition::fromConfig($definition)->resolve($this->container);
if ($middleware instanceof MiddlewarePushInterface) {
return $middleware;
}
throw new InvalidMiddlewareDefinitionException($definition);
} catch (InvalidConfigException) {
}
throw new InvalidMiddlewareDefinitionException($definition);
}
}