Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

4.x - MiddlewareDispatcherInterface #2817

Merged
merged 9 commits into from Aug 20, 2019
39 changes: 28 additions & 11 deletions Slim/App.php
Expand Up @@ -17,6 +17,7 @@
use Psr\Http\Server\RequestHandlerInterface;
use Slim\Factory\ServerRequestCreatorFactory;
use Slim\Interfaces\CallableResolverInterface;
use Slim\Interfaces\MiddlewareDispatcherInterface;
use Slim\Interfaces\RouteCollectorInterface;
use Slim\Interfaces\RouteResolverInterface;
use Slim\Middleware\BodyParsingMiddleware;
Expand All @@ -36,28 +37,30 @@ class App extends RouteCollectorProxy implements RequestHandlerInterface
public const VERSION = '4.1.0';

/**
* @var MiddlewareDispatcher
* @var RouteResolverInterface
*/
protected $middlewareDispatcher;
protected $routeResolver;

/**
* @var RouteResolverInterface
* @var MiddlewareDispatcherInterface
*/
protected $routeResolver;
protected $middlewareDispatcher;

/**
* @param ResponseFactoryInterface $responseFactory
* @param ContainerInterface|null $container
* @param CallableResolverInterface|null $callableResolver
* @param RouteCollectorInterface|null $routeCollector
* @param RouteResolverInterface|null $routeResolver
* @param ResponseFactoryInterface $responseFactory
* @param ContainerInterface|null $container
* @param CallableResolverInterface|null $callableResolver
* @param RouteCollectorInterface|null $routeCollector
* @param RouteResolverInterface|null $routeResolver
* @param MiddlewareDispatcherInterface|null $middlewareDispatcher
*/
public function __construct(
ResponseFactoryInterface $responseFactory,
?ContainerInterface $container = null,
?CallableResolverInterface $callableResolver = null,
?RouteCollectorInterface $routeCollector = null,
?RouteResolverInterface $routeResolver = null
?RouteResolverInterface $routeResolver = null,
?MiddlewareDispatcherInterface $middlewareDispatcher = null
) {
parent::__construct(
$responseFactory,
Expand All @@ -69,7 +72,13 @@ public function __construct(
$this->routeResolver = $routeResolver ?? new RouteResolver($this->routeCollector);
$routeRunner = new RouteRunner($this->routeResolver, $this->routeCollector->getRouteParser());

$this->middlewareDispatcher = new MiddlewareDispatcher($routeRunner, $this->callableResolver, $container);
if (!$middlewareDispatcher) {
$middlewareDispatcher = new MiddlewareDispatcher($routeRunner, $this->callableResolver, $container);
} else {
$middlewareDispatcher->seedMiddlewareStack($routeRunner);
}

$this->middlewareDispatcher = $middlewareDispatcher;
}

/**
Expand All @@ -80,6 +89,14 @@ public function getRouteResolver(): RouteResolverInterface
return $this->routeResolver;
}

/**
* @return MiddlewareDispatcherInterface
*/
public function getMiddlewareDispatcher(): MiddlewareDispatcherInterface
{
return $this->middlewareDispatcher;
}

/**
* @param MiddlewareInterface|string|callable $middleware
* @return self
Expand Down
44 changes: 36 additions & 8 deletions Slim/Factory/AppFactory.php
Expand Up @@ -18,6 +18,7 @@
use Slim\Factory\Psr17\Psr17FactoryProvider;
use Slim\Factory\Psr17\SlimHttpPsr17Factory;
use Slim\Interfaces\CallableResolverInterface;
use Slim\Interfaces\MiddlewareDispatcherInterface;
use Slim\Interfaces\Psr17FactoryProviderInterface;
use Slim\Interfaces\RouteCollectorInterface;
use Slim\Interfaces\RouteResolverInterface;
Expand Down Expand Up @@ -59,33 +60,41 @@ class AppFactory
*/
protected static $routeResolver;

/**
* @var MiddlewareDispatcherInterface|null
*/
protected static $middlewareDispatcher;

/**
* @var bool
*/
protected static $slimHttpDecoratorsAutomaticDetectionEnabled = true;

/**
* @param ResponseFactoryInterface|null $responseFactory
* @param ContainerInterface|null $container
* @param CallableResolverInterface|null $callableResolver
* @param RouteCollectorInterface|null $routeCollector
* @param RouteResolverInterface|null $routeResolver
* @param ResponseFactoryInterface|null $responseFactory
* @param ContainerInterface|null $container
* @param CallableResolverInterface|null $callableResolver
* @param RouteCollectorInterface|null $routeCollector
* @param RouteResolverInterface|null $routeResolver
* @param MiddlewareDispatcherInterface|null $middlewareDispatcher
* @return App
*/
public static function create(
?ResponseFactoryInterface $responseFactory = null,
?ContainerInterface $container = null,
?CallableResolverInterface $callableResolver = null,
?RouteCollectorInterface $routeCollector = null,
?RouteResolverInterface $routeResolver = null
?RouteResolverInterface $routeResolver = null,
?MiddlewareDispatcherInterface $middlewareDispatcher = null
): App {
static::$responseFactory = $responseFactory ?? static::$responseFactory;
return new App(
self::determineResponseFactory(),
$container ?? static::$container,
$callableResolver ?? static::$callableResolver,
$routeCollector ?? static::$routeCollector,
$routeResolver ?? static::$routeResolver
$routeResolver ?? static::$routeResolver,
$middlewareDispatcher ?? static::$middlewareDispatcher
);
}

Expand All @@ -111,7 +120,18 @@ public static function createFromContainer(ContainerInterface $container): App
? $container->get(RouteResolverInterface::class)
: null;

return new App($responseFactory, $container, $callableResolver, $routeCollector, $routeResolver);
$middlewareDispatcher = $container->has(MiddlewareDispatcherInterface::class)
? $container->get(MiddlewareDispatcherInterface::class)
: null;

return new App(
$responseFactory,
$container,
$callableResolver,
$routeCollector,
$routeResolver,
$middlewareDispatcher
);
}

/**
Expand Down Expand Up @@ -224,6 +244,14 @@ public static function setRouteResolver(RouteResolverInterface $routeResolver):
static::$routeResolver = $routeResolver;
}

/**
* @param MiddlewareDispatcherInterface $middlewareDispatcher
*/
public static function setMiddlewareDispatcher(MiddlewareDispatcherInterface $middlewareDispatcher): void
{
static::$middlewareDispatcher = $middlewareDispatcher;
}

/**
* @param bool $enabled
*/
Expand Down
48 changes: 48 additions & 0 deletions Slim/Interfaces/MiddlewareDispatcherInterface.php
@@ -0,0 +1,48 @@
<?php
/**
* Slim Framework (https://slimframework.com)
*
* @license https://github.com/slimphp/Slim/blob/4.x/LICENSE.md (MIT License)
*/

declare(strict_types=1);

namespace Slim\Interfaces;

use Psr\Http\Server\MiddlewareInterface;
use Psr\Http\Server\RequestHandlerInterface;

interface MiddlewareDispatcherInterface extends RequestHandlerInterface
{
/**
* Add a new middleware to the stack
*
* Middleware are organized as a stack. That means middleware
* that have been added before will be executed after the newly
* added one (last in, first out).
*
* @param MiddlewareInterface|string|callable $middleware
* @return self
*/
public function add($middleware): self;

/**
* Add a new middleware to the stack
*
* Middleware are organized as a stack. That means middleware
* that have been added before will be executed after the newly
* added one (last in, first out).
*
* @param MiddlewareInterface $middleware
* @return self
*/
public function addMiddleware(MiddlewareInterface $middleware): self;

/**
* Seed the middleware stack with the inner request handler
*
* @param RequestHandlerInterface $kernel
* @return void
*/
public function seedMiddlewareStack(RequestHandlerInterface $kernel): void;
}
28 changes: 13 additions & 15 deletions Slim/MiddlewareDispatcher.php
Expand Up @@ -18,8 +18,9 @@
use RuntimeException;
use Slim\Interfaces\AdvancedCallableResolverInterface;
use Slim\Interfaces\CallableResolverInterface;
use Slim\Interfaces\MiddlewareDispatcherInterface;

class MiddlewareDispatcher implements RequestHandlerInterface
class MiddlewareDispatcher implements MiddlewareDispatcherInterface
{
/**
* Tip of the middleware call stack
Expand All @@ -29,7 +30,7 @@ class MiddlewareDispatcher implements RequestHandlerInterface
protected $tip;

/**
* @var CallableResolverInterface
* @var CallableResolverInterface|null
l0gicgate marked this conversation as resolved.
Show resolved Hide resolved
*/
protected $callableResolver;

Expand All @@ -39,13 +40,13 @@ class MiddlewareDispatcher implements RequestHandlerInterface
protected $container;

/**
* @param RequestHandlerInterface $kernel
* @param CallableResolverInterface $callableResolver
* @param ContainerInterface|null $container
* @param RequestHandlerInterface $kernel
* @param CallableResolverInterface|null $callableResolver
* @param ContainerInterface|null $container
*/
public function __construct(
RequestHandlerInterface $kernel,
CallableResolverInterface $callableResolver,
?CallableResolverInterface $callableResolver = null,
?ContainerInterface $container = null
) {
$this->seedMiddlewareStack($kernel);
Expand All @@ -54,12 +55,9 @@ public function __construct(
}

/**
* Seed the middleware stack with the inner request handler
*
* @param RequestHandlerInterface $kernel
* @return void
* {@inheritdoc}
*/
protected function seedMiddlewareStack(RequestHandlerInterface $kernel): void
public function seedMiddlewareStack(RequestHandlerInterface $kernel): void
l0gicgate marked this conversation as resolved.
Show resolved Hide resolved
{
$this->tip = $kernel;
}
Expand All @@ -83,9 +81,9 @@ public function handle(ServerRequestInterface $request): ResponseInterface
* added one (last in, first out).
*
* @param MiddlewareInterface|string|callable $middleware
* @return self
* @return MiddlewareDispatcherInterface
*/
public function add($middleware): self
public function add($middleware): MiddlewareDispatcherInterface
{
if ($middleware instanceof MiddlewareInterface) {
return $this->addMiddleware($middleware);
Expand Down Expand Up @@ -113,9 +111,9 @@ public function add($middleware): self
* added one (last in, first out).
*
* @param MiddlewareInterface $middleware
* @return self
* @return MiddlewareDispatcherInterface
*/
public function addMiddleware(MiddlewareInterface $middleware): self
public function addMiddleware(MiddlewareInterface $middleware): MiddlewareDispatcherInterface
{
$next = $this->tip;
$this->tip = new class($middleware, $next) implements RequestHandlerInterface
Expand Down
22 changes: 22 additions & 0 deletions tests/AppTest.php
Expand Up @@ -25,6 +25,7 @@
use Slim\Exception\HttpNotFoundException;
use Slim\Handlers\Strategies\RequestResponseArgs;
use Slim\Interfaces\CallableResolverInterface;
use Slim\Interfaces\MiddlewareDispatcherInterface;
use Slim\Interfaces\RouteCollectorInterface;
use Slim\Interfaces\RouteCollectorProxyInterface;
use Slim\Interfaces\RouteParserInterface;
Expand Down Expand Up @@ -118,6 +119,27 @@ public function testCreatesRouteCollectorWhenNullWithInjectedContainer()
$this->assertEquals($routeCollector, $app->getRouteCollector());
}

public function testGetMiddlewareDispatcherGetsSeededAndReturnsInjectedInstance()
{
$responseFactoryProphecy = $this->prophesize(ResponseFactoryInterface::class);

$middlewareDispatcherProphecy = $this->prophesize(MiddlewareDispatcherInterface::class);
$middlewareDispatcherProphecy
->seedMiddlewareStack(Argument::any())
->shouldBeCalledOnce();

$app = new App(
$responseFactoryProphecy->reveal(),
null,
null,
null,
null,
$middlewareDispatcherProphecy->reveal()
);

$this->assertSame($middlewareDispatcherProphecy->reveal(), $app->getMiddlewareDispatcher());
l0gicgate marked this conversation as resolved.
Show resolved Hide resolved
}

public function lowerCaseRequestMethodsProvider()
{
return [
Expand Down