Skip to content

Commit fbe188d

Browse files
Added Container resolution from delegate
1 parent 8d09eea commit fbe188d

File tree

3 files changed

+97
-20
lines changed

3 files changed

+97
-20
lines changed

composer.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,8 @@
33
"require": {
44
"php": ">=7.1",
55
"psr/http-message": "^1.0",
6-
"http-interop/http-middleware": "^0.4.1"
6+
"http-interop/http-middleware": "^0.4.1",
7+
"psr/container": "^1.0"
78
},
89
"require-dev": {
910
"phpunit/phpunit": "^6.2",

src/Delegate.php

Lines changed: 27 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -7,53 +7,69 @@
77
use Interop\Http\ServerMiddleware\DelegateInterface;
88
use Interop\Http\ServerMiddleware\MiddlewareInterface;
99
use Moon\HttpMiddleware\Exception\InvalidArgumentException;
10+
use Psr\Container\ContainerInterface;
1011
use Psr\Http\Message\ResponseInterface;
1112
use Psr\Http\Message\ServerRequestInterface;
1213

1314
class Delegate implements DelegateInterface
1415
{
1516
/**
16-
* @var MiddlewareInterface[] $middlewares
17+
* @var string[]|MiddlewareInterface[]|mixed $middlewares
1718
*/
1819
protected $middlewares;
1920
/**
2021
* @var callable
2122
*/
2223
private $default;
24+
/**
25+
* @var ContainerInterface
26+
*/
27+
private $container;
2328

2429
/**
2530
* Delegate constructor.
2631
*
2732
* @param array $middlewares
2833
* @param callable $default
29-
*
30-
* @throws InvalidArgumentException
34+
* @param ContainerInterface|null $container
3135
*/
32-
public function __construct(array $middlewares, callable $default)
36+
public function __construct(array $middlewares, callable $default, ContainerInterface $container = null)
3337
{
34-
foreach ($middlewares as $middleware) {
35-
if (!$middleware instanceof MiddlewareInterface) {
36-
throw new InvalidArgumentException('All the middlewares must implement ' . MiddlewareInterface::class);
37-
}
38-
}
39-
4038
$this->middlewares = $middlewares;
4139
$this->default = $default;
40+
$this->container = $container;
4241
}
4342

4443
/**
4544
* {@inheritdoc}
45+
* @throws \Moon\HttpMiddleware\Exception\InvalidArgumentException
4646
*/
4747
public function process(ServerRequestInterface $request): ResponseInterface
4848
{
49-
/** @var MiddlewareInterface $middleware */
5049
$middleware = array_shift($this->middlewares);
5150

5251
// It there's no middleware use the default callable
5352
if ($middleware === null) {
5453
return call_user_func($this->default, $request);
5554
}
5655

56+
if ($middleware instanceof MiddlewareInterface) {
57+
58+
return $middleware->process($request, clone $this);
59+
}
60+
61+
if (!$this->container instanceof ContainerInterface || !$this->container->has($middleware)) {
62+
throw new InvalidArgumentException(
63+
sprintf('The middleware is not a valid %s and is not passed in the Container', MiddlewareInterface::class));
64+
}
65+
66+
$middleware = $this->container->get($middleware);
67+
if (!$middleware instanceof MiddlewareInterface) {
68+
throw new InvalidArgumentException(
69+
sprintf('The middleware is not a %s implementation', MiddlewareInterface::class)
70+
);
71+
}
72+
5773
return $middleware->process($request, clone $this);
5874
}
5975
}

tests/Unit/DelegateTest.php

Lines changed: 68 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,26 +4,21 @@
44

55
namespace Moon\HttpMiddleware\Unit;
66

7+
use Interop\Http\ServerMiddleware\DelegateInterface;
78
use Interop\Http\ServerMiddleware\MiddlewareInterface;
89
use Moon\HttpMiddleware\Delegate;
910
use Moon\HttpMiddleware\Exception\InvalidArgumentException;
1011
use Moon\HttpMiddleware\Unit\Fixture\PlusOneMiddleware;
1112
use Moon\HttpMiddleware\Unit\Fixture\PlusTwoMiddleware;
1213
use Moon\HttpMiddleware\Unit\Fixture\StoppingMiddleware;
1314
use PHPUnit\Framework\TestCase;
15+
use Prophecy\Argument;
16+
use Psr\Container\ContainerInterface;
1417
use Psr\Http\Message\ResponseInterface;
1518
use Psr\Http\Message\ServerRequestInterface;
1619

1720
class DelegateTest extends TestCase
1821
{
19-
public function testInvlidArrayThrowInvalidArgumentException()
20-
{
21-
$this->expectException(InvalidArgumentException::class);
22-
$this->expectExceptionMessage('All the middlewares must implement ' . MiddlewareInterface::class);
23-
new Delegate(['invalid object'], function () {
24-
});
25-
}
26-
2722
public function testDefaultCallbackIsCalledOnEmptyMiddlewareStack()
2823
{
2924
$requestMock = $this->prophesize(ServerRequestInterface::class)->reveal();
@@ -67,4 +62,69 @@ public function testMiddlewareStackStop()
6762

6863
$this->assertSame($responseMock, $delegate->process($requestMock));
6964
}
65+
66+
public function testInvalidLazyLoadingMiddlewareFromContainer()
67+
{
68+
$this->expectException(InvalidArgumentException::class);
69+
70+
$requestMock = $this->prophesize(ServerRequestInterface::class)->reveal();
71+
$containerProphecy = $this->prophesize(ContainerInterface::class);
72+
$containerProphecy->has('InvalidMiddleware')->shouldBeCalled(1)->willReturn(true);
73+
$containerProphecy->get('InvalidMiddleware')->shouldBeCalled(1)->willReturn(new \SplStack());
74+
$containerMock = $containerProphecy->reveal();
75+
76+
$delegate = new Delegate(['InvalidMiddleware'], function () {
77+
}, $containerMock);
78+
79+
$delegate->process($requestMock);
80+
}
81+
82+
public function testLazyLoadingMiddlewareFromContainer()
83+
{
84+
$requestMock = $this->prophesize(ServerRequestInterface::class)->reveal();
85+
$responseMock = $this->prophesize(ResponseInterface::class)->reveal();
86+
$middlewareProphecy = $this->prophesize(MiddlewareInterface::class);
87+
$middlewareProphecy->process(
88+
Argument::type(ServerRequestInterface::class), Argument::type(DelegateInterface::class)
89+
)->shouldBeCalled(1)->willReturn($responseMock);
90+
$middlewareMock = $middlewareProphecy->reveal();
91+
$containerProphecy = $this->prophesize(ContainerInterface::class);
92+
$containerProphecy->has('validMiddleware')->shouldBeCalled(1)->willReturn(true);
93+
$containerProphecy->get('validMiddleware')->shouldBeCalled(1)->willReturn($middlewareMock);
94+
$containerMock = $containerProphecy->reveal();
95+
96+
$delegate = new Delegate(['validMiddleware'], function () {
97+
}, $containerMock);
98+
99+
$delegate->process($requestMock);
100+
}
101+
102+
public function testInvalidContainerEntry()
103+
{
104+
$this->expectException(InvalidArgumentException::class);
105+
106+
$requestMock = $this->prophesize(ServerRequestInterface::class)->reveal();
107+
$containerProphecy = $this->prophesize(ContainerInterface::class);
108+
$containerProphecy->has('InvalidMiddleware')->shouldBeCalled(1)->willReturn(false);
109+
$containerProphecy->get('InvalidMiddleware')->shouldNotBeCalled(1);
110+
$containerMock = $containerProphecy->reveal();
111+
112+
$delegate = new Delegate(['InvalidMiddleware'], function () {
113+
}, $containerMock);
114+
115+
$delegate->process($requestMock);
116+
}
117+
118+
119+
public function testInvalidMiddlewareAndContainerNotPassed()
120+
{
121+
$this->expectException(InvalidArgumentException::class);
122+
123+
$requestMock = $this->prophesize(ServerRequestInterface::class)->reveal();
124+
125+
$delegate = new Delegate(['InvalidMiddleware'], function () {
126+
});
127+
128+
$delegate->process($requestMock);
129+
}
70130
}

0 commit comments

Comments
 (0)