Skip to content

Commit

Permalink
Added Container resolution from delegate
Browse files Browse the repository at this point in the history
  • Loading branch information
damianopetrungaro committed Jul 12, 2017
1 parent 8d09eea commit fbe188d
Show file tree
Hide file tree
Showing 3 changed files with 97 additions and 20 deletions.
3 changes: 2 additions & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@
"require": {
"php": ">=7.1",
"psr/http-message": "^1.0",
"http-interop/http-middleware": "^0.4.1"
"http-interop/http-middleware": "^0.4.1",
"psr/container": "^1.0"
},
"require-dev": {
"phpunit/phpunit": "^6.2",
Expand Down
38 changes: 27 additions & 11 deletions src/Delegate.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,53 +7,69 @@
use Interop\Http\ServerMiddleware\DelegateInterface;
use Interop\Http\ServerMiddleware\MiddlewareInterface;
use Moon\HttpMiddleware\Exception\InvalidArgumentException;
use Psr\Container\ContainerInterface;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;

class Delegate implements DelegateInterface
{
/**
* @var MiddlewareInterface[] $middlewares
* @var string[]|MiddlewareInterface[]|mixed $middlewares
*/
protected $middlewares;
/**
* @var callable
*/
private $default;
/**
* @var ContainerInterface
*/
private $container;

/**
* Delegate constructor.
*
* @param array $middlewares
* @param callable $default
*
* @throws InvalidArgumentException
* @param ContainerInterface|null $container
*/
public function __construct(array $middlewares, callable $default)
public function __construct(array $middlewares, callable $default, ContainerInterface $container = null)
{
foreach ($middlewares as $middleware) {
if (!$middleware instanceof MiddlewareInterface) {
throw new InvalidArgumentException('All the middlewares must implement ' . MiddlewareInterface::class);
}
}

$this->middlewares = $middlewares;
$this->default = $default;
$this->container = $container;
}

/**
* {@inheritdoc}
* @throws \Moon\HttpMiddleware\Exception\InvalidArgumentException
*/
public function process(ServerRequestInterface $request): ResponseInterface
{
/** @var MiddlewareInterface $middleware */
$middleware = array_shift($this->middlewares);

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

if ($middleware instanceof MiddlewareInterface) {

return $middleware->process($request, clone $this);
}

if (!$this->container instanceof ContainerInterface || !$this->container->has($middleware)) {
throw new InvalidArgumentException(
sprintf('The middleware is not a valid %s and is not passed in the Container', MiddlewareInterface::class));
}

$middleware = $this->container->get($middleware);
if (!$middleware instanceof MiddlewareInterface) {
throw new InvalidArgumentException(
sprintf('The middleware is not a %s implementation', MiddlewareInterface::class)
);
}

return $middleware->process($request, clone $this);
}
}
76 changes: 68 additions & 8 deletions tests/Unit/DelegateTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,26 +4,21 @@

namespace Moon\HttpMiddleware\Unit;

use Interop\Http\ServerMiddleware\DelegateInterface;
use Interop\Http\ServerMiddleware\MiddlewareInterface;
use Moon\HttpMiddleware\Delegate;
use Moon\HttpMiddleware\Exception\InvalidArgumentException;
use Moon\HttpMiddleware\Unit\Fixture\PlusOneMiddleware;
use Moon\HttpMiddleware\Unit\Fixture\PlusTwoMiddleware;
use Moon\HttpMiddleware\Unit\Fixture\StoppingMiddleware;
use PHPUnit\Framework\TestCase;
use Prophecy\Argument;
use Psr\Container\ContainerInterface;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;

class DelegateTest extends TestCase
{
public function testInvlidArrayThrowInvalidArgumentException()
{
$this->expectException(InvalidArgumentException::class);
$this->expectExceptionMessage('All the middlewares must implement ' . MiddlewareInterface::class);
new Delegate(['invalid object'], function () {
});
}

public function testDefaultCallbackIsCalledOnEmptyMiddlewareStack()
{
$requestMock = $this->prophesize(ServerRequestInterface::class)->reveal();
Expand Down Expand Up @@ -67,4 +62,69 @@ public function testMiddlewareStackStop()

$this->assertSame($responseMock, $delegate->process($requestMock));
}

public function testInvalidLazyLoadingMiddlewareFromContainer()
{
$this->expectException(InvalidArgumentException::class);

$requestMock = $this->prophesize(ServerRequestInterface::class)->reveal();
$containerProphecy = $this->prophesize(ContainerInterface::class);
$containerProphecy->has('InvalidMiddleware')->shouldBeCalled(1)->willReturn(true);
$containerProphecy->get('InvalidMiddleware')->shouldBeCalled(1)->willReturn(new \SplStack());
$containerMock = $containerProphecy->reveal();

$delegate = new Delegate(['InvalidMiddleware'], function () {
}, $containerMock);

$delegate->process($requestMock);
}

public function testLazyLoadingMiddlewareFromContainer()
{
$requestMock = $this->prophesize(ServerRequestInterface::class)->reveal();
$responseMock = $this->prophesize(ResponseInterface::class)->reveal();
$middlewareProphecy = $this->prophesize(MiddlewareInterface::class);
$middlewareProphecy->process(
Argument::type(ServerRequestInterface::class), Argument::type(DelegateInterface::class)
)->shouldBeCalled(1)->willReturn($responseMock);
$middlewareMock = $middlewareProphecy->reveal();
$containerProphecy = $this->prophesize(ContainerInterface::class);
$containerProphecy->has('validMiddleware')->shouldBeCalled(1)->willReturn(true);
$containerProphecy->get('validMiddleware')->shouldBeCalled(1)->willReturn($middlewareMock);
$containerMock = $containerProphecy->reveal();

$delegate = new Delegate(['validMiddleware'], function () {
}, $containerMock);

$delegate->process($requestMock);
}

public function testInvalidContainerEntry()
{
$this->expectException(InvalidArgumentException::class);

$requestMock = $this->prophesize(ServerRequestInterface::class)->reveal();
$containerProphecy = $this->prophesize(ContainerInterface::class);
$containerProphecy->has('InvalidMiddleware')->shouldBeCalled(1)->willReturn(false);
$containerProphecy->get('InvalidMiddleware')->shouldNotBeCalled(1);
$containerMock = $containerProphecy->reveal();

$delegate = new Delegate(['InvalidMiddleware'], function () {
}, $containerMock);

$delegate->process($requestMock);
}


public function testInvalidMiddlewareAndContainerNotPassed()
{
$this->expectException(InvalidArgumentException::class);

$requestMock = $this->prophesize(ServerRequestInterface::class)->reveal();

$delegate = new Delegate(['InvalidMiddleware'], function () {
});

$delegate->process($requestMock);
}
}

0 comments on commit fbe188d

Please sign in to comment.