Skip to content

Commit 10decab

Browse files
authored
Add wrapper factory (#55)
1 parent 5c8ce97 commit 10decab

7 files changed

+141
-84
lines changed

CHANGELOG.md

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
# Yii Middleware Dispatcher Change Log
22

3-
## 2.1.1 under development
3+
## 3.0.0 under development
44

5-
- no changes in this release.
5+
- New #55: Add wrapper factory (@rustamwin)
66

77
## 2.1.0 August 05, 2022
88

config/web.php

+3
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,10 @@
44

55
use Yiisoft\Middleware\Dispatcher\MiddlewareFactory;
66
use Yiisoft\Middleware\Dispatcher\MiddlewareFactoryInterface;
7+
use Yiisoft\Middleware\Dispatcher\WrapperFactory;
8+
use Yiisoft\Middleware\Dispatcher\WrapperFactoryInterface;
79

810
return [
911
MiddlewareFactoryInterface::class => MiddlewareFactory::class,
12+
WrapperFactoryInterface::class => WrapperFactory::class,
1013
];

src/MiddlewareFactory.php

+5-75
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@
1313
use Yiisoft\Definitions\ArrayDefinition;
1414
use Yiisoft\Definitions\Exception\InvalidConfigException;
1515
use Yiisoft\Definitions\Helpers\DefinitionValidator;
16-
use Yiisoft\Injector\Injector;
1716

1817
use function in_array;
1918
use function is_array;
@@ -27,13 +26,15 @@
2726
final class MiddlewareFactory implements MiddlewareFactoryInterface
2827
{
2928
private ContainerInterface $container;
29+
private WrapperFactoryInterface $wrapperFactory;
3030

3131
/**
3232
* @param ContainerInterface $container Container to use for resolving definitions.
3333
*/
34-
public function __construct(ContainerInterface $container)
34+
public function __construct(ContainerInterface $container, WrapperFactoryInterface $wrapperFactory)
3535
{
3636
$this->container = $container;
37+
$this->wrapperFactory = $wrapperFactory;
3738
}
3839

3940
/**
@@ -62,7 +63,8 @@ public function create($middlewareDefinition): MiddlewareInterface
6263
}
6364

6465
if ($this->isCallableDefinition($middlewareDefinition)) {
65-
return $this->wrapCallableDefinition($middlewareDefinition);
66+
/** @var array{0:class-string, 1:string}|Closure $middlewareDefinition */
67+
return $this->wrapperFactory->create($middlewareDefinition);
6668
}
6769

6870
if ($this->isArrayDefinition($middlewareDefinition)) {
@@ -77,78 +79,6 @@ public function create($middlewareDefinition): MiddlewareInterface
7779
throw new InvalidMiddlewareDefinitionException($middlewareDefinition);
7880
}
7981

80-
/**
81-
* @param array|Closure $callback
82-
*/
83-
private function wrapCallableDefinition($callback): MiddlewareInterface
84-
{
85-
if (is_array($callback)) {
86-
return new class ($this->container, $callback) implements MiddlewareInterface {
87-
private string $class;
88-
private string $method;
89-
private ContainerInterface $container;
90-
private array $callback;
91-
92-
public function __construct(ContainerInterface $container, array $callback)
93-
{
94-
[$this->class, $this->method] = $callback;
95-
$this->container = $container;
96-
$this->callback = $callback;
97-
}
98-
99-
public function process(
100-
ServerRequestInterface $request,
101-
RequestHandlerInterface $handler
102-
): ResponseInterface {
103-
/** @var mixed $controller */
104-
$controller = $this->container->get($this->class);
105-
106-
/** @var mixed $response */
107-
$response = (new Injector($this->container))
108-
->invoke([$controller, $this->method], [$request, $handler]);
109-
if ($response instanceof ResponseInterface) {
110-
return $response;
111-
}
112-
113-
throw new InvalidMiddlewareDefinitionException($this->callback);
114-
}
115-
116-
public function __debugInfo()
117-
{
118-
return [
119-
'callback' => $this->callback,
120-
];
121-
}
122-
};
123-
}
124-
125-
return new class ($callback, $this->container) implements MiddlewareInterface {
126-
private ContainerInterface $container;
127-
private $callback;
128-
129-
public function __construct(callable $callback, ContainerInterface $container)
130-
{
131-
$this->callback = $callback;
132-
$this->container = $container;
133-
}
134-
135-
public function process(
136-
ServerRequestInterface $request,
137-
RequestHandlerInterface $handler
138-
): ResponseInterface {
139-
/** @var mixed $response */
140-
$response = (new Injector($this->container))->invoke($this->callback, [$request, $handler]);
141-
if ($response instanceof ResponseInterface) {
142-
return $response;
143-
}
144-
if ($response instanceof MiddlewareInterface) {
145-
return $response->process($request, $handler);
146-
}
147-
throw new InvalidMiddlewareDefinitionException($this->callback);
148-
}
149-
};
150-
}
151-
15282
/**
15383
* @param mixed $definition
15484
*

src/WrapperFactory.php

+103
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Yiisoft\Middleware\Dispatcher;
6+
7+
use Psr\Container\ContainerInterface;
8+
use Psr\Http\Message\ResponseInterface;
9+
use Psr\Http\Message\ServerRequestInterface;
10+
use Psr\Http\Server\MiddlewareInterface;
11+
use Psr\Http\Server\RequestHandlerInterface;
12+
use Yiisoft\Injector\Injector;
13+
14+
final class WrapperFactory implements WrapperFactoryInterface
15+
{
16+
private ContainerInterface $container;
17+
18+
public function __construct(ContainerInterface $container)
19+
{
20+
$this->container = $container;
21+
}
22+
23+
/**
24+
* {@inheritDoc}
25+
*/
26+
public function create($callable): MiddlewareInterface
27+
{
28+
if (is_array($callable)) {
29+
return $this->createActionWrapper($callable[0], $callable[1]);
30+
}
31+
32+
return $this->createCallableWrapper($callable);
33+
}
34+
35+
public function createCallableWrapper(callable $callback): MiddlewareInterface
36+
{
37+
return new class ($callback, $this->container) implements MiddlewareInterface {
38+
private ContainerInterface $container;
39+
private $callback;
40+
41+
public function __construct(callable $callback, ContainerInterface $container)
42+
{
43+
$this->callback = $callback;
44+
$this->container = $container;
45+
}
46+
47+
public function process(
48+
ServerRequestInterface $request,
49+
RequestHandlerInterface $handler
50+
): ResponseInterface {
51+
/** @var MiddlewareInterface|mixed|ResponseInterface $response */
52+
$response = (new Injector($this->container))->invoke($this->callback, [$request, $handler]);
53+
if ($response instanceof ResponseInterface) {
54+
return $response;
55+
}
56+
if ($response instanceof MiddlewareInterface) {
57+
return $response->process($request, $handler);
58+
}
59+
throw new InvalidMiddlewareDefinitionException($this->callback);
60+
}
61+
};
62+
}
63+
64+
private function createActionWrapper(string $class, string $method): MiddlewareInterface
65+
{
66+
return new class ($this->container, $class, $method) implements MiddlewareInterface {
67+
private string $class;
68+
private string $method;
69+
private ContainerInterface $container;
70+
71+
public function __construct(ContainerInterface $container, string $class, string $method)
72+
{
73+
$this->container = $container;
74+
$this->class = $class;
75+
$this->method = $method;
76+
}
77+
78+
public function process(
79+
ServerRequestInterface $request,
80+
RequestHandlerInterface $handler
81+
): ResponseInterface {
82+
/** @var mixed $controller */
83+
$controller = $this->container->get($this->class);
84+
85+
/** @var mixed|ResponseInterface $response */
86+
$response = (new Injector($this->container))
87+
->invoke([$controller, $this->method], [$request, $handler]);
88+
if ($response instanceof ResponseInterface) {
89+
return $response;
90+
}
91+
92+
throw new InvalidMiddlewareDefinitionException([$this->class, $this->method]);
93+
}
94+
95+
public function __debugInfo()
96+
{
97+
return [
98+
'callback' => [$this->class, $this->method],
99+
];
100+
}
101+
};
102+
}
103+
}

src/WrapperFactoryInterface.php

+22
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Yiisoft\Middleware\Dispatcher;
6+
7+
use Psr\Http\Server\MiddlewareInterface;
8+
9+
/**
10+
* Creates a PSR-15 middleware that wraps the provided callable.
11+
* You may implement this interface if you want to introduce custom definitions or pass additional data to
12+
* the middleware created.
13+
*/
14+
interface WrapperFactoryInterface
15+
{
16+
/**
17+
* Create a PSR-15 middleware that wraps the provided callable.
18+
*
19+
* @param array{0:class-string, 1:string}|\Closure $callable
20+
*/
21+
public function create($callable): MiddlewareInterface;
22+
}

tests/MiddlewareDispatcherTest.php

+3-5
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
use Yiisoft\Middleware\Dispatcher\Tests\Support\FailMiddleware;
2020
use Yiisoft\Middleware\Dispatcher\Tests\Support\TestController;
2121
use Yiisoft\Middleware\Dispatcher\Tests\Support\TestMiddleware;
22+
use Yiisoft\Middleware\Dispatcher\WrapperFactory;
2223
use Yiisoft\Test\Support\Container\SimpleContainer;
2324
use Yiisoft\Test\Support\EventDispatcher\SimpleEventDispatcher;
2425

@@ -209,14 +210,11 @@ public function handle(ServerRequestInterface $request): ResponseInterface
209210
private function createDispatcher(ContainerInterface $container = null, ?EventDispatcherInterface $eventDispatcher = null): MiddlewareDispatcher
210211
{
211212
if ($container === null) {
212-
return new MiddlewareDispatcher(
213-
new MiddlewareFactory($this->createContainer()),
214-
$eventDispatcher
215-
);
213+
$container = $this->createContainer();
216214
}
217215

218216
return new MiddlewareDispatcher(
219-
new MiddlewareFactory($container),
217+
new MiddlewareFactory($container, new WrapperFactory($container)),
220218
$eventDispatcher
221219
);
222220
}

tests/MiddlewareFactoryTest.php

+3-2
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
use Yiisoft\Middleware\Dispatcher\Tests\Support\InvalidController;
2222
use Yiisoft\Middleware\Dispatcher\Tests\Support\TestController;
2323
use Yiisoft\Middleware\Dispatcher\Tests\Support\TestMiddleware;
24+
use Yiisoft\Middleware\Dispatcher\WrapperFactory;
2425
use Yiisoft\Test\Support\Container\SimpleContainer;
2526

2627
final class MiddlewareFactoryTest extends TestCase
@@ -256,10 +257,10 @@ public function testInvalidMiddlewareWithWrongArrayWithIntItems(): void
256257
private function getMiddlewareFactory(ContainerInterface $container = null): MiddlewareFactoryInterface
257258
{
258259
if ($container !== null) {
259-
return new MiddlewareFactory($container);
260+
return new MiddlewareFactory($container, new WrapperFactory($container));
260261
}
261262

262-
return new MiddlewareFactory($this->getContainer());
263+
return new MiddlewareFactory($this->getContainer(), new WrapperFactory($this->getContainer()));
263264
}
264265

265266
private function getContainer(array $instances = []): ContainerInterface

0 commit comments

Comments
 (0)